diff --git a/README.md b/README.md index ff52761..413c48a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ QtCipherSqlitePlugin (Support Qt 6.8) ==================== -A Qt plugin for SQLite encryption for use in the **[TaskGuard](https://github.com/mxrcode/TaskGuard)** project *(Qt 6.8.0, sqlite3mc 1.9.0)* +A Qt plugin for SQLite encryption for use in the **[TaskGuard](https://github.com/mxrcode/TaskGuard)** project *(Qt 6.8.0, sqlite3mc 2.5.0)* Based on the SQLite source and wxSQLite3 in wxWidget. diff --git a/sqlitecipher.pro b/sqlitecipher.pro index c9c246c..cbb6a26 100644 --- a/sqlitecipher.pro +++ b/sqlitecipher.pro @@ -32,8 +32,7 @@ OTHER_FILES += $$PWD/src/SqliteCipherDriverPlugin.json SQLITE_OMIT_COMPLETE \ SQLITE_ENABLE_FTS3 \ SQLITE_ENABLE_FTS3_PARENTHESIS \ - SQLITE_ENABLE_RTREE \ - SQLITE_USER_AUTHENTICATION + SQLITE_ENABLE_RTREE !contains(CONFIG, largefile):DEFINES += SQLITE_DISABLE_LFS winrt: DEFINES += SQLITE_OS_WINRT winphone: DEFINES += SQLITE_WIN32_FILEMAPPING_API=1 @@ -47,5 +46,3 @@ PLUGIN_CLASS_NAME = SqliteCipherDriverPlugin PLUGIN_TYPE = sqldrivers DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII - -QMAKE_CFLAGS += -march=native diff --git a/src/sqlcachedresult.cpp b/src/sqlcachedresult.cpp deleted file mode 100644 index 44dda58..0000000 --- a/src/sqlcachedresult.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtSql module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "sqlcachedresult_p.h" - -QT_BEGIN_NAMESPACE - -/* - SqlCachedResult is a convenience class for databases that only allow - forward only fetching. It will cache all the results so we can iterate - backwards over the results again. - All you need to do is to inherit from SqlCachedResult and reimplement - gotoNext(). gotoNext() will have a reference to the internal cache and - will give you an index where you can start filling in your data. Special - case: If the user actually wants a forward-only query, idx will be -1 - to indicate that we are not interested in the actual values. -*/ - -static const uint initial_cache_size = 128; - -class SqlCachedResultPrivate -{ -public: - SqlCachedResultPrivate(); - bool canSeek(int i) const; - inline int cacheCount() const; - void init(int count, bool fo); - void cleanup(); - int nextIndex(); - void revertLast(); - - SqlCachedResult::ValueCache cache; - int rowCacheEnd; - int colCount; - bool forwardOnly; - bool atEnd; -}; - -SqlCachedResultPrivate::SqlCachedResultPrivate(): - rowCacheEnd(0), colCount(0), forwardOnly(false), atEnd(false) -{ -} - -void SqlCachedResultPrivate::cleanup() -{ - cache.clear(); - forwardOnly = false; - atEnd = false; - colCount = 0; - rowCacheEnd = 0; -} - -void SqlCachedResultPrivate::init(int count, bool fo) -{ - Q_ASSERT(count); - cleanup(); - forwardOnly = fo; - colCount = count; - if (fo) { - cache.resize(count); - rowCacheEnd = count; - } else { - cache.resize(initial_cache_size * count); - } -} - -int SqlCachedResultPrivate::nextIndex() -{ - if (forwardOnly) - return 0; - int newIdx = rowCacheEnd; - if (newIdx + colCount > cache.size()) - cache.resize(qMin(cache.size() * 2, cache.size() + 10000)); - rowCacheEnd += colCount; - - return newIdx; -} - -bool SqlCachedResultPrivate::canSeek(int i) const -{ - if (forwardOnly || i < 0) - return false; - return rowCacheEnd >= (i + 1) * colCount; -} - -void SqlCachedResultPrivate::revertLast() -{ - if (forwardOnly) - return; - rowCacheEnd -= colCount; -} - -inline int SqlCachedResultPrivate::cacheCount() const -{ - Q_ASSERT(!forwardOnly); - Q_ASSERT(colCount); - return rowCacheEnd / colCount; -} - -////////////// - -SqlCachedResult::SqlCachedResult(const QSqlDriver * db): QSqlResult (db) -{ - d = new SqlCachedResultPrivate(); -} - -SqlCachedResult::~SqlCachedResult() -{ - delete d; -} - -void SqlCachedResult::init(int colCount) -{ - d->init(colCount, isForwardOnly()); -} - -bool SqlCachedResult::fetch(int i) -{ - if ((!isActive()) || (i < 0)) - return false; - if (at() == i) - return true; - if (d->forwardOnly) { - // speed hack - do not copy values if not needed - if (at() > i || at() == QSql::AfterLastRow) - return false; - while(at() < i - 1) { - if (!gotoNext(d->cache, -1)) - return false; - setAt(at() + 1); - } - if (!gotoNext(d->cache, 0)) - return false; - setAt(at() + 1); - return true; - } - if (d->canSeek(i)) { - setAt(i); - return true; - } - if (d->rowCacheEnd > 0) - setAt(d->cacheCount()); - while (at() < i + 1) { - if (!cacheNext()) { - if (d->canSeek(i)) - break; - return false; - } - } - setAt(i); - - return true; -} - -bool SqlCachedResult::fetchNext() -{ - if (d->canSeek(at() + 1)) { - setAt(at() + 1); - return true; - } - return cacheNext(); -} - -bool SqlCachedResult::fetchPrevious() -{ - return fetch(at() - 1); -} - -bool SqlCachedResult::fetchFirst() -{ - if (d->forwardOnly && at() != QSql::BeforeFirstRow) { - return false; - } - if (d->canSeek(0)) { - setAt(0); - return true; - } - return cacheNext(); -} - -bool SqlCachedResult::fetchLast() -{ - if (d->atEnd) { - if (d->forwardOnly) - return false; - else - return fetch(d->cacheCount() - 1); - } - - int i = at(); - while (fetchNext()) - ++i; /* brute force */ - if (d->forwardOnly && at() == QSql::AfterLastRow) { - setAt(i); - return true; - } else { - return fetch(i); - } -} - -QVariant SqlCachedResult::data(int i) -{ - int idx = d->forwardOnly ? i : at() * d->colCount + i; - if (i >= d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd) - return QVariant(); - - return d->cache.at(idx); -} - -bool SqlCachedResult::isNull(int i) -{ - int idx = d->forwardOnly ? i : at() * d->colCount + i; - if (i >= d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd) - return true; - - return d->cache.at(idx).isNull(); -} - -void SqlCachedResult::cleanup() -{ - setAt(QSql::BeforeFirstRow); - setActive(false); - d->cleanup(); -} - -void SqlCachedResult::clearValues() -{ - setAt(QSql::BeforeFirstRow); - d->rowCacheEnd = 0; - d->atEnd = false; -} - -bool SqlCachedResult::cacheNext() -{ - if (d->atEnd) - return false; - - if(isForwardOnly()) { - d->cache.clear(); - d->cache.resize(d->colCount); - } - - if (!gotoNext(d->cache, d->nextIndex())) { - d->revertLast(); - d->atEnd = true; - return false; - } - setAt(at() + 1); - return true; -} - -int SqlCachedResult::colCount() const -{ - return d->colCount; -} - -SqlCachedResult::ValueCache &SqlCachedResult::cache() -{ - return d->cache; -} - -void SqlCachedResult::virtual_hook(int id, void *data) -{ - QSqlResult::virtual_hook(id, data); -} - -void SqlCachedResult::detachFromResultSet() -{ - cleanup(); -} - -void SqlCachedResult::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy) -{ - QSqlResult::setNumericalPrecisionPolicy(policy); - cleanup(); -} - -QT_END_NAMESPACE \ No newline at end of file diff --git a/src/sqlcachedresult_p.h b/src/sqlcachedresult_p.h deleted file mode 100644 index 2453e6d..0000000 --- a/src/sqlcachedresult_p.h +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtSql module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef SQLCACHEDRESULT_H -#define SQLCACHEDRESULT_H - -#include - -#include "sqlitecipher_global.h" - -#if (QT_VERSION < 0x050000) -QT_BEGIN_HEADER -#endif - -QT_BEGIN_NAMESPACE - -class QVariant; -template class QVector; - -class SqlCachedResultPrivate; - -class SqlCachedResult : public QSqlResult -{ -public: - virtual ~SqlCachedResult(); - - typedef QVector ValueCache; - -protected: - SqlCachedResult(const QSqlDriver * db); - - void init(int colCount); - void cleanup(); - void clearValues(); - - virtual bool gotoNext(ValueCache &values, int index) = 0; - - QVariant data(int i) DECL_OVERRIDE; - bool isNull(int i) DECL_OVERRIDE; - bool fetch(int i) DECL_OVERRIDE; - bool fetchNext() DECL_OVERRIDE; - bool fetchPrevious() DECL_OVERRIDE; - bool fetchFirst() DECL_OVERRIDE; - bool fetchLast() DECL_OVERRIDE; - - int colCount() const; - ValueCache &cache(); - - void virtual_hook(int id, void *data) DECL_OVERRIDE; - void detachFromResultSet() DECL_OVERRIDE; - void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy) DECL_OVERRIDE; -private: - bool cacheNext(); - SqlCachedResultPrivate *d; -}; - -QT_END_NAMESPACE - -#if (QT_VERSION < 0x050000) -QT_END_HEADER -#endif - -#endif // SQLCACHEDRESULT_H \ No newline at end of file diff --git a/src/sqlite3/sqlite3.pri b/src/sqlite3/sqlite3.pri index 7117dbb..42cf5ee 100644 --- a/src/sqlite3/sqlite3.pri +++ b/src/sqlite3/sqlite3.pri @@ -8,14 +8,12 @@ DEFINES += _CRT_SECURE_NO_WARNINGS \ SQLITE_SOUNDEX \ SQLITE_ENABLE_EXPLAIN_COMMENTS \ SQLITE_ENABLE_COLUMN_METADATA \ - SQLITE_HAS_CODEC=1 \ CODEC_TYPE=CODEC_TYPE_CHACHA20 \ SQLITE_SECURE_DELETE \ SQLITE_ENABLE_FTS3 \ SQLITE_ENABLE_FTS3_PARENTHESIS \ SQLITE_ENABLE_FTS4 \ SQLITE_ENABLE_FTS5 \ - SQLITE_ENABLE_JSON1 \ SQLITE_ENABLE_RTREE \ SQLITE_CORE \ SQLITE_ENABLE_EXTFUNC \ @@ -25,8 +23,7 @@ DEFINES += _CRT_SECURE_NO_WARNINGS \ SQLITE_ENABLE_FILEIO \ SQLITE_ENABLE_SERIES \ SQLITE_TEMP_STORE=2 \ - SQLITE_USE_URI \ - SQLITE_USER_AUTHENTICATION + SQLITE_USE_URI win32-msvc* { # Nothing for now. diff --git a/src/sqlite3/sqlite3mc_amalgamation.c b/src/sqlite3/sqlite3mc_amalgamation.c index fcf6d89..c31ad4f 100644 --- a/src/sqlite3/sqlite3mc_amalgamation.c +++ b/src/sqlite3/sqlite3mc_amalgamation.c @@ -3,10 +3,27 @@ ** Purpose: Amalgamation of the SQLite3 Multiple Ciphers encryption extension for SQLite ** Author: Ulrich Telle ** Created: 2020-02-28 -** Copyright: (c) 2006-2024 Ulrich Telle +** Copyright: (c) 2006-2026 Ulrich Telle ** License: MIT */ +/* +** If SQLite functions should be called through a dispatch table, +** thus hiding all SQLite function symbols from the linker, +** define the symbol SQLITE3MC_USE_DISPATCH_TABLE. +*/ + +#ifdef SQLITE3MC_USE_DISPATCH_TABLE +#ifdef SQLITE_API +#undef SQLITE_API +#endif +#ifdef SQLITE_PRIVATE +#undef SQLITE_PRIVATE +#endif +#define SQLITE_API static +#define SQLITE_PRIVATE static +#endif + /* ** Force some options required for WASM builds */ @@ -17,7 +34,6 @@ #ifdef SQLITE_USER_AUTHENTICATION #undef SQLITE_USER_AUTHENTICATION #endif -#define SQLITE_USER_AUTHENTICATION 0 /* Disable AES hardware support */ /* Note: this may be changed in the future depending on available support */ @@ -38,19 +54,6 @@ #endif #endif -/* -** Define function for extra initialization and extra shutdown -** -** The extra initialization function registers an extension function -** which will be automatically executed for each new database connection. -** -** The extra shutdown function will be executed on the invocation of sqlite3_shutdown. -** All created multiple ciphers VFSs will be unregistered and destroyed. -*/ - -#define SQLITE_EXTRA_INIT sqlite3mc_initialize -#define SQLITE_EXTRA_SHUTDOWN sqlite3mc_shutdown - /* ** Declare all internal functions as 'static' unless told otherwise */ @@ -65,21 +68,22 @@ SQLITE_PRIVATE void sqlite3mc_shutdown(void); ** To enable the extension functions define SQLITE_ENABLE_EXTFUNC on compiling this module ** To enable the reading CSV files define SQLITE_ENABLE_CSV on compiling this module ** To enable the SHA3 support define SQLITE_ENABLE_SHA3 on compiling this module -** To enable the CARRAY support define SQLITE_ENABLE_CARRAY on compiling this module ** To enable the FILEIO support define SQLITE_ENABLE_FILEIO on compiling this module ** To enable the SERIES support define SQLITE_ENABLE_SERIES on compiling this module ** To enable the UUID support define SQLITE_ENABLE_UUID on compiling this module +** +** Extensions for which the SQLite amalgamation contains now the sources: +** To enable the CARRAY support define SQLITE_ENABLE_CARRAY on compiling this module +** To enable the PERCENTILE support define SQLITE_ENABLE_PERCENTILE on compiling this module */ /* ** Disable the user authentication feature by default */ #ifdef SQLITE_USER_AUTHENTICATION -#if !SQLITE_USER_AUTHENTICATION /* Option defined and disabled, therefore undefine option */ #undef SQLITE_USER_AUTHENTICATION #endif -#endif #if defined(_WIN32) || defined(WIN32) @@ -136,7 +140,7 @@ SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char*); /*** Begin of #include "sqlite3patched.c" ***/ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.47.0. By combining all the individual C code files into this +** version 3.53.4. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -154,8 +158,11 @@ SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char*); ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** 03a9703e27c44437c39363d0baf82db4ebc9. +** bf7c7f30031888f4e796e429ab3978879485 with changes in files: +** +** */ +#ifndef SQLITE_AMALGAMATION #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 #ifndef SQLITE_PRIVATE @@ -303,7 +310,9 @@ SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char*); #define HAVE_UTIME 1 #else /* This is not VxWorks. */ -#define OS_VXWORKS 0 +#ifndef OS_VXWORKS +# define OS_VXWORKS 0 +#endif #define HAVE_FCHOWN 1 #define HAVE_READLINK 1 #define HAVE_LSTAT 1 @@ -585,7 +594,7 @@ extern "C" { ** ** Since [version 3.6.18] ([dateof:3.6.18]), ** SQLite source code has been stored in the -** Fossil configuration management +** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID @@ -598,9 +607,12 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.47.0" -#define SQLITE_VERSION_NUMBER 3047000 -#define SQLITE_SOURCE_ID "2024-10-21 16:30:22 03a9703e27c44437c39363d0baf82db4ebc94538a0f28411c85dda156f82636e" +#define SQLITE_VERSION "3.53.4" +#define SQLITE_VERSION_NUMBER 3053004 +#define SQLITE_SOURCE_ID "2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc" +#define SQLITE_SCM_BRANCH "branch-3.53" +#define SQLITE_SCM_TAGS "release version-3.53.4" +#define SQLITE_SCM_DATETIME "2026-07-24T19:02:57.525Z" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -620,9 +632,9 @@ extern "C" { ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 ); ** )^ ** -** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION] -** macro. ^The sqlite3_libversion() function returns a pointer to the -** to the sqlite3_version[] string constant. The sqlite3_libversion() +** ^The sqlite3_version[] string constant contains the text of the +** [SQLITE_VERSION] macro. ^The sqlite3_libversion() function returns a +** pointer to the sqlite3_version[] string constant. The sqlite3_libversion() ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to @@ -822,7 +834,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** without having to use a lot of C code. ** ** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, -** semicolon-separate SQL statements passed into its 2nd argument, +** semicolon-separated SQL statements passed into its 2nd argument, ** in the context of the [database connection] passed in as its 1st ** argument. ^If the callback function of the 3rd argument to ** sqlite3_exec() is not NULL, then it is invoked for each result row @@ -855,7 +867,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** result row is NULL then the corresponding string pointer for the ** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the ** sqlite3_exec() callback is an array of pointers to strings where each -** entry represents the name of corresponding result column as obtained +** entry represents the name of a corresponding result column as obtained ** from [sqlite3_column_name()]. ** ** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer @@ -949,6 +961,9 @@ SQLITE_API int sqlite3_exec( #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) #define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) +#define SQLITE_ERROR_RESERVESIZE (SQLITE_ERROR | (4<<8)) +#define SQLITE_ERROR_KEY (SQLITE_ERROR | (5<<8)) +#define SQLITE_ERROR_UNABLE (SQLITE_ERROR | (6<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) @@ -983,6 +998,8 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8)) +#define SQLITE_IOERR_BADKEY (SQLITE_IOERR | (35<<8)) +#define SQLITE_IOERR_CODEC (SQLITE_IOERR | (36<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) @@ -1022,7 +1039,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) -#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ +#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal only */ /* ** CAPI3REF: Flags For File Open Operations @@ -1041,7 +1058,7 @@ SQLITE_API int sqlite3_exec( ** Note in particular that passing the SQLITE_OPEN_EXCLUSIVE flag into ** [sqlite3_open_v2()] does *not* cause the underlying database file ** to be opened using O_EXCL. Passing SQLITE_OPEN_EXCLUSIVE into -** [sqlite3_open_v2()] has historically be a no-op and might become an +** [sqlite3_open_v2()] has historically been a no-op and might become an ** error in future versions of SQLite. */ #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ @@ -1104,6 +1121,13 @@ SQLITE_API int sqlite3_exec( ** filesystem supports doing multiple write operations atomically when those ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. +** +** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read +** from the database file in amounts that are not a multiple of the +** page size and that do not begin at a page boundary. Without this +** property, SQLite is careful to only do full-page reads and write +** on aligned pages, with the one exception that it will do a sub-page +** read of the first page to access the database header. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -1120,6 +1144,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 +#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000 /* ** CAPI3REF: File Locking Levels @@ -1127,7 +1152,7 @@ SQLITE_API int sqlite3_exec( ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods ** of an [sqlite3_io_methods] object. These values are ordered from -** lest restrictive to most restrictive. +** least restrictive to most restrictive. ** ** The argument to xLock() is always SHARED or higher. The argument to ** xUnlock is either SHARED or NONE. @@ -1266,6 +1291,7 @@ struct sqlite3_file { **
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] **
  • [SQLITE_IOCAP_IMMUTABLE] **
  • [SQLITE_IOCAP_BATCH_ATOMIC] +**
  • [SQLITE_IOCAP_SUBPAGE_READ] ** ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -1367,7 +1393,7 @@ struct sqlite3_io_methods { ** connection. See also [SQLITE_FCNTL_FILE_POINTER]. ** **
  • [[SQLITE_FCNTL_SYNC_OMITTED]] -** No longer in use. +** The SQLITE_FCNTL_SYNC_OMITTED file-control is no longer used. ** **
  • [[SQLITE_FCNTL_SYNC]] ** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and @@ -1442,7 +1468,7 @@ struct sqlite3_io_methods { ** **
  • [[SQLITE_FCNTL_VFSNAME]] ** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of -** all [VFSes] in the VFS stack. The names are of all VFS shims and the +** all [VFSes] in the VFS stack. The names of all VFS shims and the ** final bottom-level VFS are written into memory obtained from ** [sqlite3_malloc()] and the result is stored in the char* variable ** that the fourth parameter of [sqlite3_file_control()] points to. @@ -1456,7 +1482,7 @@ struct sqlite3_io_methods { ** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level ** [VFSes] currently in use. ^(The argument X in ** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be -** of type "[sqlite3_vfs] **". This opcodes will set *X +** of type "[sqlite3_vfs] **". This opcode will set *X ** to a pointer to the top-level VFS.)^ ** ^When there are multiple VFS shims in the stack, this opcode finds the ** upper-most shim only. @@ -1543,6 +1569,11 @@ struct sqlite3_io_methods { ** pointed to by the pArg argument. This capability is used during testing ** and only needs to be supported when SQLITE_TEST is defined. ** +**
  • [[SQLITE_FCNTL_NULL_IO]] +** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor +** or file handle for the [sqlite3_file] object such that it will no longer +** read or write to the database file. +** **
  • [[SQLITE_FCNTL_WAL_BLOCK]] ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might ** be advantageous to block on the next WAL lock if the lock is not immediately @@ -1601,6 +1632,12 @@ struct sqlite3_io_methods { ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** +**
  • [[SQLITE_FCNTL_BLOCK_ON_CONNECT]] +** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the +** VFS to block when taking a SHARED lock to connect to a wal mode database. +** This is used to implement the functionality associated with +** SQLITE_SETLK_BLOCK_ON_CONNECT. +** **
  • [[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. @@ -1635,7 +1672,7 @@ struct sqlite3_io_methods { **
  • [[SQLITE_FCNTL_EXTERNAL_READER]] ** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect ** whether or not there is a database client in another process with a wal-mode -** transaction open on the database or not. It is only available on unix.The +** transaction open on the database or not. It is only available on unix. The ** (void*) argument passed with this file-control should be a pointer to a ** value of type (int). The integer value is set to 1 if the database is a wal ** mode database and there exists at least one client in another process that @@ -1653,6 +1690,15 @@ struct sqlite3_io_methods { ** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control ** purges the contents of the in-memory page cache. If there is an open ** transaction, or if the db is a temp-db, this opcode is a no-op, not an error. +** +**
  • [[SQLITE_FCNTL_FILESTAT]] +** The [SQLITE_FCNTL_FILESTAT] opcode returns low-level diagnostic information +** about the [sqlite3_file] objects used access the database and journal files +** for the given schema. The fourth parameter to [sqlite3_file_control()] +** should be an initialized [sqlite3_str] pointer. JSON text describing +** various aspects of the sqlite3_file object is appended to the sqlite3_str. +** The SQLITE_FCNTL_FILESTAT opcode is usually a no-op, unless compile-time +** options are used to enable it. ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1696,12 +1742,21 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 +#define SQLITE_FCNTL_NULL_IO 43 +#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44 +#define SQLITE_FCNTL_FILESTAT 45 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO +/* reserved file-control numbers: +** 101 +** 102 +** 103 +*/ + /* ** CAPI3REF: Mutex Handle @@ -1902,7 +1957,7 @@ typedef const char *sqlite3_filename; ** greater and the function pointer is not NULL) and will fall back ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. ** -** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces +** ^The xSetSystemCall(), xGetSystemCall(), and xNextSystemCall() interfaces ** are not used by the SQLite core. These optional interfaces are provided ** by some VFSes to facilitate testing of the VFS code. By overriding ** system calls with functions under its control, a test program can @@ -2058,7 +2113,7 @@ struct sqlite3_vfs { ** SQLite interfaces so that an application usually does not need to ** invoke sqlite3_initialize() directly. For example, [sqlite3_open()] ** calls sqlite3_initialize() so the SQLite library will be automatically -** initialized when [sqlite3_open()] is called if it has not be initialized +** initialized when [sqlite3_open()] is called if it has not been initialized ** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT] ** compile-time option, then the automatic calls to sqlite3_initialize() ** are omitted and the application must call sqlite3_initialize() directly @@ -2123,7 +2178,8 @@ SQLITE_API int sqlite3_os_end(void); ** are called "anytime configuration options". ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before ** [sqlite3_shutdown()] with a first argument that is not an anytime -** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE. +** configuration option, then the sqlite3_config() call will +** return SQLITE_MISUSE. ** Note, however, that ^sqlite3_config() can be called as part of the ** implementation of an application-defined [sqlite3_os_init()]. ** @@ -2315,21 +2371,21 @@ struct sqlite3_mem_methods { ** The [sqlite3_mem_methods] ** structure is filled with the currently defined memory allocation routines.)^ ** This option can be used to overload the default memory allocation -** routines with a wrapper that simulations memory allocation failure or +** routines with a wrapper that simulates memory allocation failure or ** tracks memory usage, for example. ** ** [[SQLITE_CONFIG_SMALL_MALLOC]]
    SQLITE_CONFIG_SMALL_MALLOC
    -**
    ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of +**
    ^The SQLITE_CONFIG_SMALL_MALLOC option takes a single argument of ** type int, interpreted as a boolean, which if true provides a hint to ** SQLite that it should avoid large memory allocations if possible. ** SQLite will run faster if it is free to make large memory allocations, -** but some application might prefer to run slower in exchange for +** but some applications might prefer to run slower in exchange for ** guarantees about memory fragmentation that are possible if large ** allocations are avoided. This hint is normally off. **
    ** ** [[SQLITE_CONFIG_MEMSTATUS]]
    SQLITE_CONFIG_MEMSTATUS
    -**
    ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, +**
    ^The SQLITE_CONFIG_MEMSTATUS option takes a single argument of type int, ** interpreted as a boolean, which enables or disables the collection of ** memory allocation statistics. ^(When memory allocation statistics are ** disabled, the following SQLite interfaces become non-operational: @@ -2374,7 +2430,7 @@ struct sqlite3_mem_methods { ** ^If pMem is NULL and N is non-zero, then each database connection ** does an initial bulk allocation for page cache memory ** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or -** of -1024*N bytes if N is negative, . ^If additional +** of -1024*N bytes if N is negative. ^If additional ** page cache memory is needed beyond what is provided by the initial ** allocation, then SQLite goes to [sqlite3_malloc()] separately for each ** additional cache line.
    @@ -2403,7 +2459,7 @@ struct sqlite3_mem_methods { **
    ^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a ** pointer to an instance of the [sqlite3_mutex_methods] structure. ** The argument specifies alternative low-level mutex routines to be used -** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of +** in place of the mutex routines built into SQLite.)^ ^SQLite makes a copy of ** the content of the [sqlite3_mutex_methods] structure before the call to ** [sqlite3_config()] returns. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then @@ -2426,13 +2482,16 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_LOOKASIDE]]
    SQLITE_CONFIG_LOOKASIDE
    **
    ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine -** the default size of lookaside memory on each [database connection]. +** the default size of [lookaside memory] on each [database connection]. ** The first argument is the -** size of each lookaside buffer slot and the second is the number of -** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE -** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] -** option to [sqlite3_db_config()] can be used to change the lookaside -** configuration on individual connections.)^
    +** size of each lookaside buffer slot ("sz") and the second is the number of +** slots allocated to each database connection ("cnt").)^ +** ^(SQLITE_CONFIG_LOOKASIDE sets the default lookaside size. +** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can +** be used to change the lookaside configuration on individual connections.)^ +** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the +** default lookaside configuration at compile-time. +** ** ** [[SQLITE_CONFIG_PCACHE2]]
    SQLITE_CONFIG_PCACHE2
    **
    ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is @@ -2442,7 +2501,7 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_GETPCACHE2]]
    SQLITE_CONFIG_GETPCACHE2
    **
    ^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which -** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of +** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies off ** the current page cache implementation into that object.)^
    ** ** [[SQLITE_CONFIG_LOG]]
    SQLITE_CONFIG_LOG
    @@ -2459,7 +2518,7 @@ struct sqlite3_mem_methods { ** the logger function is a copy of the first parameter to the corresponding ** [sqlite3_log()] call and is intended to be a [result code] or an ** [extended result code]. ^The third parameter passed to the logger is -** log message after formatting via [sqlite3_snprintf()]. +** a log message after formatting via [sqlite3_snprintf()]. ** The SQLite logging interface is not reentrant; the logger function ** supplied by the application must not invoke any SQLite interface. ** In a multi-threaded application, the application-defined logger @@ -2648,7 +2707,15 @@ struct sqlite3_mem_methods { ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that -** can be passed as the second argument to the [sqlite3_db_config()] interface. +** can be passed as the second parameter to the [sqlite3_db_config()] interface. +** +** The [sqlite3_db_config()] interface is a var-args function. It takes a +** variable number of parameters, though always at least two. The number of +** parameters passed into sqlite3_db_config() depends on which of these +** constants is given as the second parameter. This documentation page +** refers to parameters beyond the second as "arguments". Thus, when this +** page says "the N-th argument" it means "the N-th parameter past the +** configuration option" or "the (N+2)-th parameter to sqlite3_db_config()". ** ** New configuration options may be added in future releases of SQLite. ** Existing configuration options might be discontinued. Applications @@ -2660,31 +2727,58 @@ struct sqlite3_mem_methods { **
    ** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    -**
    ^This option takes three additional arguments that determine the -** [lookaside memory allocator] configuration for the [database connection]. -** ^The first argument (the third parameter to [sqlite3_db_config()] is a +**
    The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the +** configuration of the [lookaside memory allocator] within a database +** connection. +** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are not +** in the [DBCONFIG arguments|usual format]. +** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two, +** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE +** should have a total of five parameters. +**
      +**
    1. The first argument ("buf") is a ** pointer to a memory buffer to use for lookaside memory. -** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb -** may be NULL in which case SQLite will allocate the -** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the -** size of each lookaside buffer slot. ^The third argument is the number of -** slots. The size of the buffer in the first argument must be greater than -** or equal to the product of the second and third arguments. The buffer -** must be aligned to an 8-byte boundary. ^If the second argument to -** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally -** rounded down to the next smaller multiple of 8. ^(The lookaside memory +** The first argument may be NULL in which case SQLite will allocate the +** lookaside buffer itself using [sqlite3_malloc()]. +**

    2. The second argument ("sz") is the +** size of each lookaside buffer slot. Lookaside is disabled if "sz" +** is less than 8. The "sz" argument should be a multiple of 8 less than +** 65536. If "sz" does not meet this constraint, it is reduced in size until +** it does. +**

    3. The third argument ("cnt") is the number of slots. +** Lookaside is disabled if "cnt"is less than 1. +* The "cnt" value will be reduced, if necessary, so +** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt" +** parameter is usually chosen so that the product of "sz" and "cnt" is less +** than 1,000,000. +**

    +**

    If the "buf" argument is not NULL, then it must +** point to a memory buffer with a size that is greater than +** or equal to the product of "sz" and "cnt". +** The buffer must be aligned to an 8-byte boundary. +** The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words -** when the "current value" returned by -** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero. +** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns -** [SQLITE_BUSY].)^

    +** [SQLITE_BUSY]. +** If the "buf" argument is NULL and an attempt +** to allocate memory based on "sz" and "cnt" fails, then +** lookaside is silently disabled. +**

    +** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the +** default lookaside configuration at initialization. The +** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside +** configuration at compile-time. Typical values for lookaside are 1200 for +** "sz" and 40 to 100 for "cnt". +** ** ** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **

    SQLITE_DBCONFIG_ENABLE_FKEY
    **
    ^This option is used to enable or disable the enforcement of -** [foreign key constraints]. There should be two additional arguments. +** [foreign key constraints]. This is the same setting that is +** enabled or disabled by the [PRAGMA foreign_keys] statement. ** The first argument is an integer which is 0 to disable FK enforcement, ** positive to enable FK enforcement or negative to leave FK enforcement ** unchanged. The second parameter is a pointer to an integer into which @@ -2706,13 +2800,13 @@ struct sqlite3_mem_methods { **

    Originally this option disabled all triggers. ^(However, since ** SQLite version 3.35.0, TEMP triggers are still allowed even if ** this option is off. So, in other words, this option now only disables -** triggers in the main database schema or in the schemas of ATTACH-ed +** triggers in the main database schema or in the schemas of [ATTACH]-ed ** databases.)^

    ** ** [[SQLITE_DBCONFIG_ENABLE_VIEW]] **
    SQLITE_DBCONFIG_ENABLE_VIEW
    **
    ^This option is used to enable or disable [CREATE VIEW | views]. -** There should be two additional arguments. +** There must be two additional arguments. ** The first argument is an integer which is 0 to disable views, ** positive to enable views or negative to leave the setting unchanged. ** The second parameter is a pointer to an integer into which @@ -2728,17 +2822,20 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] **
    SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
    -**
    ^This option is used to enable or disable the -** [fts3_tokenizer()] function which is part of the -** [FTS3] full-text search engine extension. -** There should be two additional arguments. -** The first argument is an integer which is 0 to disable fts3_tokenizer() or -** positive to enable fts3_tokenizer() or negative to leave the setting -** unchanged. -** The second parameter is a pointer to an integer into which -** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled -** following this call. The second parameter may be a NULL pointer, in -** which case the new setting is not reported back.
    +**
    ^This option is used to enable or disable using the +** [fts3_tokenizer()] function - part of the [FTS3] full-text search engine +** extension - without using bound parameters as the parameters. Doing so +** is disabled by default. There must be two additional arguments. The first +** argument is an integer. If it is passed 0, then using fts3_tokenizer() +** without bound parameters is disabled. If it is passed a positive value, +** then calling fts3_tokenizer without bound parameters is enabled. If it +** is passed a negative value, this setting is not modified - this can be +** used to query for the current setting. The second parameter is a pointer +** to an integer into which is written 0 or 1 to indicate the current value +** of this setting (after it is modified, if applicable). The second +** parameter may be a NULL pointer, in which case the value of the setting +** is not reported back. Refer to [FTS3] documentation for further details. +**
    ** ** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]] **
    SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
    @@ -2746,12 +2843,12 @@ struct sqlite3_mem_methods { ** interface independently of the [load_extension()] SQL function. ** The [sqlite3_enable_load_extension()] API enables or disables both the ** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. -** There should be two additional arguments. +** There must be two additional arguments. ** When the first argument to this interface is 1, then only the C-API is ** enabled and the SQL function remains disabled. If the first argument to ** this interface is 0, then both the C-API and the SQL function are disabled. -** If the first argument is -1, then no changes are made to state of either the -** C-API or the SQL function. +** If the first argument is -1, then no changes are made to the state of either +** the C-API or the SQL function. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface ** is disabled or enabled following this call. The second parameter may @@ -2760,23 +2857,30 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_DBCONFIG_MAINDBNAME]]
    SQLITE_DBCONFIG_MAINDBNAME
    **
    ^This option is used to change the name of the "main" database -** schema. ^The sole argument is a pointer to a constant UTF8 string -** which will become the new schema name in place of "main". ^SQLite -** does not make a copy of the new main schema name string, so the application -** must ensure that the argument passed into this DBCONFIG option is unchanged -** until after the database connection closes. +** schema. This option does not follow the +** [DBCONFIG arguments|usual SQLITE_DBCONFIG argument format]. +** This option takes exactly one additional argument so that the +** [sqlite3_db_config()] call has a total of three parameters. The +** extra argument must be a pointer to a constant UTF8 string which +** will become the new schema name in place of "main". ^SQLite does +** not make a copy of the new main schema name string, so the application +** must ensure that the argument passed into SQLITE_DBCONFIG MAINDBNAME +** is unchanged until after the database connection closes. **
    ** ** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] **
    SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
    -**
    Usually, when a database in wal mode is closed or detached from a -** database handle, SQLite checks if this will mean that there are now no -** connections at all to the database. If so, it performs a checkpoint -** operation before closing the connection. This option may be used to -** override this behavior. The first parameter passed to this operation -** is an integer - positive to disable checkpoints-on-close, or zero (the -** default) to enable them, and negative to leave the setting unchanged. -** The second parameter is a pointer to an integer +**
    Usually, when a database in [WAL mode] is closed or detached from a +** database handle, SQLite checks if if there are other connections to the +** same database, and if there are no other database connection (if the +** connection being closed is the last open connection to the database), +** then SQLite performs a [checkpoint] before closing the connection and +** deletes the WAL file. The SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE option can +** be used to override that behavior. The first argument passed to this +** operation (the third parameter to [sqlite3_db_config()]) is an integer +** which is positive to disable checkpoints-on-close, or zero (the default) +** to enable them, and negative to leave the setting unchanged. +** The second argument (the fourth parameter) is a pointer to an integer ** into which is written 0 or 1 to indicate whether checkpoints-on-close ** have been disabled - 0 if they are not disabled, 1 if they are. **
    @@ -2862,7 +2966,7 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]] **
    SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
    **
    The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates -** the legacy behavior of the [ALTER TABLE RENAME] command such it +** the legacy behavior of the [ALTER TABLE RENAME] command such that it ** behaves as it did prior to [version 3.24.0] (2018-06-04). See the ** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for ** additional information. This feature can also be turned on and off @@ -2911,7 +3015,7 @@ struct sqlite3_mem_methods { **
    SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
    **
    The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates ** the legacy file format flag. When activated, this flag causes all newly -** created database file to have a schema format version number (the 4-byte +** created database files to have a schema format version number (the 4-byte ** integer found at offset 44 into the database header) of 1. This in turn ** means that the resulting database file will be readable and writable by ** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting, @@ -2932,13 +3036,16 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]] **
    SQLITE_DBCONFIG_STMT_SCANSTATUS
    **
    The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in -** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears -** a flag that enables collection of the sqlite3_stmt_scanstatus_v2() -** statistics. For statistics to be collected, the flag must be set on -** the database handle both when the SQL statement is prepared and when it -** is stepped. The flag is set (collection of statistics is enabled) -** by default. This option takes two arguments: an integer and a pointer to -** an integer.. The first argument is 1, 0, or -1 to enable, disable, or +** [SQLITE_ENABLE_STMT_SCANSTATUS] builds. In this case, it sets or clears +** a flag that enables collection of run-time performance statistics +** used by [sqlite3_stmt_scanstatus_v2()] and the [nexec and ncycle] +** columns of the [bytecode virtual table]. +** For statistics to be collected, the flag must be set on +** the database handle both when the SQL statement is +** [sqlite3_prepare|prepared] and when it is [sqlite3_step|stepped]. +** The flag is set (collection of statistics is enabled) by default. +**

    This option takes two arguments: an integer and a pointer to +** an integer. The first argument is 1, 0, or -1 to enable, disable, or ** leave unchanged the statement scanstatus option. If the second argument ** is not NULL, then the value of the statement scanstatus setting after ** processing the first argument is written into the integer that the second @@ -2951,7 +3058,7 @@ struct sqlite3_mem_methods { ** in which tables and indexes are scanned so that the scans start at the end ** and work toward the beginning rather than starting at the beginning and ** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the -** same as setting [PRAGMA reverse_unordered_selects]. This option takes +** same as setting [PRAGMA reverse_unordered_selects].

    This option takes ** two arguments which are an integer and a pointer to an integer. The first ** argument is 1, 0, or -1 to enable, disable, or leave unchanged the ** reverse scan order flag, respectively. If the second argument is not NULL, @@ -2960,7 +3067,95 @@ struct sqlite3_mem_methods { ** first argument. **

    ** +** [[SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]] +**
    SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE
    +**
    The SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE option enables or disables +** the ability of the [ATTACH DATABASE] SQL command to create a new database +** file if the database filed named in the ATTACH command does not already +** exist. This ability of ATTACH to create a new database is enabled by +** default. Applications can disable or reenable the ability for ATTACH to +** create new database files using this DBCONFIG option.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is 1, 0, or -1 to enable, disable, or +** leave unchanged the attach-create flag, respectively. If the second +** argument is not NULL, then 0 or 1 is written into the integer that the +** second argument points to depending on if the attach-create flag is set +** after processing the first argument. +**

    +** +** [[SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE]] +**
    SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE
    +**
    The SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE option enables or disables the +** ability of the [ATTACH DATABASE] SQL command to open a database for writing. +** This capability is enabled by default. Applications can disable or +** reenable this capability using the current DBCONFIG option. If +** this capability is disabled, the [ATTACH] command will still work, +** but the database will be opened read-only. If this option is disabled, +** then the ability to create a new database using [ATTACH] is also disabled, +** regardless of the value of the [SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE] +** option.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is 1, 0, or -1 to enable, disable, or +** leave unchanged the ability to ATTACH another database for writing, +** respectively. If the second argument is not NULL, then 0 or 1 is written +** into the integer to which the second argument points, depending on whether +** the ability to ATTACH a read/write database is enabled or disabled +** after processing the first argument. +**

    +** +** [[SQLITE_DBCONFIG_ENABLE_COMMENTS]] +**
    SQLITE_DBCONFIG_ENABLE_COMMENTS
    +**
    The SQLITE_DBCONFIG_ENABLE_COMMENTS option enables or disables the +** ability to include comments in SQL text. Comments are enabled by default. +** An application can disable or reenable comments in SQL text using this +** DBCONFIG option.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is 1, 0, or -1 to enable, disable, or +** leave unchanged the ability to use comments in SQL text, +** respectively. If the second argument is not NULL, then 0 or 1 is written +** into the integer that the second argument points to depending on if +** comments are allowed in SQL text after processing the first argument. +**

    +** +** [[SQLITE_DBCONFIG_FP_DIGITS]] +**
    SQLITE_DBCONFIG_FP_DIGITS
    +**
    The SQLITE_DBCONFIG_FP_DIGITS setting is a small integer that determines +** the number of significant digits that SQLite will attempt to preserve when +** converting floating point numbers (IEEE 754 "doubles") into text. The +** default value 17, as of SQLite version 3.52.0. The value was 15 in all +** prior versions.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is a small integer, between 3 and 23, or +** zero. The FP_DIGITS setting is changed to that small integer, or left +** unaltered if the first argument is zero or out of range. The second argument +** is a pointer to an integer. If the pointer is not NULL, then the value of +** the FP_DIGITS setting, after possibly being modified by the first +** arguments, is written into the integer to which the second argument points. +**

    +** **
    +** +** [[DBCONFIG arguments]]

    Arguments To SQLITE_DBCONFIG Options

    +** +**

    Most of the SQLITE_DBCONFIG options take two arguments, so that the +** overall call to [sqlite3_db_config()] has a total of four parameters. +** The first argument (the third parameter to sqlite3_db_config()) is +** an integer. +** The second argument is a pointer to an integer. If the first argument is 1, +** then the option becomes enabled. If the first integer argument is 0, +** then the option is disabled. +** If the first argument is -1, then the option setting +** is unchanged. The second argument, the pointer to an integer, may be NULL. +** If the second argument is not NULL, then a value of 0 or 1 is written into +** the integer to which the second argument points, depending on whether the +** setting is disabled or enabled after applying any changes specified by +** the first argument. +** +**

    While most SQLITE_DBCONFIG options use the argument format +** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME], +** [SQLITE_DBCONFIG_LOOKASIDE], and [SQLITE_DBCONFIG_FP_DIGITS] options +** are different. See the documentation of those exceptional options for +** details. */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ @@ -2982,7 +3177,11 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ #define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */ #define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE 1020 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE 1021 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_COMMENTS 1022 /* int int* */ +#define SQLITE_DBCONFIG_FP_DIGITS 1023 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1023 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -3074,10 +3273,14 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. ** The two functions are identical except for the type of the return value -** and that if the number of rows modified by the most recent INSERT, UPDATE +** and that if the number of rows modified by the most recent INSERT, UPDATE, ** or DELETE is greater than the maximum value supported by type "int", then ** the return value of sqlite3_changes() is undefined. ^Executing any other ** type of SQL statement does not modify the value returned by these functions. +** For the purposes of this interface, a CREATE TABLE AS SELECT statement +** does not count as an INSERT, UPDATE or DELETE statement and hence the rows +** added to the new table by the CREATE TABLE AS SELECT statement are not +** counted. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], @@ -3230,7 +3433,7 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** ^These routines return 0 if the statement is incomplete. ^If a ** memory allocation fails, then SQLITE_NOMEM is returned. ** -** ^These routines do not parse the SQL statements thus +** ^These routines do not parse the SQL statements and thus ** will not detect syntactically incorrect SQL. ** ** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior @@ -3332,6 +3535,44 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); +/* +** CAPI3REF: Set the Setlk Timeout +** METHOD: sqlite3 +** +** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If +** the VFS supports blocking locks, it sets the timeout in ms used by +** eligible locks taken on wal mode databases by the specified database +** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does +** not support blocking locks, this function is a no-op. +** +** Passing 0 to this function disables blocking locks altogether. Passing +** -1 to this function requests that the VFS blocks for a long time - +** indefinitely if possible. The results of passing any other negative value +** are undefined. +** +** Internally, each SQLite database handle stores two timeout values - the +** busy-timeout (used for rollback mode databases, or if the VFS does not +** support blocking locks) and the setlk-timeout (used for blocking locks +** on wal-mode databases). The sqlite3_busy_timeout() method sets both +** values, this function sets only the setlk-timeout value. Therefore, +** to configure separate busy-timeout and setlk-timeout values for a single +** database handle, call sqlite3_busy_timeout() followed by this function. +** +** Whenever the number of connections to a wal mode database falls from +** 1 to 0, the last connection takes an exclusive lock on the database, +** then checkpoints and deletes the wal file. While it is doing this, any +** new connection that tries to read from the database fails with an +** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is +** passed to this API, the new connection blocks until the exclusive lock +** has been released. +*/ +SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags); + +/* +** CAPI3REF: Flags for sqlite3_setlk_timeout() +*/ +#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01 + /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 @@ -3339,7 +3580,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); ** This is a legacy interface that is preserved for backwards compatibility. ** Use of this interface is not recommended. ** -** Definition: A result table is memory data structure created by the +** Definition: A result table is a memory data structure created by the ** [sqlite3_get_table()] interface. A result table records the ** complete query results from one or more queries. ** @@ -3482,7 +3723,7 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** ^Calling sqlite3_free() with a pointer previously returned ** by sqlite3_malloc() or sqlite3_realloc() releases that memory so ** that it might be reused. ^The sqlite3_free() routine is -** a no-op if is called with a NULL pointer. Passing a NULL pointer +** a no-op if it is called with a NULL pointer. Passing a NULL pointer ** to sqlite3_free() is harmless. After being freed, memory ** should neither be read nor written. Even reading previously freed ** memory might result in a segmentation fault or other severe error. @@ -3500,13 +3741,13 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** sqlite3_free(X). ** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation ** of at least N bytes in size or NULL if insufficient memory is available. -** ^If M is the size of the prior allocation, then min(N,M) bytes -** of the prior allocation are copied into the beginning of buffer returned +** ^If M is the size of the prior allocation, then min(N,M) bytes of the +** prior allocation are copied into the beginning of the buffer returned ** by sqlite3_realloc(X,N) and the prior allocation is freed. ** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the ** prior allocation is not freed. ** -** ^The sqlite3_realloc64(X,N) interfaces works the same as +** ^The sqlite3_realloc64(X,N) interface works the same as ** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead ** of a 32-bit signed integer. ** @@ -3556,7 +3797,7 @@ SQLITE_API sqlite3_uint64 sqlite3_msize(void*); ** was last reset. ^The values returned by [sqlite3_memory_used()] and ** [sqlite3_memory_highwater()] include any overhead ** added by SQLite in its implementation of [sqlite3_malloc()], -** but not overhead added by the any underlying system library +** but not overhead added by any underlying system library ** routines that [sqlite3_malloc()] may call. ** ** ^The memory high-water mark is reset to the current value of @@ -4008,7 +4249,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** there is no harm in trying.) ** ** ^(

    [SQLITE_OPEN_SHAREDCACHE]
    -**
    The database is opened [shared cache] enabled, overriding +**
    The database is opened with [shared cache] enabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** The [use of shared cache mode is discouraged] and hence shared cache @@ -4016,7 +4257,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** this option is a no-op. ** ** ^(
    [SQLITE_OPEN_PRIVATECACHE]
    -**
    The database is opened [shared cache] disabled, overriding +**
    The database is opened with [shared cache] disabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** @@ -4351,7 +4592,7 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); ** ** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of ** database filename D with corresponding journal file J and WAL file W and -** with N URI parameters key/values pairs in the array P. The result from +** an array P of N URI Key/Value pairs. The result from ** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that ** is safe to pass to routines like: **
      @@ -4422,6 +4663,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); **
    • sqlite3_errmsg() **
    • sqlite3_errmsg16() **
    • sqlite3_error_offset() +**
    • sqlite3_db_handle() **
    ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language @@ -4434,7 +4676,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); ** subsequent calls to other SQLite interface functions.)^ ** ** ^The sqlite3_errstr(E) interface returns the English-language text -** that describes the [result code] E, as UTF-8, or NULL if E is not an +** that describes the [result code] E, as UTF-8, or NULL if E is not a ** result code for which a text error message is available. ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. @@ -4442,7 +4684,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); ** ^If the most recent error references a specific token in the input ** SQL, the sqlite3_error_offset() interface returns the byte offset ** of the start of that token. ^The byte offset returned by -** sqlite3_error_offset() assumes that the input SQL is UTF8. +** sqlite3_error_offset() assumes that the input SQL is UTF-8. ** ^If the most recent error does not reference a specific token in the input ** SQL, then the sqlite3_error_offset() function returns -1. ** @@ -4467,6 +4709,34 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3*); SQLITE_API const char *sqlite3_errstr(int); SQLITE_API int sqlite3_error_offset(sqlite3 *db); +/* +** CAPI3REF: Set Error Code And Message +** METHOD: sqlite3 +** +** Set the error code of the database handle passed as the first argument +** to errcode, and the error message to a copy of nul-terminated string +** zErrMsg. If zErrMsg is passed NULL, then the error message is set to +** the default message associated with the supplied error code. Subsequent +** calls to [sqlite3_errcode()] and [sqlite3_errmsg()] and similar will +** return the values set by this routine in place of what was previously +** set by SQLite itself. +** +** This function returns SQLITE_OK if the error code and error message are +** successfully set, SQLITE_NOMEM if an OOM occurs, and SQLITE_MISUSE if +** the database handle is NULL or invalid. +** +** The error code and message set by this routine remains in effect until +** they are changed, either by another call to this routine or until they are +** changed to by SQLite itself to reflect the result of some subsquent +** API call. +** +** This function is intended for use by SQLite extensions or wrappers. The +** idea is that an extension or wrapper can use this routine to set error +** messages and error codes and thus behave more like a core SQLite +** feature from the point of view of an application. +*/ +SQLITE_API int sqlite3_set_errmsg(sqlite3 *db, int errcode, const char *zErrMsg); + /* ** CAPI3REF: Prepared Statement Object ** KEYWORDS: {prepared statement} {prepared statements} @@ -4541,8 +4811,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** These constants define various performance limits ** that can be lowered at run-time using [sqlite3_limit()]. -** The synopsis of the meanings of the various limits is shown below. -** Additional information is available at [limits | Limits in SQLite]. +** A concise description of these limits follows, and additional information +** is available at [limits | Limits in SQLite]. ** **
    ** [[SQLITE_LIMIT_LENGTH]] ^(
    SQLITE_LIMIT_LENGTH
    @@ -4557,7 +4827,12 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** or in an ORDER BY or GROUP BY clause.
    )^ ** ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
    SQLITE_LIMIT_EXPR_DEPTH
    -**
    The maximum depth of the parse tree on any expression.
    )^ +**
    The maximum depth of the parse tree on any expression and +** the maximum nesting depth for subqueries and VIEWs
    )^ +** +** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(
    SQLITE_LIMIT_PARSER_DEPTH
    +**
    The maximum depth of the LALR(1) parser stack used to analyze +** input SQL statements.
    )^ ** ** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(
    SQLITE_LIMIT_COMPOUND_SELECT
    **
    The maximum number of terms in a compound SELECT statement.
    )^ @@ -4584,7 +4859,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); **
    The maximum index number of any [parameter] in an SQL statement.)^ ** ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
    SQLITE_LIMIT_TRIGGER_DEPTH
    -**
    The maximum depth of recursion for triggers.
    )^ +**
    The maximum depth of recursion for triggers, and the maximum +** nesting depth for separate triggers.
    )^ ** ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
    SQLITE_LIMIT_WORKER_THREADS
    **
    The maximum number of auxiliary worker threads that a single @@ -4603,11 +4879,12 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +#define SQLITE_LIMIT_PARSER_DEPTH 12 /* ** CAPI3REF: Prepare Flags ** -** These constants define various flags that can be passed into +** These constants define various flags that can be passed into the ** "prepFlags" parameter of the [sqlite3_prepare_v3()] and ** [sqlite3_prepare16_v3()] interfaces. ** @@ -4637,11 +4914,39 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); **
    The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler ** to return an error (error code SQLITE_ERROR) if the statement uses ** any virtual tables. +** +** [[SQLITE_PREPARE_DONT_LOG]]
    SQLITE_PREPARE_DONT_LOG
    +**
    The SQLITE_PREPARE_DONT_LOG flag prevents SQL compiler +** errors from being sent to the error log defined by +** [SQLITE_CONFIG_LOG]. This can be used, for example, to do test +** compiles to see if some SQL syntax is well-formed, without generating +** messages on the global error log when it is not. If the test compile +** fails, the sqlite3_prepare_v3() call returns the same error indications +** with or without this flag; it just omits the call to [sqlite3_log()] that +** logs the error. +** +** [[SQLITE_PREPARE_FROM_DDL]]
    SQLITE_PREPARE_FROM_DDL
    +**
    The SQLITE_PREPARE_FROM_DDL flag causes the SQL compiler to enforce +** security constraints that would otherwise only be enforced when parsing +** the database schema. In other words, the SQLITE_PREPARE_FROM_DDL flag +** causes the SQL compiler to treat the SQL statement being prepared as if +** it had come from an attacker. When SQLITE_PREPARE_FROM_DDL is used and +** [SQLITE_DBCONFIG_TRUSTED_SCHEMA] is off, SQL functions may only be called +** if they are tagged with [SQLITE_INNOCUOUS] and virtual tables may only +** be used if they are tagged with [SQLITE_VTAB_INNOCUOUS]. Best practice +** is to use the SQLITE_PREPARE_FROM_DDL option when preparing any SQL that +** is derived from parts of the database schema. In particular, virtual +** table implementations that run SQL statements that are derived from +** arguments to their CREATE VIRTUAL TABLE statement should always use +** [sqlite3_prepare_v3()] and set the SQLITE_PREPARE_FROM_DDL flag to +** prevent bypass of the [SQLITE_DBCONFIG_TRUSTED_SCHEMA] security checks. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 #define SQLITE_PREPARE_NORMALIZE 0x02 #define SQLITE_PREPARE_NO_VTAB 0x04 +#define SQLITE_PREPARE_DONT_LOG 0x10 +#define SQLITE_PREPARE_FROM_DDL 0x20 /* ** CAPI3REF: Compiling An SQL Statement @@ -4655,8 +4960,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** The preferred routine to use is [sqlite3_prepare_v2()]. The ** [sqlite3_prepare()] interface is legacy and should be avoided. -** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used -** for special purposes. +** [sqlite3_prepare_v3()] has an extra +** [SQLITE_PREPARE_FROM_DDL|"prepFlags" option] that is sometimes +** needed for special purpose or to pass along security restrictions. ** ** The use of the UTF-8 interfaces is preferred, as SQLite currently ** does all parsing using UTF-8. The UTF-16 interfaces are provided @@ -4683,7 +4989,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** there is a small performance advantage to passing an nByte parameter that ** is the number of bytes in the input string including ** the nul-terminator. -** Note that nByte measure the length of the input in bytes, not +** Note that nByte measures the length of the input in bytes, not ** characters, even for the UTF-16 interfaces. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte @@ -4817,7 +5123,7 @@ SQLITE_API int sqlite3_prepare16_v3( ** ** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory ** is available to hold the result, or if the result would exceed the -** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. +** maximum string length determined by the [SQLITE_LIMIT_LENGTH]. ** ** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time @@ -5005,7 +5311,7 @@ typedef struct sqlite3_value sqlite3_value; ** ** The context in which an SQL function executes is stored in an ** sqlite3_context object. ^A pointer to an sqlite3_context object -** is always first parameter to [application-defined SQL functions]. +** is always the first parameter to [application-defined SQL functions]. ** The application-defined SQL function implementation will pass this ** pointer through into calls to [sqlite3_result_int | sqlite3_result()], ** [sqlite3_aggregate_context()], [sqlite3_user_data()], @@ -5021,7 +5327,7 @@ typedef struct sqlite3_context sqlite3_context; ** METHOD: sqlite3_stmt ** ** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants, -** literals may be replaced by a [parameter] that matches one of following +** literals may be replaced by a [parameter] that matches one of the following ** templates: ** **
      @@ -5061,12 +5367,12 @@ typedef struct sqlite3_context sqlite3_context; ** it should be a pointer to well-formed UTF16 text. ** ^If the third parameter to sqlite3_bind_text64() is not NULL, then ** it should be a pointer to a well-formed unicode string that is -** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16 -** otherwise. +** either UTF8 if the sixth parameter is SQLITE_UTF8 or SQLITE_UTF8_ZT, +** or UTF16 otherwise. ** ** [[byte-order determination rules]] ^The byte-order of ** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF) -** found in first character, which is removed, or in the absence of a BOM +** found in the first character, which is removed, or in the absence of a BOM ** the byte order is the native byte order of the host ** machine for sqlite3_bind_text16() or the byte order specified in ** the 6th parameter for sqlite3_bind_text64().)^ @@ -5086,7 +5392,7 @@ typedef struct sqlite3_context sqlite3_context; ** or sqlite3_bind_text16() or sqlite3_bind_text64() then ** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL -** terminated. If any NUL characters occurs at byte offsets less than +** terminated. If any NUL characters occur at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. @@ -5108,10 +5414,15 @@ typedef struct sqlite3_context sqlite3_context; ** object and pointer to it must remain valid until then. ^SQLite will then ** manage the lifetime of its private copy. ** -** ^The sixth argument to sqlite3_bind_text64() must be one of -** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] -** to specify the encoding of the text in the third parameter. If -** the sixth argument to sqlite3_bind_text64() is not one of the +** ^The sixth argument (the E argument) +** to sqlite3_bind_text64(S,K,Z,N,D,E) must be one of +** [SQLITE_UTF8], [SQLITE_UTF8_ZT], [SQLITE_UTF16], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE] to specify the encoding of the text in the +** third parameter, Z. The special value [SQLITE_UTF8_ZT] means that the +** string argument is both UTF-8 encoded and is zero-terminated. In other +** words, SQLITE_UTF8_ZT means that the Z array is allocated to hold at +** least N+1 bytes and that the Z[N] byte is zero. If +** the E argument to sqlite3_bind_text64(S,K,Z,N,D,E) is not one of the ** allowed values shown above, or if the text encoding is different ** from the encoding specified by the sixth parameter, then the behavior ** is undefined. @@ -5129,9 +5440,11 @@ typedef struct sqlite3_context sqlite3_context; ** associated with the pointer P of type T. ^D is either a NULL pointer or ** a pointer to a destructor function for P. ^SQLite will invoke the ** destructor D with a single argument of P when it is finished using -** P. The T parameter should be a static string, preferably a string -** literal. The sqlite3_bind_pointer() routine is part of the -** [pointer passing interface] added for SQLite 3.20.0. +** P, even if the call to sqlite3_bind_pointer() fails. Due to a +** historical design quirk, results are undefined if D is +** SQLITE_TRANSIENT. The T parameter should be a static string, +** preferably a string literal. The sqlite3_bind_pointer() routine is +** part of the [pointer passing interface] added for SQLite 3.20.0. ** ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer ** for the [prepared statement] or with a prepared statement for which @@ -5298,7 +5611,7 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); ** METHOD: sqlite3_stmt ** ** ^These routines provide a means to determine the database, table, and -** table column that is the origin of a particular result column in +** table column that is the origin of a particular result column in a ** [SELECT] statement. ** ^The name of the database or table or column can be returned as ** either a UTF-8 or UTF-16 string. ^The _database_ routines return @@ -5436,7 +5749,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from -** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], +** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]), ** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility @@ -5742,7 +6055,7 @@ SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); ** ** ^The sqlite3_finalize() function is called to delete a [prepared statement]. ** ^If the most recent evaluation of the statement encountered no errors -** or if the statement is never been evaluated, then sqlite3_finalize() returns +** or if the statement has never been evaluated, then sqlite3_finalize() returns ** SQLITE_OK. ^If the most recent evaluation of statement S failed, then ** sqlite3_finalize(S) returns the appropriate [error code] or ** [extended error code]. @@ -5867,8 +6180,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** ** For best security, the [SQLITE_DIRECTONLY] flag is recommended for ** all application-defined SQL functions that do not need to be -** used inside of triggers, view, CHECK constraints, or other elements of -** the database schema. This flags is especially recommended for SQL +** used inside of triggers, views, CHECK constraints, or other elements of +** the database schema. This flag is especially recommended for SQL ** functions that have side effects or reveal internal application state. ** Without this flag, an attacker might be able to modify the schema of ** a database file to include invocations of the function with parameters @@ -5899,7 +6212,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** [user-defined window functions|available here]. ** ** ^(If the final parameter to sqlite3_create_function_v2() or -** sqlite3_create_window_function() is not NULL, then it is destructor for +** sqlite3_create_window_function() is not NULL, then it is the destructor for ** the application data pointer. The destructor is invoked when the function ** is deleted, either by being overloaded or when the database connection ** closes.)^ ^The destructor is also invoked if the call to @@ -5974,8 +6287,54 @@ SQLITE_API int sqlite3_create_window_function( /* ** CAPI3REF: Text Encodings ** -** These constant define integer codes that represent the various +** These constants define integer codes that represent the various ** text encodings supported by SQLite. +** +**
      +** [[SQLITE_UTF8]]
      SQLITE_UTF8
      Text is encoding as UTF-8
      +** +** [[SQLITE_UTF16LE]]
      SQLITE_UTF16LE
      Text is encoding as UTF-16 +** with each code point being expressed "little endian" - the least significant +** byte first. This is the usual encoding, for example on Windows.
      +** +** [[SQLITE_UTF16BE]]
      SQLITE_UTF16BE
      Text is encoding as UTF-16 +** with each code point being expressed "big endian" - the most significant +** byte first. This encoding is less common, but is still sometimes seen, +** specially on older systems. +** +** [[SQLITE_UTF16]]
      SQLITE_UTF16
      Text is encoding as UTF-16 +** with each code point being expressed either little endian or as big +** endian, according to the native endianness of the host computer. +** +** [[SQLITE_ANY]]
      SQLITE_ANY
      This encoding value may only be used +** to declare the preferred text for [application-defined SQL functions] +** created using [sqlite3_create_function()] and similar. If the preferred +** encoding (the 4th parameter to sqlite3_create_function() - the eTextRep +** parameter) is SQLITE_ANY, that indicates that the function does not have +** a preference regarding the text encoding of its parameters and can take +** any text encoding that the SQLite core find convenient to supply. This +** option is deprecated. Please do not use it in new applications. +** +** [[SQLITE_UTF16_ALIGNED]]
      SQLITE_UTF16_ALIGNED
      This encoding +** value may be used as the 3rd parameter (the eTextRep parameter) to +** [sqlite3_create_collation()] and similar. This encoding value means +** that the application-defined collating sequence created expects its +** input strings to be in UTF16 in native byte order, and that the start +** of the strings must be aligned to a 2-byte boundary. +** +** [[SQLITE_UTF8_ZT]]
      SQLITE_UTF8_ZT
      This option can only be +** used to specify the text encoding to strings input to +** [sqlite3_result_text64()] and [sqlite3_bind_text64()]. +** The SQLITE_UTF8_ZT encoding means that the input string (call it "z") +** is UTF-8 encoded and that it is zero-terminated. If the length parameter +** (call it "n") is non-negative, this encoding option means that the caller +** guarantees that z array contains at least n+1 bytes and that the z[n] +** byte has a value of zero. +** This option gives the same output as SQLITE_UTF8, but can be more efficient +** by avoiding the need to make a copy of the input string, in some cases. +** However, if z is allocated to hold fewer than n+1 bytes or if the +** z[n] byte is not zero, undefined behavior may result. +**
      */ #define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ #define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ @@ -5983,6 +6342,7 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* Deprecated */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ +#define SQLITE_UTF8_ZT 16 /* Zero-terminated UTF8 */ /* ** CAPI3REF: Function Flags @@ -6066,7 +6426,7 @@ SQLITE_API int sqlite3_create_window_function( ** result. ** Every function that invokes [sqlite3_result_subtype()] should have this ** property. If it does not, then the call to [sqlite3_result_subtype()] -** might become a no-op if the function is used as term in an +** might become a no-op if the function is used as a term in an ** [expression index]. On the other hand, SQL functions that never invoke ** [sqlite3_result_subtype()] should avoid setting this property, as the ** purpose of this property is to disable certain optimizations that are @@ -6193,7 +6553,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** sqlite3_value_nochange(X) interface returns true if and only if ** the column corresponding to X is unchanged by the UPDATE operation ** that the xUpdate method call was invoked to implement and if -** and the prior [xColumn] method call that was invoked to extracted +** the prior [xColumn] method call that was invoked to extract ** the value for that column returned without setting a result (probably ** because it queried [sqlite3_vtab_nochange()] and found that the column ** was unchanging). ^Within an [xUpdate] method, any value for which @@ -6217,26 +6577,22 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** the SQL function that supplied the [sqlite3_value*] parameters. ** ** As long as the input parameter is correct, these routines can only -** fail if an out-of-memory error occurs during a format conversion. -** Only the following subset of interfaces are subject to out-of-memory -** errors: -** -**
        -**
      • sqlite3_value_blob() -**
      • sqlite3_value_text() -**
      • sqlite3_value_text16() -**
      • sqlite3_value_text16le() -**
      • sqlite3_value_text16be() -**
      • sqlite3_value_bytes() -**
      • sqlite3_value_bytes16() -**
      -** +** fail if an out-of-memory error occurs while trying to do a +** UTF8→UTF16 or UTF16→UTF8 conversion. ** If an out-of-memory error occurs, then the return value from these ** routines is the same as if the column had contained an SQL NULL value. -** Valid SQL NULL returns can be distinguished from out-of-memory errors -** by invoking the [sqlite3_errcode()] immediately after the suspect +** If the input sqlite3_value was not obtained from [sqlite3_value_dup()], +** then valid SQL NULL returns can also be distinguished from +** out-of-memory errors after extracting the value +** by invoking the [sqlite3_errcode()] immediately after the suspicious ** return value is obtained and before any ** other SQLite interface is called on the same [database connection]. +** If the input sqlite3_value was obtained from sqlite3_value_dup() then +** it is disconnected from the database connection and so sqlite3_errcode() +** will not work. +** In that case, the only way to distinguish an out-of-memory +** condition from a true SQL NULL is to invoke sqlite3_value_type() on the +** input to see if it is NULL prior to trying to extract the value. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); @@ -6263,7 +6619,8 @@ SQLITE_API int sqlite3_value_frombind(sqlite3_value*); ** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X) ** returns something other than SQLITE_TEXT, then the return value from ** sqlite3_value_encoding(X) is meaningless. ^Calls to -** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)], +** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], +** [sqlite3_value_text16be(X)], ** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or ** [sqlite3_value_bytes16(X)] might change the encoding of the value X and ** thus change the return from subsequent calls to sqlite3_value_encoding(X). @@ -6299,7 +6656,7 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); ** METHOD: sqlite3_value ** ** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value] -** object D and returns a pointer to that copy. ^The [sqlite3_value] returned +** object V and returns a pointer to that copy. ^The [sqlite3_value] returned ** is a [protected sqlite3_value] object even if the input is not. ** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a ** memory allocation fails. ^If V is a [pointer value], then the result @@ -6337,7 +6694,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*); ** allocation error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is -** determined by the N parameter on first successful call. Changing the +** determined by the N parameter on the first successful call. Changing the ** value of N in any subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory ** allocation.)^ Within the xFinal callback, it is customary to set @@ -6394,17 +6751,17 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** query execution, under some circumstances the associated auxiliary data ** might be preserved. An example of where this might be useful is in a ** regular-expression matching function. The compiled version of the regular -** expression can be stored as auxiliary data associated with the pattern string. -** Then as long as the pattern string remains the same, +** expression can be stored as auxiliary data associated with the pattern +** string. Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data -** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument -** value to the application-defined function. ^N is zero for the left-most -** function argument. ^If there is no auxiliary data -** associated with the function argument, the sqlite3_get_auxdata(C,N) interface -** returns a NULL pointer. +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary +** data associated by the sqlite3_set_auxdata(C,N,P,X) function with the +** Nth argument value to the application-defined function. ^N is zero +** for the left-most function argument. ^If there is no auxiliary data +** associated with the function argument, the sqlite3_get_auxdata(C,N) +** interface returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the ** N-th argument of the application-defined function. ^Subsequent @@ -6466,6 +6823,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi ** or a NULL pointer if there were no prior calls to ** sqlite3_set_clientdata() with the same values of D and N. ** Names are compared using strcmp() and are thus case sensitive. +** It returns 0 on success and SQLITE_NOMEM on allocation failure. ** ** If P and X are both non-NULL, then the destructor X is invoked with ** argument P on the first of the following occurrences: @@ -6487,10 +6845,14 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi ** ** There is no limit (other than available memory) on the number of different ** client data pointers (with different names) that can be attached to a -** single database connection. However, the implementation is optimized -** for the case of having only one or two different client data names. -** Applications and wrapper libraries are discouraged from using more than -** one client data name each. +** single database connection. However, the current implementation stores +** the content on a linked list. Insert and retrieval performance will +** be proportional to the number of entries. The design use case, and +** the use case for which the implementation is optimized, is +** that an application will store only small number of client data names, +** typically just one or two. This interface is not intended to be a +** generalized key/value store for thousands or millions of keys. It +** will work for that, but performance might be disappointing. ** ** There is no way to enumerate the client data pointers ** associated with a database connection. The N parameter can be thought @@ -6499,7 +6861,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi ** ** Security Warning: These interfaces should not be exposed in scripting ** languages or in other circumstances where it might be possible for an -** an attacker to invoke them. Any agent that can invoke these interfaces +** attacker to invoke them. Any agent that can invoke these interfaces ** can probably also take control of the process. ** ** Database connection client data is only available for SQLite @@ -6598,10 +6960,14 @@ typedef void (*sqlite3_destructor_type)(void*); ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. -** ^The sqlite3_result_text64() interface sets the return value of an +** ^The sqlite3_result_text64(C,Z,N,D,E) interface sets the return value of an ** application-defined function to be a text string in an encoding -** specified by the fifth (and last) parameter, which must be one -** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. +** specified the E parameter, which must be one +** of [SQLITE_UTF8], [SQLITE_UTF8_ZT], [SQLITE_UTF16], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE]. ^The special value [SQLITE_UTF8_ZT] means that +** the result text is both UTF-8 and zero-terminated. In other words, +** SQLITE_UTF8_ZT means that the Z array holds at least N+1 bytes and that +** the Z[N] is zero. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to any of the sqlite3_result_text* interfaces @@ -6613,7 +6979,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** pointed to by the 2nd parameter are taken as the application-defined ** function result. If the 3rd parameter is non-negative, then it ** must be the byte offset into the string where the NUL terminator would -** appear if the string where NUL terminated. If any NUL characters occur +** appear if the string were NUL terminated. If any NUL characters occur ** in the string at a byte offset that is less than the value of the 3rd ** parameter, then the resulting string will contain embedded NULs and the ** result of expressions operating on strings with embedded NULs is undefined. @@ -6671,7 +7037,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** string and preferably a string literal. The sqlite3_result_pointer() ** routine is part of the [pointer passing interface] added for SQLite 3.20.0. ** -** If these routines are called from within the different thread +** If these routines are called from within a different thread ** than the one containing the application-defined function that received ** the [sqlite3_context] pointer, the results are undefined. */ @@ -6688,7 +7054,7 @@ SQLITE_API void sqlite3_result_int(sqlite3_context*, int); SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); SQLITE_API void sqlite3_result_null(sqlite3_context*); SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); -SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, +SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char *z, sqlite3_uint64 n, void(*)(void*), unsigned char encoding); SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); @@ -7077,7 +7443,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); ** METHOD: sqlite3 ** ** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name -** for the N-th database on database connection D, or a NULL pointer of N is +** for the N-th database on database connection D, or a NULL pointer if N is ** out of range. An N value of 0 means the main database file. An N of 1 is ** the "temp" schema. Larger values of N correspond to various ATTACH-ed ** databases. @@ -7172,7 +7538,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); **
      The SQLITE_TXN_READ state means that the database is currently ** in a read transaction. Content has been read from the database file ** but nothing in the database file has changed. The transaction state -** will advanced to SQLITE_TXN_WRITE if any changes occur and there are +** will be advanced to SQLITE_TXN_WRITE if any changes occur and there are ** no other conflicting concurrent write transactions. The transaction ** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or ** [COMMIT].
      @@ -7181,7 +7547,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); **
      The SQLITE_TXN_WRITE state means that the database is currently ** in a write transaction. Content has been written to the database file ** but has not yet committed. The transaction state will change to -** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
      +** SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
    */ #define SQLITE_TXN_NONE 0 #define SQLITE_TXN_READ 1 @@ -7332,6 +7698,8 @@ SQLITE_API int sqlite3_autovacuum_pages( ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. +** ^The update hook is disabled by invoking sqlite3_update_hook() +** with a NULL pointer as the second parameter. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], @@ -7460,7 +7828,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); ** CAPI3REF: Impose A Limit On Heap Size ** ** These interfaces impose limits on the amount of heap memory that will be -** by all database connections within a single process. +** used by all database connections within a single process. ** ** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the ** soft limit on the amount of heap memory that may be allocated by SQLite. @@ -7518,7 +7886,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); ** )^ ** ** The circumstances under which SQLite will enforce the heap limits may -** changes in future releases of SQLite. +** change in future releases of SQLite. */ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N); @@ -7625,7 +7993,7 @@ SQLITE_API int sqlite3_table_column_metadata( ** ^The sqlite3_load_extension() interface attempts to load an ** [SQLite extension] library contained in the file zFile. If ** the file cannot be loaded directly, attempts are made to load -** with various operating-system specific extensions added. +** with various operating-system specific filename extensions added. ** So for example, if "samplelib" cannot be loaded, then names like ** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might ** be tried also. @@ -7633,10 +8001,10 @@ SQLITE_API int sqlite3_table_column_metadata( ** ^The entry point is zProc. ** ^(zProc may be 0, in which case SQLite will try to come up with an ** entry point name on its own. It first tries "sqlite3_extension_init". -** If that does not work, it constructs a name "sqlite3_X_init" where the -** X is consists of the lower-case equivalent of all ASCII alphabetic -** characters in the filename from the last "/" to the first following -** "." and omitting any initial "lib".)^ +** If that does not work, it tries names of the form "sqlite3_X_init" +** where X consists of the lower-case equivalent of all ASCII alphabetic +** characters or all ASCII alphanumeric characters in the filename from +** the last "/" to the first following "." and omitting any initial "lib".)^ ** ^The sqlite3_load_extension() interface returns ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. ** ^If an error occurs and pzErrMsg is not 0, then the @@ -7705,12 +8073,12 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three ** arguments and expects an integer result as if the signature of the -** entry point where as follows: +** entry point were as follows: ** **
     **    int xEntryPoint(
     **      sqlite3 *db,
    -**      const char **pzErrMsg,
    +**      char **pzErrMsg,
     **      const struct sqlite3_api_routines *pThunk
     **    );
     ** 
    )^ @@ -7869,7 +8237,7 @@ struct sqlite3_module { ** virtual table and might not be checked again by the byte code.)^ ^(The ** aConstraintUsage[].omit flag is an optimization hint. When the omit flag ** is left in its default setting of false, the constraint will always be -** checked separately in byte code. If the omit flag is change to true, then +** checked separately in byte code. If the omit flag is changed to true, then ** the constraint may or may not be checked in byte code. In other words, ** when the omit flag is true there is no guarantee that the constraint will ** not be checked again using byte code.)^ @@ -7895,7 +8263,7 @@ struct sqlite3_module { ** The xBestIndex method may optionally populate the idxFlags field with a ** mask of SQLITE_INDEX_SCAN_* flags. One such flag is ** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN] -** output to show the idxNum has hex instead of as decimal. Another flag is +** output to show the idxNum as hex instead of as decimal. Another flag is ** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will ** return at most one row. ** @@ -8036,7 +8404,7 @@ struct sqlite3_index_info { ** the implementation of the [virtual table module]. ^The fourth ** parameter is an arbitrary client data pointer that is passed through ** into the [xCreate] and [xConnect] methods of the virtual table module -** when a new virtual table is be being created or reinitialized. +** when a new virtual table is being created or reinitialized. ** ** ^The sqlite3_create_module_v2() interface has a fifth parameter which ** is a pointer to a destructor for the pClientData. ^SQLite will @@ -8201,7 +8569,7 @@ typedef struct sqlite3_blob sqlite3_blob; ** in *ppBlob. Otherwise an [error code] is returned and, unless the error ** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided ** the API is not misused, it is always safe to call [sqlite3_blob_close()] -** on *ppBlob after this function it returns. +** on *ppBlob after this function returns. ** ** This function fails with SQLITE_ERROR if any of the following are true: **
      @@ -8321,7 +8689,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *); ** ** ^Returns the size in bytes of the BLOB accessible via the ** successfully opened [BLOB handle] in its only argument. ^The -** incremental blob I/O routines can only read or overwriting existing +** incremental blob I/O routines can only read or overwrite existing ** blob content; they cannot change the size of a blob. ** ** This routine only works on a [BLOB handle] which has been created @@ -8460,18 +8828,11 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); ** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix ** and Windows. ** -** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor -** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex -** implementation is included with the library. In this case the -** application must supply a custom mutex implementation using the -** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function -** before calling sqlite3_initialize() or any other public sqlite3_ -** function that calls sqlite3_initialize(). ** ** ^The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc() ** routine returns NULL if it is unable to allocate the requested -** mutex. The argument to sqlite3_mutex_alloc() must one of these +** mutex. The argument to sqlite3_mutex_alloc() must be one of these ** integer constants: ** **
        @@ -8704,7 +9065,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); ** CAPI3REF: Retrieve the mutex for a database connection ** METHOD: sqlite3 ** -** ^This interface returns a pointer the [sqlite3_mutex] object that +** ^This interface returns a pointer to the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument ** when the [threading mode] is Serialized. ** ^If the [threading mode] is Single-thread or Multi-thread then this @@ -8821,13 +9182,14 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */ +#define SQLITE_TESTCTRL_ATOF 34 #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking ** ** These routines provide access to the set of SQL language keywords -** recognized by SQLite. Applications can uses these routines to determine +** recognized by SQLite. Applications can use these routines to determine ** whether or not a specific identifier needs to be escaped (for example, ** by enclosing in double-quotes) so as not to confuse the parser. ** @@ -8929,17 +9291,22 @@ SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); ** pass the returned value to [sqlite3_free()] to avoid a memory leak. ** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any ** errors were encountered during construction of the string. ^The -** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the +** [sqlite3_str_finish(X)] interface might also return a NULL pointer if the ** string in [sqlite3_str] object X is zero bytes long. +** +** ^The [sqlite3_str_free(X)] interface destroys both the sqlite3_str object +** X and the string content it contains. Calling sqlite3_str_free(X) is +** the equivalent of calling [sqlite3_free](sqlite3_str_finish(X)). */ SQLITE_API char *sqlite3_str_finish(sqlite3_str*); +SQLITE_API void sqlite3_str_free(sqlite3_str*); /* ** CAPI3REF: Add Content To A Dynamic String ** METHOD: sqlite3_str ** -** These interfaces add content to an sqlite3_str object previously obtained -** from [sqlite3_str_new()]. +** These interfaces add or remove content to an sqlite3_str object +** previously obtained from [sqlite3_str_new()]. ** ** ^The [sqlite3_str_appendf(X,F,...)] and ** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] @@ -8962,6 +9329,10 @@ SQLITE_API char *sqlite3_str_finish(sqlite3_str*); ** ^The [sqlite3_str_reset(X)] method resets the string under construction ** inside [sqlite3_str] object X back to zero bytes in length. ** +** ^The [sqlite3_str_truncate(X,N)] method changes the length of the string +** under construction to be N bytes or less. This routine is a no-op if +** N is negative or if the string is already N bytes or smaller in size. +** ** These methods do not return a result code. ^If an error occurs, that fact ** is recorded in the [sqlite3_str] object and can be recovered by a ** subsequent call to [sqlite3_str_errcode(X)]. @@ -8972,6 +9343,7 @@ SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn); SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); SQLITE_API void sqlite3_str_reset(sqlite3_str*); +SQLITE_API void sqlite3_str_truncate(sqlite3_str*,int N); /* ** CAPI3REF: Status Of A Dynamic String @@ -8995,7 +9367,7 @@ SQLITE_API void sqlite3_str_reset(sqlite3_str*); ** content of the dynamic string under construction in X. The value ** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X ** and might be freed or altered by any subsequent method on the same -** [sqlite3_str] object. Applications must not used the pointer returned +** [sqlite3_str] object. Applications must not use the pointer returned by ** [sqlite3_str_value(X)] after any subsequent method call on the same ** object. ^Applications may change the content of the string returned ** by [sqlite3_str_value(X)] as long as they do not write into any bytes @@ -9081,7 +9453,7 @@ SQLITE_API int sqlite3_status64( ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] ** buffer and where forced to overflow to [sqlite3_malloc()]. The ** returned value includes allocations that overflowed because they -** where too large (they were larger than the "sz" parameter to +** were too large (they were larger than the "sz" parameter to ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because ** no space was left in the page cache.)^ ** @@ -9140,9 +9512,18 @@ SQLITE_API int sqlite3_status64( ** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a ** non-zero [error code] on failure. ** +** ^The sqlite3_db_status64(D,O,C,H,R) routine works exactly the same +** way as sqlite3_db_status(D,O,C,H,R) routine except that the C and H +** parameters are pointer to 64-bit integers (type: sqlite3_int64) instead +** of pointers to 32-bit integers, which allows larger status values +** to be returned. If a status value exceeds 2,147,483,647 then +** sqlite3_db_status() will truncate the value whereas sqlite3_db_status64() +** will return the full value. +** ** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. */ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); +SQLITE_API int sqlite3_db_status64(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int); /* ** CAPI3REF: Status Parameters for database connections @@ -9165,28 +9546,29 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(
        SQLITE_DBSTATUS_LOOKASIDE_HIT
        **
        This parameter returns the number of malloc attempts that were ** satisfied using lookaside memory. Only the high-water value is meaningful; -** the current value is always zero.)^ +** the current value is always zero.
        )^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] ** ^(
        SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
        -**
        This parameter returns the number malloc attempts that might have +**
        This parameter returns the number of malloc attempts that might have ** been satisfied using lookaside memory but failed due to the amount of ** memory requested being larger than the lookaside slot size. ** Only the high-water value is meaningful; -** the current value is always zero.)^ +** the current value is always zero.
        )^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] ** ^(
        SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
        -**
        This parameter returns the number malloc attempts that might have +**
        This parameter returns the number of malloc attempts that might have ** been satisfied using lookaside memory but failed due to all lookaside ** memory already being in use. ** Only the high-water value is meaningful; -** the current value is always zero.)^ +** the current value is always zero.
        )^ ** ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
        SQLITE_DBSTATUS_CACHE_USED
        **
        This parameter returns the approximate number of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. +**
        ** ** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] ** ^(
        SQLITE_DBSTATUS_CACHE_USED_SHARED
        @@ -9195,10 +9577,10 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** memory used by that pager cache is divided evenly between the attached ** connections.)^ In other words, if none of the pager caches associated ** with the database connection are shared, this request returns the same -** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are +** value as DBSTATUS_CACHE_USED. Or, if one or more of the pager caches are ** shared, the value returned by this call will be smaller than that returned ** by DBSTATUS_CACHE_USED. ^The highwater mark associated with -** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. +** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. ** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
        SQLITE_DBSTATUS_SCHEMA_USED
        **
        This parameter returns the approximate number of bytes of heap @@ -9208,6 +9590,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** schema memory is shared with other database connections due to ** [shared cache mode] being enabled. ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. +**
        ** ** [[SQLITE_DBSTATUS_STMT_USED]] ^(
        SQLITE_DBSTATUS_STMT_USED
        **
        This parameter returns the approximate number of bytes of heap @@ -9237,6 +9620,10 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** If an IO or other error occurs while writing a page to disk, the effect ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. +**

        +** ^(There is overlap between the quantities measured by this parameter +** (SQLITE_DBSTATUS_CACHE_WRITE) and SQLITE_DBSTATUS_TEMPBUF_SPILL. +** Resetting one will reduce the other.)^ **

        ** ** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(
        SQLITE_DBSTATUS_CACHE_SPILL
        @@ -9244,7 +9631,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** been written to disk in the middle of a transaction due to the page ** cache overflowing. Transactions are more efficient if they are written ** to disk all at once. When pages spill mid-transaction, that introduces -** additional overhead. This parameter can be used help identify +** additional overhead. This parameter can be used to help identify ** inefficiencies that can be resolved by increasing the cache size. ** ** @@ -9252,6 +9639,18 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r **
        This parameter returns zero for the current value if and only if ** all foreign key constraints (deferred or immediate) have been ** resolved.)^ ^The highwater mark is always 0. +** +** [[SQLITE_DBSTATUS_TEMPBUF_SPILL] ^(
        SQLITE_DBSTATUS_TEMPBUF_SPILL
        +**
        ^(This parameter returns the number of bytes written to temporary +** files on disk that could have been kept in memory had sufficient memory +** been available. This value includes writes to intermediate tables that +** are part of complex queries, external sorts that spill to disk, and +** writes to TEMP tables.)^ +** ^The highwater mark is always 0. +**

        +** ^(There is overlap between the quantities measured by this parameter +** (SQLITE_DBSTATUS_TEMPBUF_SPILL) and SQLITE_DBSTATUS_CACHE_WRITE. +** Resetting one will reduce the other.)^ **

        ** */ @@ -9268,7 +9667,8 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r #define SQLITE_DBSTATUS_DEFERRED_FKS 10 #define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 #define SQLITE_DBSTATUS_CACHE_SPILL 12 -#define SQLITE_DBSTATUS_MAX 12 /* Largest defined DBSTATUS */ +#define SQLITE_DBSTATUS_TEMPBUF_SPILL 13 +#define SQLITE_DBSTATUS_MAX 13 /* Largest defined DBSTATUS */ /* @@ -9315,13 +9715,13 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** [[SQLITE_STMTSTATUS_SORT]]
        SQLITE_STMTSTATUS_SORT
        **
        ^This is the number of sort operations that have occurred. ** A non-zero value in this counter may indicate an opportunity to -** improvement performance through careful use of indices.
        +** improve performance through careful use of indices. ** ** [[SQLITE_STMTSTATUS_AUTOINDEX]]
        SQLITE_STMTSTATUS_AUTOINDEX
        **
        ^This is the number of rows inserted into transient indices that ** were created automatically in order to help joins run faster. ** A non-zero value in this counter may indicate an opportunity to -** improvement performance by adding permanent indices that do not +** improve performance by adding permanent indices that do not ** need to be reinitialized each time the statement is run.
        ** ** [[SQLITE_STMTSTATUS_VM_STEP]]
        SQLITE_STMTSTATUS_VM_STEP
        @@ -9330,19 +9730,19 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** to 2147483647. The number of virtual machine operations can be ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 -** then the value returned by this statement status code is undefined. +** then the value returned by this statement status code is undefined. ** ** [[SQLITE_STMTSTATUS_REPREPARE]]
        SQLITE_STMTSTATUS_REPREPARE
        **
        ^This is the number of times that the prepare statement has been ** automatically regenerated due to schema changes or changes to -** [bound parameters] that might affect the query plan. +** [bound parameters] that might affect the query plan.
        ** ** [[SQLITE_STMTSTATUS_RUN]]
        SQLITE_STMTSTATUS_RUN
        **
        ^This is the number of times that the prepared statement has ** been run. A single "run" for the purposes of this counter is one ** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()]. ** The counter is incremented on the first [sqlite3_step()] call of each -** cycle. +** cycle.
        ** ** [[SQLITE_STMTSTATUS_FILTER_MISS]] ** [[SQLITE_STMTSTATUS_FILTER HIT]] @@ -9352,7 +9752,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** step was bypassed because a Bloom filter returned not-found. The ** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of ** times that the Bloom filter returned a find, and thus the join step -** had to be processed as normal. +** had to be processed as normal. ** ** [[SQLITE_STMTSTATUS_MEMUSED]]
        SQLITE_STMTSTATUS_MEMUSED
        **
        ^This is the approximate number of bytes of heap memory @@ -9457,9 +9857,9 @@ struct sqlite3_pcache_page { ** SQLite will typically create one cache instance for each open database file, ** though this is not guaranteed. ^The ** first parameter, szPage, is the size in bytes of the pages that must -** be allocated by the cache. ^szPage will always a power of two. ^The +** be allocated by the cache. ^szPage will always be a power of two. ^The ** second parameter szExtra is a number of bytes of extra storage -** associated with each page cache entry. ^The szExtra parameter will +** associated with each page cache entry. ^The szExtra parameter will be ** a number less than 250. SQLite will use the ** extra szExtra bytes on each page to store metadata about the underlying ** database page on disk. The value passed into szExtra depends @@ -9467,17 +9867,17 @@ struct sqlite3_pcache_page { ** ^The third argument to xCreate(), bPurgeable, is true if the cache being ** created will be used to cache database pages of a file stored on disk, or ** false if it is used for an in-memory database. The cache implementation -** does not have to do anything special based with the value of bPurgeable; +** does not have to do anything special based upon the value of bPurgeable; ** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will ** never invoke xUnpin() except to deliberately delete a page. ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to ** false will always have the "discard" flag set to true. -** ^Hence, a cache created with bPurgeable false will +** ^Hence, a cache created with bPurgeable set to false will ** never contain any unpinned pages. ** ** [[the xCachesize() page cache method]] ** ^(The xCachesize() method may be called at any time by SQLite to set the -** suggested maximum cache-size (number of pages stored by) the cache +** suggested maximum cache-size (number of pages stored) for the cache ** instance passed as the first argument. This is the value configured using ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable ** parameter, the implementation is not required to do anything with this @@ -9504,12 +9904,12 @@ struct sqlite3_pcache_page { ** implementation must return a pointer to the page buffer with its content ** intact. If the requested page is not already in the cache, then the ** cache implementation should use the value of the createFlag -** parameter to help it determined what action to take: +** parameter to help it determine what action to take: ** ** ** **
        createFlag Behavior when page is not already in cache **
        0 Do not allocate a new page. Return NULL. -**
        1 Allocate a new page if it easy and convenient to do so. +**
        1 Allocate a new page if it is easy and convenient to do so. ** Otherwise return NULL. **
        2 Make every effort to allocate a new page. Only return ** NULL if allocating a new page is effectively impossible. @@ -9526,7 +9926,7 @@ struct sqlite3_pcache_page { ** as its second argument. If the third parameter, discard, is non-zero, ** then the page must be evicted from the cache. ** ^If the discard parameter is -** zero, then the page may be discarded or retained at the discretion of +** zero, then the page may be discarded or retained at the discretion of the ** page cache implementation. ^The page cache implementation ** may choose to evict unpinned pages at any time. ** @@ -9544,7 +9944,7 @@ struct sqlite3_pcache_page { ** When SQLite calls the xTruncate() method, the cache must discard all ** existing cache entries with page numbers (keys) greater than or equal ** to the value of the iLimit parameter passed to xTruncate(). If any -** of these pages are pinned, they are implicitly unpinned, meaning that +** of these pages are pinned, they become implicitly unpinned, meaning that ** they can be safely discarded. ** ** [[the xDestroy() page cache method]] @@ -9724,7 +10124,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** external process or via a database connection other than the one being ** used by the backup operation, then the backup will be automatically ** restarted by the next call to sqlite3_backup_step(). ^If the source -** database is modified by the using the same database connection as is used +** database is modified by using the same database connection as is used ** by the backup operation, then the backup database is automatically ** updated at the same time. ** @@ -9741,7 +10141,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** and may not be used following a call to sqlite3_backup_finish(). ** ** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no -** sqlite3_backup_step() errors occurred, regardless or whether or not +** sqlite3_backup_step() errors occurred, regardless of whether or not ** sqlite3_backup_step() completed. ** ^If an out-of-memory condition or IO error occurred during any prior ** sqlite3_backup_step() call on the same [sqlite3_backup] object, then @@ -9843,7 +10243,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** application receives an SQLITE_LOCKED error, it may call the ** sqlite3_unlock_notify() method with the blocked connection handle as ** the first argument to register for a callback that will be invoked -** when the blocking connections current transaction is concluded. ^The +** when the blocking connection's current transaction is concluded. ^The ** callback is invoked from within the [sqlite3_step] or [sqlite3_close] ** call that concludes the blocking connection's transaction. ** @@ -9863,7 +10263,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** blocked connection already has a registered unlock-notify callback, ** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is ** called with a NULL pointer as its second argument, then any existing -** unlock-notify callback is canceled. ^The blocked connections +** unlock-notify callback is canceled. ^The blocked connection's ** unlock-notify callback may also be canceled by closing the blocked ** connection using [sqlite3_close()]. ** @@ -10033,7 +10433,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); ** is the number of pages currently in the write-ahead log file, ** including those that were just committed. ** -** The callback function should normally return [SQLITE_OK]. ^If an error +** ^The callback function should normally return [SQLITE_OK]. ^If an error ** code is returned, that error will propagate back up through the ** SQLite code base to cause the statement that provoked the callback ** to report an error, though the commit will have still occurred. If the @@ -10041,13 +10441,26 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); ** that does not correspond to any valid SQLite error code, the results ** are undefined. ** -** A single database handle may have at most a single write-ahead log callback -** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any -** previously registered write-ahead log callback. ^The return value is -** a copy of the third parameter from the previous call, if any, or 0. -** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the -** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will -** overwrite any prior [sqlite3_wal_hook()] settings. +** ^A single database handle may have at most a single write-ahead log +** callback registered at one time. ^Calling [sqlite3_wal_hook()] +** replaces the default behavior or previously registered write-ahead +** log callback. +** +** ^The return value is a copy of the third parameter from the +** previous call, if any, or 0. +** +** ^The [sqlite3_wal_autocheckpoint()] interface and the +** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and +** will overwrite any prior [sqlite3_wal_hook()] settings. +** +** ^If a write-ahead log callback is set using this function then +** [sqlite3_wal_checkpoint_v2()] or [PRAGMA wal_checkpoint] +** should be invoked periodically to keep the write-ahead log file +** from growing without bound. +** +** ^Passing a NULL pointer for the callback disables automatic +** checkpointing entirely. To re-enable the default behavior, call +** sqlite3_wal_autocheckpoint(db,1000) or use [PRAGMA wal_checkpoint]. */ SQLITE_API void *sqlite3_wal_hook( sqlite3*, @@ -10064,7 +10477,7 @@ SQLITE_API void *sqlite3_wal_hook( ** to automatically [checkpoint] ** after committing a transaction if there are N or ** more frames in the [write-ahead log] file. ^Passing zero or -** a negative value as the nFrame parameter disables automatic +** a negative value as the N parameter disables automatic ** checkpoints entirely. ** ** ^The callback registered by this function replaces any existing callback @@ -10080,9 +10493,10 @@ SQLITE_API void *sqlite3_wal_hook( ** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] -** pages. The use of this interface -** is only necessary if the default setting is found to be suboptimal -** for a particular application. +** pages. +** +** ^The use of this interface is only necessary if the default setting +** is found to be suboptimal for a particular application. */ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); @@ -10147,6 +10561,11 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the ** addition that it also truncates the log file to zero bytes just prior ** to a successful return. +** +**
        SQLITE_CHECKPOINT_NOOP
        +** ^This mode always checkpoints zero frames. The only reason to invoke +** a NOOP checkpoint is to access the values returned by +** sqlite3_wal_checkpoint_v2() via output parameters *pnLog and *pnCkpt. ** ** ** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in @@ -10217,6 +10636,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( ** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the ** meaning of each of these checkpoint modes. */ +#define SQLITE_CHECKPOINT_NOOP -1 /* Do no work at all */ #define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ #define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ #define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */ @@ -10261,7 +10681,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** support constraints. In this configuration (which is the default) if ** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire ** statement is rolled back as if [ON CONFLICT | OR ABORT] had been -** specified as part of the users SQL statement, regardless of the actual +** specified as part of the user's SQL statement, regardless of the actual ** ON CONFLICT mode specified. ** ** If X is non-zero, then the virtual table implementation guarantees @@ -10295,7 +10715,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** [[SQLITE_VTAB_INNOCUOUS]]
        SQLITE_VTAB_INNOCUOUS
        **
        Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the -** the [xConnect] or [xCreate] methods of a [virtual table] implementation +** [xConnect] or [xCreate] methods of a [virtual table] implementation ** identify that virtual table as being safe to use from within triggers ** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the ** virtual table can do no serious harm even if it is controlled by a @@ -10454,7 +10874,8 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); **
        sqlite3_vtab_distinct() return value ** Rows are returned in aOrderBy order -** Rows with the same value in all aOrderBy columns are adjacent +** Rows with the same value in all aOrderBy columns are +** adjacent ** Duplicates over all colUsed columns may be omitted **
        0yesyesno **
        1noyesno @@ -10463,8 +10884,8 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); **
        ** ** ^For the purposes of comparing virtual table output values to see if the -** values are same value for sorting purposes, two NULL values are considered -** to be the same. In other words, the comparison operator is "IS" +** values are the same value for sorting purposes, two NULL values are +** considered to be the same. In other words, the comparison operator is "IS" ** (or "IS NOT DISTINCT FROM") and not "==". ** ** If a virtual table implementation is unable to meet the requirements @@ -10473,7 +10894,7 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); ** ** ^A virtual table implementation is always free to return rows in any order ** it wants, as long as the "orderByConsumed" flag is not set. ^When the -** the "orderByConsumed" flag is unset, the query planner will add extra +** "orderByConsumed" flag is unset, the query planner will add extra ** [bytecode] to ensure that the final results returned by the SQL query are ** ordered correctly. The use of the "orderByConsumed" flag and the ** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful @@ -10570,7 +10991,7 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); ** sqlite3_vtab_in_next(X,P) should be one of the parameters to the ** xFilter method which invokes these routines, and specifically ** a parameter that was previously selected for all-at-once IN constraint -** processing use the [sqlite3_vtab_in()] interface in the +** processing using the [sqlite3_vtab_in()] interface in the ** [xBestIndex|xBestIndex method]. ^(If the X parameter is not ** an xFilter argument that was selected for all-at-once IN constraint ** processing, then these routines return [SQLITE_ERROR].)^ @@ -10585,7 +11006,7 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); **   ){ **   // do something with pVal **   } -**   if( rc!=SQLITE_OK ){ +**   if( rc!=SQLITE_DONE ){ **   // an error has occurred **   } ** )^ @@ -10625,7 +11046,7 @@ SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut); ** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V) ** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th ** constraint is not available. ^The sqlite3_vtab_rhs_value() interface -** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if +** can return a result code other than SQLITE_OK or SQLITE_NOTFOUND if ** something goes wrong. ** ** The sqlite3_vtab_rhs_value() interface is usually only successful if @@ -10653,8 +11074,8 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** KEYWORDS: {conflict resolution mode} ** ** These constants are returned by [sqlite3_vtab_on_conflict()] to -** inform a [virtual table] implementation what the [ON CONFLICT] mode -** is for the SQL statement being evaluated. +** inform a [virtual table] implementation of the [ON CONFLICT] mode +** for the SQL statement being evaluated. ** ** Note that the [SQLITE_IGNORE] constant is also used as a potential ** return value from the [sqlite3_set_authorizer()] callback and that @@ -10694,39 +11115,39 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** [[SQLITE_SCANSTAT_EST]]
        SQLITE_SCANSTAT_EST
        **
        ^The "double" variable pointed to by the V parameter will be set to the ** query planner's estimate for the average number of rows output from each -** iteration of the X-th loop. If the query planner's estimates was accurate, +** iteration of the X-th loop. If the query planner's estimate was accurate, ** then this value will approximate the quotient NVISIT/NLOOP and the ** product of this value for all prior loops with the same SELECTID will -** be the NLOOP value for the current loop. +** be the NLOOP value for the current loop.
        ** ** [[SQLITE_SCANSTAT_NAME]]
        SQLITE_SCANSTAT_NAME
        **
        ^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the name of the index or table -** used for the X-th loop. +** used for the X-th loop.
        ** ** [[SQLITE_SCANSTAT_EXPLAIN]]
        SQLITE_SCANSTAT_EXPLAIN
        **
        ^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] -** description for the X-th loop. +** description for the X-th loop.
        ** ** [[SQLITE_SCANSTAT_SELECTID]]
        SQLITE_SCANSTAT_SELECTID
        **
        ^The "int" variable pointed to by the V parameter will be set to the ** id for the X-th query plan element. The id value is unique within the ** statement. The select-id is the same value as is output in the first -** column of an [EXPLAIN QUERY PLAN] query. +** column of an [EXPLAIN QUERY PLAN] query.
        ** ** [[SQLITE_SCANSTAT_PARENTID]]
        SQLITE_SCANSTAT_PARENTID
        **
        The "int" variable pointed to by the V parameter will be set to the -** the id of the parent of the current query element, if applicable, or +** id of the parent of the current query element, if applicable, or ** to zero if the query element has no parent. This is the same value as -** returned in the second column of an [EXPLAIN QUERY PLAN] query. +** returned in the second column of an [EXPLAIN QUERY PLAN] query.
        ** ** [[SQLITE_SCANSTAT_NCYCLE]]
        SQLITE_SCANSTAT_NCYCLE
        **
        The sqlite3_int64 output value is set to the number of cycles, ** according to the processor time-stamp counter, that elapsed while the ** query element was being processed. This value is not available for ** all query elements - if it is unavailable the output variable is -** set to -1. +** set to -1.
        ** */ #define SQLITE_SCANSTAT_NLOOP 0 @@ -10757,9 +11178,9 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** a variable pointed to by the "pOut" parameter. ** ** The "flags" parameter must be passed a mask of flags. At present only -** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX +** one flag is defined - [SQLITE_SCANSTAT_COMPLEX]. If SQLITE_SCANSTAT_COMPLEX ** is specified, then status information is available for all elements -** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If +** of a query plan that are reported by "[EXPLAIN QUERY PLAN]" output. If ** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements ** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of ** the EXPLAIN QUERY PLAN output) are available. Invoking API @@ -10767,13 +11188,14 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter. ** ** Parameter "idx" identifies the specific query element to retrieve statistics -** for. Query elements are numbered starting from zero. A value of -1 may be -** to query for statistics regarding the entire query. ^If idx is out of range +** for. Query elements are numbered starting from zero. A value of -1 may +** retrieve statistics for the entire query. ^If idx is out of range ** - less than -1 or greater than or equal to the total number of query ** elements used to implement the statement - a non-zero value is returned and ** the variable that pOut points to is unchanged. ** -** See also: [sqlite3_stmt_scanstatus_reset()] +** See also: [sqlite3_stmt_scanstatus_reset()] and the +** [nexec and ncycle] columns of the [bytecode virtual table]. */ SQLITE_API int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ @@ -10811,7 +11233,7 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); ** METHOD: sqlite3 ** ** ^If a write-transaction is open on [database connection] D when the -** [sqlite3_db_cacheflush(D)] interface invoked, any dirty +** [sqlite3_db_cacheflush(D)] interface is invoked, any dirty ** pages in the pager-cache that are not currently in use are written out ** to disk. A dirty page may be in use if a database cursor created by an ** active SQL statement is reading from it, or if it is page 1 of a database @@ -10925,8 +11347,8 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** triggers; and so forth. ** ** When the [sqlite3_blob_write()] API is used to update a blob column, -** the pre-update hook is invoked with SQLITE_DELETE. This is because the -** in this case the new values are not available. In this case, when a +** the pre-update hook is invoked with SQLITE_DELETE, because +** the new values are not yet available. In this case, when a ** callback made with op==SQLITE_DELETE is actually a write using the ** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns ** the index of the column being written. In other cases, where the @@ -11044,7 +11466,7 @@ typedef struct sqlite3_snapshot { ** The [sqlite3_snapshot_get()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( +SQLITE_API int sqlite3_snapshot_get( sqlite3 *db, const char *zSchema, sqlite3_snapshot **ppSnapshot @@ -11093,7 +11515,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( ** The [sqlite3_snapshot_open()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( +SQLITE_API int sqlite3_snapshot_open( sqlite3 *db, const char *zSchema, sqlite3_snapshot *pSnapshot @@ -11110,7 +11532,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( ** The [sqlite3_snapshot_free()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); +SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot*); /* ** CAPI3REF: Compare the ages of two snapshot handles. @@ -11137,7 +11559,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); ** This interface is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SNAPSHOT] option. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( +SQLITE_API int sqlite3_snapshot_cmp( sqlite3_snapshot *p1, sqlite3_snapshot *p2 ); @@ -11165,20 +11587,21 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( ** This interface is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SNAPSHOT] option. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); +SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Serialize a database ** -** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory -** that is a serialization of the S database on [database connection] D. +** The sqlite3_serialize(D,S,P,F) interface returns a pointer to +** memory that is a serialization of the S database on +** [database connection] D. If S is a NULL pointer, the main database is used. ** If P is not a NULL pointer, then the size of the database in bytes ** is written into *P. ** ** For an ordinary on-disk database file, the serialization is just a ** copy of the disk file. For an in-memory database or a "TEMP" database, ** the serialization is the same sequence of bytes which would be written -** to disk if that database where backed up to disk. +** to disk if that database were backed up to disk. ** ** The usual case is that sqlite3_serialize() copies the serialization of ** the database into memory obtained from [sqlite3_malloc64()] and returns @@ -11187,7 +11610,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c ** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations ** are made, and the sqlite3_serialize() function will return a pointer ** to the contiguous memory representation of the database that SQLite -** is currently using for that database, or NULL if the no such contiguous +** is currently using for that database, or NULL if no such contiguous ** memory representation of the database exists. A contiguous memory ** representation of the database will usually only exist if there has ** been a prior call to [sqlite3_deserialize(D,S,...)] with the same @@ -11238,12 +11661,13 @@ SQLITE_API unsigned char *sqlite3_serialize( ** ** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the ** [database connection] D to disconnect from database S and then -** reopen S as an in-memory database based on the serialization contained -** in P. The serialized database P is N bytes in size. M is the size of -** the buffer P, which might be larger than N. If M is larger than N, and -** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is -** permitted to add content to the in-memory database as long as the total -** size does not exceed M bytes. +** reopen S as an in-memory database based on the serialization +** contained in P. If S is a NULL pointer, the main database is +** used. The serialized database P is N bytes in size. M is the size +** of the buffer P, which might be larger than N. If M is larger than +** N, and the SQLITE_DESERIALIZE_READONLY bit is not set in F, then +** SQLite is permitted to add content to the in-memory database as +** long as the total size does not exceed M bytes. ** ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will ** invoke sqlite3_free() on the serialization buffer when the database @@ -11258,7 +11682,7 @@ SQLITE_API unsigned char *sqlite3_serialize( ** database is currently in a read transaction or is involved in a backup ** operation. ** -** It is not possible to deserialized into the TEMP database. If the +** It is not possible to deserialize into the TEMP database. If the ** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the ** function returns SQLITE_ERROR. ** @@ -11280,7 +11704,7 @@ SQLITE_API int sqlite3_deserialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which DB to reopen with the deserialization */ unsigned char *pData, /* The serialized database content */ - sqlite3_int64 szDb, /* Number bytes in the deserialization */ + sqlite3_int64 szDb, /* Number of bytes in the deserialization */ sqlite3_int64 szBuf, /* Total size of buffer pData[] */ unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ ); @@ -11288,7 +11712,7 @@ SQLITE_API int sqlite3_deserialize( /* ** CAPI3REF: Flags for sqlite3_deserialize() ** -** The following are allowed values for 6th argument (the F argument) to +** The following are allowed values for the 6th argument (the F argument) to ** the [sqlite3_deserialize(D,S,P,N,M,F)] interface. ** ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization @@ -11310,6 +11734,77 @@ SQLITE_API int sqlite3_deserialize( #define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */ #define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */ +/* +** CAPI3REF: Bind array values to the CARRAY table-valued function +** +** The sqlite3_carray_bind_v2(S,I,P,N,F,X,D) interface binds an array value to +** parameter that is the first argument of the [carray() table-valued function]. +** The S parameter is a pointer to the [prepared statement] that uses the +** carray() functions. I is the parameter index to be bound. I must be the +** index of the parameter that is the first argument to the carray() +** table-valued function. P is a pointer to the array to be bound, and N +** is the number of elements in the array. The F argument is one of +** constants [SQLITE_CARRAY_INT32], [SQLITE_CARRAY_INT64], +** [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT], +** or [SQLITE_CARRAY_BLOB] to indicate the datatype of the array P. +** +** If the X argument is not a NULL pointer or one of the special +** values [SQLITE_STATIC] or [SQLITE_TRANSIENT], then SQLite will invoke +** the function X with argument D when it is finished using the data in P. +** The call to X(D) is a destructor for the array P. The destructor X(D) +** is invoked even if the call to sqlite3_carray_bind_v2() fails. If the X +** parameter is the special-case value [SQLITE_STATIC], then SQLite assumes +** that the data static and the destructor is never invoked. If the X +** parameter is the special-case value [SQLITE_TRANSIENT], then +** sqlite3_carray_bind_v2() makes its own private copy of the data prior +** to returning and never invokes the destructor X. +** +** The sqlite3_carray_bind() function works the same as sqlite3_carray_bind_v2() +** with a D parameter set to P. In other words, +** sqlite3_carray_bind(S,I,P,N,F,X) is same as +** sqlite3_carray_bind_v2(S,I,P,N,F,X,P). +*/ +SQLITE_API int sqlite3_carray_bind_v2( + sqlite3_stmt *pStmt, /* Statement to be bound */ + int i, /* Parameter index */ + void *aData, /* Pointer to array data */ + int nData, /* Number of data elements */ + int mFlags, /* CARRAY flags */ + void (*xDel)(void*), /* Destructor for aData */ + void *pDel /* Optional argument to xDel() */ +); +SQLITE_API int sqlite3_carray_bind( + sqlite3_stmt *pStmt, /* Statement to be bound */ + int i, /* Parameter index */ + void *aData, /* Pointer to array data */ + int nData, /* Number of data elements */ + int mFlags, /* CARRAY flags */ + void (*xDel)(void*) /* Destructor for aData */ +); + +/* +** CAPI3REF: Datatypes for the CARRAY table-valued function +** +** The fifth argument to the [sqlite3_carray_bind()] interface musts be +** one of the following constants, to specify the datatype of the array +** that is being bound into the [carray table-valued function]. +*/ +#define SQLITE_CARRAY_INT32 0 /* Data is 32-bit signed integers */ +#define SQLITE_CARRAY_INT64 1 /* Data is 64-bit signed integers */ +#define SQLITE_CARRAY_DOUBLE 2 /* Data is doubles */ +#define SQLITE_CARRAY_TEXT 3 /* Data is char* */ +#define SQLITE_CARRAY_BLOB 4 /* Data is struct iovec */ + +/* +** Versions of the above #defines that omit the initial SQLITE_, for +** legacy compatibility. +*/ +#define CARRAY_INT32 0 /* Data is 32-bit signed integers */ +#define CARRAY_INT64 1 /* Data is 64-bit signed integers */ +#define CARRAY_DOUBLE 2 /* Data is doubles */ +#define CARRAY_TEXT 3 /* Data is char* */ +#define CARRAY_BLOB 4 /* Data is struct iovec */ + /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. @@ -11332,19 +11827,7 @@ SQLITE_API int sqlite3_deserialize( #if 0 } /* End of the 'extern "C"' block */ #endif -#endif /* SQLITE3_H */ - -/* Function prototypes of SQLite3 Multiple Ciphers */ -SQLITE_PRIVATE int sqlite3mcCheckVfs(const char*); -SQLITE_PRIVATE int sqlite3mcFileControlPragma(sqlite3*, const char*, int, void*); -SQLITE_PRIVATE int sqlite3mcHandleAttachKey(sqlite3*, const char*, const char*, sqlite3_value*, char**); -SQLITE_PRIVATE int sqlite3mcHandleMainKey(sqlite3*, const char*); -typedef struct PgHdr PgHdrMC; -SQLITE_PRIVATE void* sqlite3mcPagerCodec(PgHdrMC* pPg); -typedef struct Pager PagerMC; -SQLITE_PRIVATE int sqlite3mcPagerHasCodec(PagerMC* pPager); -SQLITE_PRIVATE void sqlite3mcInitMemoryMethods(); -SQLITE_PRIVATE int sqlite3mcIsBackupSupported(sqlite3*, const char*, sqlite3*, const char*); +/* #endif for SQLITE3_H will be added by mksqlite3.tcl */ /******** Begin file sqlite3rtree.h *********/ /* @@ -11825,9 +12308,10 @@ SQLITE_API void sqlite3session_table_filter( ** is inserted while a session object is enabled, then later deleted while ** the same session object is disabled, no INSERT record will appear in the ** changeset, even though the delete took place while the session was disabled. -** Or, if one field of a row is updated while a session is disabled, and -** another field of the same row is updated while the session is enabled, the -** resulting changeset will contain an UPDATE change that updates both fields. +** Or, if one field of a row is updated while a session is enabled, and +** then another field of the same row is updated while the session is disabled, +** the resulting changeset will contain an UPDATE change that updates both +** fields. */ SQLITE_API int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ @@ -11899,8 +12383,9 @@ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession ** database zFrom the contents of the two compatible tables would be ** identical. ** -** It an error if database zFrom does not exist or does not contain the -** required compatible table. +** Unless the call to this function is a no-op as described above, it is an +** error if database zFrom does not exist or does not contain the required +** compatible table. ** ** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg @@ -12035,7 +12520,7 @@ SQLITE_API int sqlite3changeset_start_v2( ** The following flags may passed via the 4th parameter to ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: ** -**
        SQLITE_CHANGESETAPPLY_INVERT
        +**
        SQLITE_CHANGESETSTART_INVERT
        ** Invert the changeset while iterating through it. This is equivalent to ** inverting a changeset using sqlite3changeset_invert() before applying it. ** It is an error to specify this flag with a patchset. @@ -12350,19 +12835,6 @@ SQLITE_API int sqlite3changeset_concat( void **ppOut /* OUT: Buffer containing output changeset */ ); - -/* -** CAPI3REF: Upgrade the Schema of a Changeset/Patchset -*/ -SQLITE_API int sqlite3changeset_upgrade( - sqlite3 *db, - const char *zDb, - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ -); - - - /* ** CAPI3REF: Changegroup Handle ** @@ -12592,14 +13064,32 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); ** update the "main" database attached to handle db with the changes found in ** the changeset passed via the second and third arguments. ** +** All changes made by these functions are enclosed in a savepoint transaction. +** If any other error (aside from a constraint failure when attempting to +** write to the target database) occurs, then the savepoint transaction is +** rolled back, restoring the target database to its original state, and an +** SQLite error code returned. Additionally, starting with version 3.51.0, +** an error code and error message that may be accessed using the +** [sqlite3_errcode()] and [sqlite3_errmsg()] APIs are left in the database +** handle. +** ** The fourth argument (xFilter) passed to these functions is the "filter -** callback". If it is not NULL, then for each table affected by at least one -** change in the changeset, the filter callback is invoked with -** the table name as the second argument, and a copy of the context pointer -** passed as the sixth argument as the first. If the "filter callback" -** returns zero, then no attempt is made to apply any changes to the table. -** Otherwise, if the return value is non-zero or the xFilter argument to -** is NULL, all changes related to the table are attempted. +** callback". This may be passed NULL, in which case all changes in the +** changeset are applied to the database. For sqlite3changeset_apply() and +** sqlite3_changeset_apply_v2(), if it is not NULL, then it is invoked once +** for each table affected by at least one change in the changeset. In this +** case the table name is passed as the second argument, and a copy of +** the context pointer passed as the sixth argument to apply() or apply_v2() +** as the first. If the "filter callback" returns zero, then no attempt is +** made to apply any changes to the table. Otherwise, if the return value is +** non-zero, all changes related to the table are attempted. +** +** For sqlite3_changeset_apply_v3(), the xFilter callback is invoked once +** per change. The second argument in this case is an sqlite3_changeset_iter +** that may be queried using the usual APIs for the details of the current +** change. If the "filter callback" returns zero in this case, then no attempt +** is made to apply the current change. If it returns non-zero, the change +** is applied. ** ** For each table that is not excluded by the filter callback, this function ** tests that the target database contains a compatible table. A table is @@ -12620,11 +13110,11 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); ** one such warning is issued for each table in the changeset. ** ** For each change for which there is a compatible table, an attempt is made -** to modify the table contents according to the UPDATE, INSERT or DELETE -** change. If a change cannot be applied cleanly, the conflict handler -** function passed as the fifth argument to sqlite3changeset_apply() may be -** invoked. A description of exactly when the conflict handler is invoked for -** each type of change is below. +** to modify the table contents according to each UPDATE, INSERT or DELETE +** change that is not excluded by a filter callback. If a change cannot be +** applied cleanly, the conflict handler function passed as the fifth argument +** to sqlite3changeset_apply() may be invoked. A description of exactly when +** the conflict handler is invoked for each type of change is below. ** ** Unlike the xFilter argument, xConflict may not be passed NULL. The results ** of passing anything other than a valid function pointer as the xConflict @@ -12720,12 +13210,6 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); ** This can be used to further customize the application's conflict ** resolution strategy. ** -** All changes made by these functions are enclosed in a savepoint transaction. -** If any other error (aside from a constraint failure when attempting to -** write to the target database) occurs, then the savepoint transaction is -** rolled back, restoring the target database to its original state, and an -** SQLite error code returned. -** ** If the output parameters (ppRebase) and (pnRebase) are non-NULL and ** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2() ** may set (*ppRebase) to point to a "rebase" that may be used with the @@ -12775,6 +13259,23 @@ SQLITE_API int sqlite3changeset_apply_v2( void **ppRebase, int *pnRebase, /* OUT: Rebase data */ int flags /* SESSION_CHANGESETAPPLY_* flags */ ); +SQLITE_API int sqlite3changeset_apply_v3( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + sqlite3_changeset_iter *p /* Handle describing change */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, /* OUT: Rebase data */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ +); /* ** CAPI3REF: Flags for sqlite3changeset_apply_v2 @@ -12815,11 +13316,23 @@ SQLITE_API int sqlite3changeset_apply_v2( ** database behave as if they were declared with "ON UPDATE NO ACTION ON ** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL ** or SET DEFAULT. +** +**
        SQLITE_CHANGESETAPPLY_NOUPDATELOOP
        +** Sometimes, a changeset contains two or more update statements such that +** although after applying all updates the database will contain no +** constraint violations, no single update can be applied before the others. +** The simplest example of this is a pair of UPDATEs that have "swapped" +** two column values with a UNIQUE constraint. +**

        +** Usually, sqlite3changeset_apply() and similar functions work hard to try +** to find a way to apply such a changeset. However, if this flag is set, +** then all such updates are considered CONSTRAINT conflicts. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 #define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004 #define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008 +#define SQLITE_CHANGESETAPPLY_NOUPDATELOOP 0x0010 /* ** CAPI3REF: Constants Passed To The Conflict Handler @@ -13194,6 +13707,23 @@ SQLITE_API int sqlite3changeset_apply_v2_strm( void **ppRebase, int *pnRebase, int flags ); +SQLITE_API int sqlite3changeset_apply_v3_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + sqlite3_changeset_iter *p + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, + int flags +); SQLITE_API int sqlite3changeset_concat_strm( int (*xInputA)(void *pIn, void *pData, int *pnData), void *pInA, @@ -13285,6 +13815,232 @@ SQLITE_API int sqlite3session_config(int op, void *pArg); */ #define SQLITE_SESSION_CONFIG_STRMSIZE 1 +/* +** CAPI3REF: Configure a changegroup object +** +** Configure the changegroup object passed as the first argument. +** At present the only valid value for the second parameter is +** [SQLITE_CHANGEGROUP_CONFIG_PATCHSET]. +*/ +SQLITE_API int sqlite3changegroup_config(sqlite3_changegroup*, int, void *pArg); + +/* +** CAPI3REF: Options for sqlite3changegroup_config(). +** +** The following values may be passed as the 2nd parameter to +** sqlite3changegroup_config(). +** +**

        SQLITE_CHANGEGROUP_CONFIG_PATCHSET
        +** A changegroup object generates either a changeset or patchset. Usually, +** this is determined by whether the first call to sqlite3changegroup_add() +** is passed a changeset or a patchset. Or, if the first changes are added +** to the changegroup object using the sqlite3changegroup_change_xxx() +** APIs, then this option may be used to configure whether the changegroup +** object generates a changeset or patchset. +** +** When this option is invoked, parameter pArg must point to a value of +** type int. If the changegroup currently contains zero changes, and the +** value of the int variable is zero or greater than zero, then the +** changegroup is configured to generate a changeset or patchset, +** respectively. It is a no-op, not an error, if the changegroup is not +** configured because it has already started accumulating changes. +** +** Before returning, the int variable is set to 0 if the changegroup is +** configured to generate a changeset, or 1 if it is configured to generate +** a patchset. +*/ +#define SQLITE_CHANGEGROUP_CONFIG_PATCHSET 1 + + +/* +** CAPI3REF: Begin adding a change to a changegroup +** +** This API is used, in concert with other sqlite3changegroup_change_xxx() +** APIs, to add changes to a changegroup object one at a time. To add a +** single change, the caller must: +** +** 1. Invoke sqlite3changegroup_change_begin() to indicate the type of +** change (INSERT, UPDATE or DELETE), the affected table and whether +** or not the change should be marked as indirect. +** +** 2. Invoke sqlite3changegroup_change_int64() or one of the other four +** value functions - _null(), _double(), _text() or _blob() - one or +** more times to specify old.* and new.* values for the change being +** constructed. +** +** 3. Invoke sqlite3changegroup_change_finish() to either finish adding +** the change to the group, or to discard the change altogether. +** +** The first argument to this function must be a pointer to the existing +** changegroup object that the change will be added to. The second argument +** must be SQLITE_INSERT, SQLITE_UPDATE or SQLITE_DELETE. The third is the +** name of the table that the change affects, and the fourth is a boolean +** flag specifying whether the change should be marked as "indirect" (if +** bIndirect is non-zero) or not indirect (if bIndirect is zero). +** +** Following a successful call to this function, this function may not be +** called again on the same changegroup object until after +** sqlite3changegroup_change_finish() has been called. Doing so is an +** SQLITE_MISUSE error. +** +** The changegroup object passed as the first argument must be already +** configured with schema data for the specified table. It may be configured +** either by calling sqlite3changegroup_schema() with a database that contains +** the table, or sqlite3changegroup_add() with a changeset that contains the +** table. If the changegroup object has not been configured with a schema for +** the specified table when this function is called, SQLITE_ERROR is returned. +** +** If successful, SQLITE_OK is returned. Otherwise, if an error occurs, an +** SQLite error code is returned. In this case, if argument pzErr is non-NULL, +** then (*pzErr) may be set to point to a buffer containing a utf-8 formated, +** nul-terminated, English language error message. It is the responsibility +** of the caller to eventually free this buffer using sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_change_begin( + sqlite3_changegroup*, + int eOp, + const char *zTab, + int bIndirect, + char **pzErr +); + +/* +** CAPI3REF: Add a 64-bit integer to a changegroup +** +** This function may only be called between a successful call to +** sqlite3changegroup_change_begin() and its matching +** sqlite3changegroup_change_finish() call. If it is called at any +** other time, it is an SQLITE_MISUSE error. Calling this function +** specifies a 64-bit integer value to be used in the change currently being +** added to the changegroup object passed as the first argument. +** +** The second parameter, bNew, specifies whether the value is to be part of +** the new.* (if bNew is non-zero) or old.* (if bNew is zero) record of +** the change under construction. If this does not match the type of change +** specified by the preceding call to sqlite3changegroup_change_begin() (i.e. +** an old.* value for an SQLITE_INSERT change, or a new.* value for an +** SQLITE_DELETE), then SQLITE_ERROR is returned. +** +** The third parameter specifies the column of the old.* or new.* record that +** the value will be a part of. If the specified table has an explicit primary +** key, then this is the index of the table column, numbered from 0 in the order +** specified within the CREATE TABLE statement. Or, if the table uses an +** implicit rowid key, then the column 0 is the rowid and the explicit columns +** are numbered starting from 1. If the iCol parameter is less than 0 or greater +** than the index of the last column in the table, SQLITE_RANGE is returned. +** +** The fourth parameter is the integer value to use as part of the old.* or +** new.* record. +** +** If this call is successful, SQLITE_OK is returned. Otherwise, if an +** error occurs, an SQLite error code is returned. +*/ +SQLITE_API int sqlite3changegroup_change_int64( + sqlite3_changegroup*, + int bNew, + int iCol, + sqlite3_int64 iVal +); + +/* +** CAPI3REF: Add a NULL to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). Except that +** it configures the change currently under construction with a NULL value +** instead of a 64-bit integer. +*/ +SQLITE_API int sqlite3changegroup_change_null(sqlite3_changegroup*, int, int); + +/* +** CAPI3REF: Add an double to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). Except that +** it configures the change currently being constructed with a real value +** instead of a 64-bit integer. +*/ +SQLITE_API int sqlite3changegroup_change_double(sqlite3_changegroup*, int, int, double); + +/* +** CAPI3REF: Add a text value to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). It configures +** the currently accumulated change with a text value instead of a 64-bit +** integer. Parameter pVal points to a buffer containing the text encoded using +** utf-8. Parameter nVal may either be the size of the text value in bytes, or +** else a negative value, in which case the buffer pVal points to is assumed to +** be nul-terminated. +*/ +SQLITE_API int sqlite3changegroup_change_text( + sqlite3_changegroup*, int, int, const char *pVal, int nVal +); + +/* +** CAPI3REF: Add a blob to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). It configures +** the currently accumulated change with a blob value instead of a 64-bit +** integer. Parameter pVal points to a buffer containing the blob. Parameter +** nVal is the size of the blob in bytes. +*/ +SQLITE_API int sqlite3changegroup_change_blob( + sqlite3_changegroup*, int, int, const void *pVal, int nVal +); + +/* +** CAPI3REF: Finish adding one-at-at-time changes to a changegroup +** +** This function may only be called following a successful call to +** sqlite3changegroup_change_begin(). Otherwise, it is an SQLITE_MISUSE error. +** +** If parameter bDiscard is non-zero, then the current change is simply +** discarded. In this case this function is always successful and SQLITE_OK +** returned. +** +** If parameter bDiscard is zero, then an attempt is made to add the current +** change to the changegroup. Assuming the changegroup is configured to +** produce a changeset (not a patchset), this requires that: +** +** * If the change is an INSERT or DELETE, then a value must be specified +** for all columns of the new.* or old.* record, respectively. +** +** * If the change is an UPDATE record, then values must be provided for +** the PRIMARY KEY columns of the old.* record, but must not be provided +** for PRIMARY KEY columns of the new.* record. +** +** * If the change is an UPDATE record, then for each non-PRIMARY KEY +** column in the old.* record for which a value has been provided, a +** value must also be provided for the same column in the new.* record. +** Similarly, for each non-PK column in the old.* record for which +** a value is not provided, a value must not be provided for the same +** column in the new.* record. +** +** * All values specified for PRIMARY KEY columns must be non-NULL. +** +** Otherwise, it is an error. +** +** If the changegroup already contains a change for the same row (identified +** by PRIMARY KEY columns), then the current change is combined with the +** existing change in the same way as for sqlite3changegroup_add(). +** +** For a patchset, all of the above rules apply except that it doesn't matter +** whether or not values are provided for the non-PK old.* record columns +** for an UPDATE or DELETE change. This means that code used to produce +** a changeset using the sqlite3changegroup_change_xxx() APIs may also +** be used to produce patchsets. +** +** If the call is successful, SQLITE_OK is returned. Otherwise, if an error +** occurs, an SQLite error code is returned. If an error is returned and +** parameter pzErr is not NULL, then (*pzErr) may be set to point to a buffer +** containing a nul-terminated, utf-8 encoded, English language error message. +** It is the responsibility of the caller to eventually free any such error +** message buffer using sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_change_finish( + sqlite3_changegroup*, + int bDiscard, + char **pzErr +); + /* ** Make sure we can call this stuff from C++. */ @@ -13595,14 +14351,29 @@ struct Fts5PhraseIter { ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, ** output variable (*ppToken) is set to point to a buffer containing the ** matching document token, and (*pnToken) to the size of that buffer in -** bytes. This API is not available if the specified token matches a -** prefix query term. In that case both output variables are always set -** to 0. +** bytes. ** ** The output text is not a copy of the document text that was tokenized. ** It is the output of the tokenizer module. For tokendata=1 tables, this ** includes any embedded 0x00 and trailing data. ** +** This API may be slow in some cases if the token identified by parameters +** iIdx and iToken matched a prefix token in the query. In most cases, the +** first call to this API for each prefix token in the query is forced +** to scan the portion of the full-text index that matches the prefix +** token to collect the extra data required by this API. If the prefix +** token matches a large number of token instances in the document set, +** this may be a performance problem. +** +** If the user knows in advance that a query may use this API for a +** prefix token, FTS5 may be configured to collect all required data as part +** of the initial querying of the full-text index, avoiding the second scan +** entirely. This also causes prefix queries that do not use this API to +** run more slowly and use more memory. FTS5 may be configured in this way +** either on a per-table basis using the [FTS5 insttoken | 'insttoken'] +** option, or on a per-query basis using the +** [fts5_insttoken | fts5_insttoken()] user function. +** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. ** @@ -14036,6 +14807,21 @@ struct fts5_api { #endif /* _FTS5_H */ /******** End of fts5.h *********/ +#endif /* SQLITE3_H */ + +/* Function prototypes of SQLite3 Multiple Ciphers */ +SQLITE_PRIVATE int sqlite3mcCheckVfs(const char*); +SQLITE_PRIVATE int sqlite3mcFileControlPragma(sqlite3*, const char*, int, void*); +SQLITE_PRIVATE int sqlite3mcHandleAttachKey(sqlite3*, const char*, const char*, sqlite3_value*, char**); +SQLITE_PRIVATE int sqlite3mcHandleMainKey(sqlite3*, const char*); +typedef struct PgHdr PgHdrMC; +SQLITE_PRIVATE void* sqlite3mcPagerCodec(PgHdrMC* pPg); +typedef struct Pager PagerMC; +SQLITE_PRIVATE int sqlite3mcPagerHasCodec(PagerMC* pPager); +SQLITE_PRIVATE void sqlite3mcInitMemoryMethods(); +SQLITE_PRIVATE int sqlite3mcIsBackupSupported(sqlite3*, const char*, sqlite3*, const char*); +SQLITE_PRIVATE void sqlite3mcCodecGetKey(sqlite3* db, int nDb, void** zKey, int* nKey); +SQLITE_PRIVATE int sqlite3mc_builtin_extensions(sqlite3* db); /************** End of sqlite3.h *********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -14081,6 +14867,28 @@ struct fts5_api { #ifndef SQLITE_MAX_LENGTH # define SQLITE_MAX_LENGTH 1000000000 #endif +#define SQLITE_MIN_LENGTH 30 /* Minimum value for the length limit */ + +/* +** Maximum size of any single memory allocation. +** +** This is not a limit on the total amount of memory used. This is +** a limit on the size parameter to sqlite3_malloc() and sqlite3_realloc(). +** +** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391 +** This provides a 256-byte safety margin for defense against 32-bit +** signed integer overflow bugs when computing memory allocation sizes. +** Paranoid applications might want to reduce the maximum allocation size +** further for an even larger safety margin. 0x3fffffff or 0x0fffffff +** or even smaller would be reasonable upper bounds on the size of a memory +** allocations for most applications. +*/ +#ifndef SQLITE_MAX_ALLOCATION_SIZE +# define SQLITE_MAX_ALLOCATION_SIZE 2147483391 +#endif +#if SQLITE_MAX_ALLOCATION_SIZE>2147483391 +# error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391 +#endif /* ** This is the maximum number of @@ -14093,14 +14901,22 @@ struct fts5_api { ** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement. ** * Terms in the VALUES clause of an INSERT statement ** -** The hard upper limit here is 32676. Most database people will +** The hard upper limit here is 32767. Most database people will ** tell you that in a well-normalized database, you usually should ** not have more than a dozen or so columns in any table. And if ** that is the case, there is no point in having more than a few ** dozen values in any of the other situations described above. +** +** An index can only have SQLITE_MAX_COLUMN columns from the user +** point of view, but the underlying b-tree that implements the index +** might have up to twice as many columns in a WITHOUT ROWID table, +** since must also store the primary key at the end. Hence the +** column count for Index is u16 instead of i16. */ -#ifndef SQLITE_MAX_COLUMN +#if !defined(SQLITE_MAX_COLUMN) # define SQLITE_MAX_COLUMN 2000 +#elif SQLITE_MAX_COLUMN>32767 +# error SQLITE_MAX_COLUMN may not exceed 32767 #endif /* @@ -14109,21 +14925,42 @@ struct fts5_api { ** It used to be the case that setting this value to zero would ** turn the limit off. That is no longer true. It is not possible ** to turn this limit off. +** +** The hard limit is the largest possible 32-bit signed integer less +** 1024, or 2147482624. */ #ifndef SQLITE_MAX_SQL_LENGTH # define SQLITE_MAX_SQL_LENGTH 1000000000 #endif /* -** The maximum depth of an expression tree. This is limited to -** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might -** want to place more severe limits on the complexity of an -** expression. A value of 0 means that there is no limit. +** The maximum depth of an expression tree. The expression tree depth +** is also limited indirectly by SQLITE_MAX_SQL_LENGTH and by +** SQLITE_MAX_PARSER_DEPTH. Reducing the maximum complexity of +** expressions can help prevent excess memory usage by hostile SQL. +** +** A value of 0 for this compile-time option causes all expression +** depth limiting code to be omitted. */ #ifndef SQLITE_MAX_EXPR_DEPTH # define SQLITE_MAX_EXPR_DEPTH 1000 #endif +/* +** The maximum depth of the LALR(1) stack used in the parser that +** interprets SQL inputs. The parser stack depth can also be limited +** indirectly by SQLITE_MAX_SQL_LENGTH. Limiting the parser stack +** depth can help prevent excess memory usage and excess CPU stack +** usage when processing hostile SQL. +** +** Prior to version 3.45.0 (2024-01-15), the parser stack was +** hard-coded to 100 entries, and that worked fine for almost all +** applications. So the upper bound on this limit need not be large. +*/ +#ifndef SQLITE_MAX_PARSER_DEPTH +# define SQLITE_MAX_PARSER_DEPTH 2500 +#endif + /* ** The maximum number of terms in a compound SELECT statement. ** The code generator for compound SELECT statements does one @@ -14146,9 +14983,13 @@ struct fts5_api { /* ** The maximum number of arguments to an SQL function. +** +** This value has a hard upper limit of 32767 due to storage +** constraints (it needs to fit inside a i16). We keep it +** lower than that to prevent abuse. */ #ifndef SQLITE_MAX_FUNCTION_ARG -# define SQLITE_MAX_FUNCTION_ARG 127 +# define SQLITE_MAX_FUNCTION_ARG 1000 #endif /* @@ -14235,13 +15076,17 @@ struct fts5_api { # undef SQLITE_MAX_DEFAULT_PAGE_SIZE # define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE #endif +#if SQLITE_MAX_DEFAULT_PAGE_SIZE -#endif #ifdef HAVE_INTTYPES_H #include #endif @@ -14748,6 +15591,7 @@ struct HashElem { HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ const char *pKey; /* Key associated with this element */ + unsigned int h; /* hash for pKey */ }; /* @@ -14971,7 +15815,8 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_ERROR 182 #define TK_QNUMBER 183 #define TK_SPACE 184 -#define TK_ILLEGAL 185 +#define TK_COMMENT 185 +#define TK_ILLEGAL 186 /************** End of parse.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -15003,6 +15848,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); # define float sqlite_int64 # define fabs(X) ((X)<0?-(X):(X)) # define sqlite3IsOverflow(X) 0 +# define INFINITY (9223372036854775807LL) # ifndef SQLITE_BIG_DBL # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50) # endif @@ -15107,7 +15953,24 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); ** ourselves. */ #ifndef offsetof -#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD)) +# define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0)) +#endif + +/* +** sizeof64() is like sizeof(), but always returns a 64-bit value, even +** on 32-bit builds. This can help to avoid overflow by ensuring 64-bit +** arithmetic is used consistently in both 32-bit and 64-bit builds. +*/ +#define sizeof64(X) ((sqlite3_int64)sizeof(X)) + +/* +** Work around C99 "flex-array" syntax for pre-C99 compilers, so as +** to avoid complaints from -fsanitize=strict-bounds. +*/ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY +#else +# define FLEXARRAY 1 #endif /* @@ -15185,6 +16048,11 @@ typedef INT16_TYPE i16; /* 2-byte signed integer */ typedef UINT8_TYPE u8; /* 1-byte unsigned integer */ typedef INT8_TYPE i8; /* 1-byte signed integer */ +/* A bitfield type for use inside of structures. Always follow with :N where +** N is the number of bits. +*/ +typedef unsigned bft; /* Bit Field Type */ + /* ** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value ** that can be stored in a u32 without loss of data. The value @@ -15223,6 +16091,8 @@ typedef u64 tRowcnt; ** 0.5 -> -10 0.1 -> -33 0.0625 -> -40 */ typedef INT16_TYPE LogEst; +#define LOGEST_MIN (-32768) +#define LOGEST_MAX (32767) /* ** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer @@ -15351,6 +16221,14 @@ typedef INT16_TYPE LogEst; #define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) +/* +** Macro SMXV(n) return the maximum value that can be held in variable n, +** assuming n is a signed integer type. UMXV(n) is similar for unsigned +** integer types. +*/ +#define SMXV(n) ((((i64)1)<<(sizeof(n)*8-1))-1) +#define UMXV(n) ((((i64)1)<<(sizeof(n)*8))-1) + /* ** Round up a number to the next larger multiple of 8. This is used ** to force 8-byte alignment on 64-bit architectures. @@ -15387,6 +16265,7 @@ typedef INT16_TYPE LogEst; #else # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) #endif +#define TWO_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&1)==0) /* ** Disable MMAP on platforms where it is known to not work @@ -15470,6 +16349,8 @@ SQLITE_PRIVATE u32 sqlite3TreeTrace; ** 0x00020000 Transform DISTINCT into GROUP BY ** 0x00040000 SELECT tree dump after all code has been generated ** 0x00080000 NOT NULL strength reduction +** 0x00100000 Pointers are all shown as zero +** 0x00200000 EXISTS-to-JOIN optimization */ /* @@ -15493,7 +16374,7 @@ SQLITE_PRIVATE u32 sqlite3WhereTrace; ** 0xFFFF---- Low-level debug messages ** ** 0x00000001 Code generation -** 0x00000002 Solver +** 0x00000002 Solver (Use 0x40000 for less detail) ** 0x00000004 Solver costs ** 0x00000008 WhereLoop inserts ** @@ -15512,6 +16393,9 @@ SQLITE_PRIVATE u32 sqlite3WhereTrace; ** ** 0x00010000 Show more detail when printing WHERE terms ** 0x00020000 Show WHERE terms returned from whereScanNext() +** 0x00040000 Solver overview messages +** 0x00080000 Star-query heuristic +** 0x00100000 Pointers are all shown as zero */ @@ -15584,7 +16468,7 @@ struct BusyHandler { ** pointer will work here as long as it is distinct from SQLITE_STATIC ** and SQLITE_TRANSIENT. */ -#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomClear) +#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3RowSetClear) /* ** When SQLITE_OMIT_WSD is defined, it means that the target platform does @@ -15805,8 +16689,8 @@ typedef int VList; ** must provide its own VFS implementation together with sqlite3_os_init() ** and sqlite3_os_end() routines. */ -#if !defined(SQLITE_OS_KV) && !defined(SQLITE_OS_OTHER) && \ - !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_WIN) +#if SQLITE_OS_KV+1<=1 && SQLITE_OS_OTHER+1<=1 && \ + SQLITE_OS_WIN+1<=1 && SQLITE_OS_UNIX+1<=1 # if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \ defined(__MINGW32__) || defined(__BORLANDC__) # define SQLITE_OS_WIN 1 @@ -16150,6 +17034,22 @@ typedef struct PgHdr DbPage; #define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */ #define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */ +#define isWalMode(x) ((x)==PAGER_JOURNALMODE_WAL) + +/* +** The argument to this macro is a file descriptor (type sqlite3_file*). +** Return 0 if it is not open, or non-zero (but not 1) if it is. +** +** This is so that expressions can be written as: +** +** if( isOpen(pPager->jfd) ){ ... +** +** instead of +** +** if( pPager->jfd->pMethods ){ ... +*/ +#define isOpen(pFd) ((pFd)->pMethods!=0) + /* ** Flags that make up the mask passed to sqlite3PagerGet(). */ @@ -16424,7 +17324,7 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *); SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *); -SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *); +SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree*, Btree*); SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *); @@ -16636,6 +17536,7 @@ struct BtreePayload { SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int flags, int seekResult); SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); +SQLITE_PRIVATE int sqlite3BtreeIsEmpty(BtCursor *pCur, int *pRes); SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags); SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); @@ -16788,6 +17689,7 @@ typedef struct SubrtnSig SubrtnSig; */ struct SubrtnSig { int selId; /* SELECT-id for the SELECT statement on the RHS */ + u8 bComplete; /* True if fully coded and available for reusable */ char *zAff; /* Affinity of the overall IN expression */ int iTable; /* Ephemeral table generated by the subroutine */ int iAddr; /* Subroutine entry address */ @@ -16822,6 +17724,7 @@ struct VdbeOp { SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ Table *pTab; /* Used when p4type is P4_TABLE */ SubrtnSig *pSubrtnSig; /* Used when p4type is P4_SUBRTNSIG */ + Index *pIdx; /* Used when p4type is P4_INDEX */ #ifdef SQLITE_ENABLE_CURSOR_HINTS Expr *pExpr; /* Used when p4type is P4_EXPR */ #endif @@ -16876,20 +17779,21 @@ typedef struct VdbeOpList VdbeOpList; #define P4_INT32 (-3) /* P4 is a 32-bit signed integer */ #define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */ #define P4_TABLE (-5) /* P4 is a pointer to a Table structure */ +#define P4_INDEX (-6) /* P4 is a pointer to an Index structure */ /* Above do not own any resources. Must free those below */ -#define P4_FREE_IF_LE (-6) -#define P4_DYNAMIC (-6) /* Pointer to memory from sqliteMalloc() */ -#define P4_FUNCDEF (-7) /* P4 is a pointer to a FuncDef structure */ -#define P4_KEYINFO (-8) /* P4 is a pointer to a KeyInfo structure */ -#define P4_EXPR (-9) /* P4 is a pointer to an Expr tree */ -#define P4_MEM (-10) /* P4 is a pointer to a Mem* structure */ -#define P4_VTAB (-11) /* P4 is a pointer to an sqlite3_vtab structure */ -#define P4_REAL (-12) /* P4 is a 64-bit floating point value */ -#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ -#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */ -#define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */ -#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */ -#define P4_SUBRTNSIG (-17) /* P4 is a SubrtnSig pointer */ +#define P4_FREE_IF_LE (-7) +#define P4_DYNAMIC (-7) /* Pointer to memory from sqliteMalloc() */ +#define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */ +#define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */ +#define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */ +#define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */ +#define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */ +#define P4_REAL (-13) /* P4 is a 64-bit floating point value */ +#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */ +#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ +#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ +#define P4_TABLEREF (-17) /* Like P4_TABLE, but reference counted */ +#define P4_SUBRTNSIG (-18) /* P4 is a SubrtnSig pointer */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 @@ -16968,20 +17872,20 @@ typedef struct VdbeOpList VdbeOpList; #define OP_SorterSort 34 /* jump */ #define OP_Sort 35 /* jump */ #define OP_Rewind 36 /* jump0 */ -#define OP_SorterNext 37 /* jump */ -#define OP_Prev 38 /* jump */ -#define OP_Next 39 /* jump */ -#define OP_IdxLE 40 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IdxGT 41 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IdxLT 42 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IfEmpty 37 /* jump, synopsis: if( empty(P1) ) goto P2 */ +#define OP_SorterNext 38 /* jump */ +#define OP_Prev 39 /* jump */ +#define OP_Next 40 /* jump */ +#define OP_IdxLE 41 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGT 42 /* jump, synopsis: key=r[P3@P4] */ #define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ -#define OP_IdxGE 45 /* jump, synopsis: key=r[P3@P4] */ -#define OP_RowSetRead 46 /* jump, synopsis: r[P3]=rowset(P1) */ -#define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ -#define OP_Program 48 /* jump0 */ -#define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ -#define OP_IfPos 50 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ +#define OP_IdxLT 45 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGE 46 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IFindKey 47 /* jump */ +#define OP_RowSetRead 48 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_RowSetTest 49 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ +#define OP_Program 50 /* jump0 */ #define OP_IsNull 51 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 52 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 53 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ @@ -16991,49 +17895,49 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Lt 57 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */ #define OP_ElseEq 59 /* jump, same as TK_ESCAPE */ -#define OP_IfNotZero 60 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ -#define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */ -#define OP_IncrVacuum 62 /* jump */ -#define OP_VNext 63 /* jump */ -#define OP_Filter 64 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ -#define OP_PureFunc 65 /* synopsis: r[P3]=func(r[P2@NP]) */ -#define OP_Function 66 /* synopsis: r[P3]=func(r[P2@NP]) */ -#define OP_Return 67 -#define OP_EndCoroutine 68 -#define OP_HaltIfNull 69 /* synopsis: if r[P3]=null halt */ -#define OP_Halt 70 -#define OP_Integer 71 /* synopsis: r[P2]=P1 */ -#define OP_Int64 72 /* synopsis: r[P2]=P4 */ -#define OP_String 73 /* synopsis: r[P2]='P4' (len=P1) */ -#define OP_BeginSubrtn 74 /* synopsis: r[P2]=NULL */ -#define OP_Null 75 /* synopsis: r[P2..P3]=NULL */ -#define OP_SoftNull 76 /* synopsis: r[P1]=NULL */ -#define OP_Blob 77 /* synopsis: r[P2]=P4 (len=P1) */ -#define OP_Variable 78 /* synopsis: r[P2]=parameter(P1) */ -#define OP_Move 79 /* synopsis: r[P2@P3]=r[P1@P3] */ -#define OP_Copy 80 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ -#define OP_SCopy 81 /* synopsis: r[P2]=r[P1] */ -#define OP_IntCopy 82 /* synopsis: r[P2]=r[P1] */ -#define OP_FkCheck 83 -#define OP_ResultRow 84 /* synopsis: output=r[P1@P2] */ -#define OP_CollSeq 85 -#define OP_AddImm 86 /* synopsis: r[P1]=r[P1]+P2 */ -#define OP_RealAffinity 87 -#define OP_Cast 88 /* synopsis: affinity(r[P1]) */ -#define OP_Permutation 89 -#define OP_Compare 90 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_IsTrue 91 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ -#define OP_ZeroOrNull 92 /* synopsis: r[P2] = 0 OR NULL */ -#define OP_Offset 93 /* synopsis: r[P3] = sqlite_offset(P1) */ -#define OP_Column 94 /* synopsis: r[P3]=PX cursor P1 column P2 */ -#define OP_TypeCheck 95 /* synopsis: typecheck(r[P1@P2]) */ -#define OP_Affinity 96 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 97 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_Count 98 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 99 -#define OP_SetCookie 100 -#define OP_ReopenIdx 101 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenRead 102 /* synopsis: root=P2 iDb=P3 */ +#define OP_FkIfZero 60 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_IfPos 61 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ +#define OP_IfNotZero 62 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ +#define OP_DecrJumpZero 63 /* jump, synopsis: if (--r[P1])==0 goto P2 */ +#define OP_IncrVacuum 64 /* jump */ +#define OP_VNext 65 /* jump */ +#define OP_Filter 66 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ +#define OP_PureFunc 67 /* synopsis: r[P3]=func(r[P2@NP]) */ +#define OP_Function 68 /* synopsis: r[P3]=func(r[P2@NP]) */ +#define OP_Return 69 +#define OP_EndCoroutine 70 +#define OP_HaltIfNull 71 /* synopsis: if r[P3]=null halt */ +#define OP_Halt 72 +#define OP_Integer 73 /* synopsis: r[P2]=P1 */ +#define OP_Int64 74 /* synopsis: r[P2]=P4 */ +#define OP_String 75 /* synopsis: r[P2]='P4' (len=P1) */ +#define OP_BeginSubrtn 76 /* synopsis: r[P2]=NULL */ +#define OP_Null 77 /* synopsis: r[P2..P3]=NULL */ +#define OP_SoftNull 78 /* synopsis: r[P1]=NULL */ +#define OP_Blob 79 /* synopsis: r[P2]=P4 (len=P1) */ +#define OP_Variable 80 /* synopsis: r[P2]=parameter(P1) */ +#define OP_Move 81 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 82 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ +#define OP_SCopy 83 /* synopsis: r[P2]=r[P1] */ +#define OP_IntCopy 84 /* synopsis: r[P2]=r[P1] */ +#define OP_FkCheck 85 +#define OP_ResultRow 86 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 87 +#define OP_AddImm 88 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 89 +#define OP_Cast 90 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 91 +#define OP_Compare 92 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_IsTrue 93 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ +#define OP_ZeroOrNull 94 /* synopsis: r[P2] = 0 OR NULL */ +#define OP_Offset 95 /* synopsis: r[P3] = sqlite_offset(P1) */ +#define OP_Column 96 /* synopsis: r[P3]=PX cursor P1 column P2 */ +#define OP_TypeCheck 97 /* synopsis: typecheck(r[P1@P2]) */ +#define OP_Affinity 98 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 99 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 100 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 101 +#define OP_SetCookie 102 #define OP_BitAnd 103 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ #define OP_BitOr 104 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ #define OP_ShiftLeft 105 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggInverse 161 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ -#define OP_AggStep 162 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep1 163 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggValue 164 /* synopsis: r[P3]=value N=P2 */ -#define OP_AggFinal 165 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 166 -#define OP_CursorLock 167 -#define OP_CursorUnlock 168 -#define OP_TableLock 169 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 170 -#define OP_VCreate 171 -#define OP_VDestroy 172 -#define OP_VOpen 173 -#define OP_VCheck 174 -#define OP_VInitIn 175 /* synopsis: r[P2]=ValueList(P1,P3) */ -#define OP_VColumn 176 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 177 -#define OP_Pagecount 178 -#define OP_MaxPgcnt 179 -#define OP_ClrSubtype 180 /* synopsis: r[P1].subtype = 0 */ -#define OP_GetSubtype 181 /* synopsis: r[P2] = r[P1].subtype */ -#define OP_SetSubtype 182 /* synopsis: r[P2].subtype = r[P1] */ -#define OP_FilterAdd 183 /* synopsis: filter(P1) += key(P3@P4) */ -#define OP_Trace 184 -#define OP_CursorHint 185 -#define OP_ReleaseReg 186 /* synopsis: release r[P1@P2] mask P3 */ -#define OP_Noop 187 -#define OP_Explain 188 -#define OP_Abortable 189 +#define OP_DropIndex 155 +#define OP_DropTrigger 156 +#define OP_IntegrityCk 157 +#define OP_RowSetAdd 158 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 159 +#define OP_FkCounter 160 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 161 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 162 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggInverse 163 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ +#define OP_AggStep 164 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep1 165 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggValue 166 /* synopsis: r[P3]=value N=P2 */ +#define OP_AggFinal 167 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 168 +#define OP_CursorLock 169 +#define OP_CursorUnlock 170 +#define OP_TableLock 171 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 172 +#define OP_VCreate 173 +#define OP_VDestroy 174 +#define OP_VOpen 175 +#define OP_VCheck 176 +#define OP_VInitIn 177 /* synopsis: r[P2]=ValueList(P1,P3) */ +#define OP_VColumn 178 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 179 +#define OP_Pagecount 180 +#define OP_MaxPgcnt 181 +#define OP_ClrSubtype 182 /* synopsis: r[P1].subtype = 0 */ +#define OP_GetSubtype 183 /* synopsis: r[P2] = r[P1].subtype */ +#define OP_SetSubtype 184 /* synopsis: r[P2].subtype = r[P1] */ +#define OP_FilterAdd 185 /* synopsis: filter(P1) += key(P3@P4) */ +#define OP_Trace 186 +#define OP_CursorHint 187 +#define OP_ReleaseReg 188 /* synopsis: release r[P1@P2] mask P3 */ +#define OP_Noop 189 +#define OP_Explain 190 +#define OP_Abortable 191 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -17139,26 +18045,27 @@ typedef struct VdbeOpList VdbeOpList; /* 8 */ 0x81, 0x01, 0x01, 0x81, 0x83, 0x83, 0x01, 0x01,\ /* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0xc9, 0xc9, 0xc9,\ /* 24 */ 0xc9, 0x01, 0x49, 0x49, 0x49, 0x49, 0xc9, 0x49,\ -/* 32 */ 0xc1, 0x01, 0x41, 0x41, 0xc1, 0x01, 0x41, 0x41,\ -/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x23, 0x0b,\ -/* 48 */ 0x81, 0x01, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\ -/* 56 */ 0x0b, 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x01, 0x41,\ -/* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\ -/* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\ -/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\ -/* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40, 0x00,\ -/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x40, 0x26,\ +/* 32 */ 0xc1, 0x01, 0x41, 0x41, 0xc1, 0x01, 0x01, 0x41,\ +/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x41, 0x09,\ +/* 48 */ 0x23, 0x0b, 0x81, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\ +/* 56 */ 0x0b, 0x0b, 0x0b, 0x01, 0x01, 0x03, 0x03, 0x03,\ +/* 64 */ 0x01, 0x41, 0x01, 0x00, 0x00, 0x02, 0x02, 0x08,\ +/* 72 */ 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10,\ +/* 80 */ 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,\ +/* 88 */ 0x02, 0x02, 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20,\ +/* 96 */ 0x40, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x26,\ /* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\ -/* 112 */ 0x26, 0x00, 0x40, 0x12, 0x40, 0x40, 0x10, 0x00,\ -/* 120 */ 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10, 0x10,\ -/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50,\ -/* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\ -/* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ -/* 152 */ 0x00, 0x00, 0x10, 0x00, 0x06, 0x10, 0x00, 0x04,\ -/* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x50,\ -/* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12, 0x00,\ -/* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,} +/* 112 */ 0x26, 0x40, 0x40, 0x12, 0x00, 0x40, 0x10, 0x40,\ +/* 120 */ 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40,\ +/* 128 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,\ +/* 136 */ 0x00, 0x50, 0x00, 0x40, 0x04, 0x04, 0x00, 0x40,\ +/* 144 */ 0x50, 0x40, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00,\ +/* 152 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x10,\ +/* 160 */ 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,\ +/* 176 */ 0x10, 0x50, 0x40, 0x00, 0x10, 0x10, 0x02, 0x12,\ +/* 184 */ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +} /* The resolve3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum @@ -17166,7 +18073,7 @@ typedef struct VdbeOpList VdbeOpList; ** generated this include file strives to group all JUMP opcodes ** together near the beginning of the list. */ -#define SQLITE_MX_JUMP_OPCODE 64 /* Maximum JUMP opcode */ +#define SQLITE_MX_JUMP_OPCODE 66 /* Maximum JUMP opcode */ /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ @@ -17175,7 +18082,7 @@ typedef struct VdbeOpList VdbeOpList; ** Additional non-public SQLITE_PREPARE_* flags */ #define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */ -#define SQLITE_PREPARE_MASK 0x0f /* Mask of public flags */ +#define SQLITE_PREPARE_MASK 0x3f /* Mask of public flags */ /* ** Prototypes for the VDBE interface. See comments on the implementation @@ -17289,8 +18196,11 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); SQLITE_PRIVATE int sqlite3BlobCompare(const Mem*, const Mem*); +#ifdef SQLITE_ENABLE_PERCENTILE +SQLITE_PRIVATE const char *sqlite3VdbeFuncName(const sqlite3_context*); +#endif -SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); +SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(int,const void*,UnpackedRecord*); SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int); SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*); @@ -17303,13 +18213,15 @@ SQLITE_PRIVATE int sqlite3VdbeHasSubProgram(Vdbe*); SQLITE_PRIVATE void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val); +#ifndef SQLITE_OMIT_DATETIME_FUNCS SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*); +#endif #ifdef SQLITE_ENABLE_BYTECODE_VTAB SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*); #endif -/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on -** each VDBE opcode. +/* Use SQLITE_ENABLE_EXPLAIN_COMMENTS to enable generation of extra +** comments on each VDBE opcode. ** ** Use the SQLITE_ENABLE_MODULE_COMMENTS macro to see some extra no-op ** comments in VDBE programs that show key decision points in the code @@ -17452,10 +18364,10 @@ struct PgHdr { PCache *pCache; /* PRIVATE: Cache that owns this page */ PgHdr *pDirty; /* Transient list of dirty sorted by pgno */ Pager *pPager; /* The pager this page is part of */ - Pgno pgno; /* Page number for this page */ #ifdef SQLITE_CHECK_PAGES - u32 pageHash; /* Hash of page content */ + u64 pageHash; /* Hash of page content */ #endif + Pgno pgno; /* Page number for this page */ u16 flags; /* PGHDR flags defined below */ /********************************************************************** @@ -17795,7 +18707,7 @@ struct Schema { ** The number of different kinds of things that can be limited ** using the sqlite3_limit() interface. */ -#define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1) +#define SQLITE_N_LIMIT (SQLITE_LIMIT_PARSER_DEPTH+1) /* ** Lookaside malloc is a set of fixed-size buffers that can be used @@ -17890,46 +18802,11 @@ struct FuncDefHash { }; #define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ) -#if defined(SQLITE_USER_AUTHENTICATION) -#pragma message("The SQLITE_USER_AUTHENTICATION extension is deprecated. See ext/userauth/user-auth.txt for details.") -#endif -#ifdef SQLITE_USER_AUTHENTICATION -/* -** Information held in the "sqlite3" database connection object and used -** to manage user authentication. -*/ -typedef struct sqlite3_userauth sqlite3_userauth; -struct sqlite3_userauth { - u8 authLevel; /* Current authentication level */ - int nAuthPW; /* Size of the zAuthPW in bytes */ - char *zAuthPW; /* Password used to authenticate */ - char *zAuthUser; /* User name used to authenticate */ -}; - -/* Allowed values for sqlite3_userauth.authLevel */ -#define UAUTH_Unknown 0 /* Authentication not yet checked */ -#define UAUTH_Fail 1 /* User authentication failed */ -#define UAUTH_User 2 /* Authenticated as a normal user */ -#define UAUTH_Admin 3 /* Authenticated as an administrator */ - -/* Functions used only by user authorization logic */ -SQLITE_PRIVATE int sqlite3UserAuthTable(const char*); -SQLITE_PRIVATE int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*); -SQLITE_PRIVATE void sqlite3UserAuthInit(sqlite3*); -SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); - -#endif /* SQLITE_USER_AUTHENTICATION */ - /* ** typedef for the authorization callback function. */ -#ifdef SQLITE_USER_AUTHENTICATION - typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, - const char*, const char*); -#else - typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, - const char*); -#endif +typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, + const char*); #ifndef SQLITE_OMIT_DEPRECATED /* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing @@ -17984,6 +18861,7 @@ struct sqlite3 { u8 noSharedCache; /* True if no shared-cache backends */ u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */ u8 eOpenState; /* Current condition of the connection */ + u8 nFpDigit; /* Significant digits to keep on double->text */ int nextPagesize; /* Pagesize after VACUUM if >0 */ i64 nChange; /* Value returned by sqlite3_changes() */ i64 nTotalChange; /* Value returned by sqlite3_total_changes() */ @@ -17994,7 +18872,7 @@ struct sqlite3 { u8 iDb; /* Which db file is being initialized */ u8 busy; /* TRUE if currently initializing */ unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */ - unsigned imposterTable : 1; /* Building an imposter table */ + unsigned imposterTable : 2; /* Building an imposter table */ unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */ const char **azInit; /* "type", "name", and "tbl_name" columns */ } init; @@ -18067,12 +18945,17 @@ struct sqlite3 { Savepoint *pSavepoint; /* List of active savepoints */ int nAnalysisLimit; /* Number of index rows to ANALYZE */ int busyTimeout; /* Busy handler timeout, in msec */ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + int setlkTimeout; /* Blocking lock timeout, in msec. -1 -> inf. */ + int setlkFlags; /* Flags passed to setlk_timeout() */ +#endif int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ DbClientData *pDbData; /* sqlite3_set_clientdata() content */ + u64 nSpill; /* TEMP content spilled to disk */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MAIN ** mutex, not by sqlite3.mutex. They are used by code in notify.c. @@ -18090,9 +18973,6 @@ struct sqlite3 { void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif -#ifdef SQLITE_USER_AUTHENTICATION - sqlite3_userauth auth; /* User authentication information */ -#endif }; /* @@ -18156,6 +19036,9 @@ struct sqlite3 { #define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */ #define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */ #define SQLITE_FkNoAction HI(0x00008) /* Treat all FK as NO ACTION */ +#define SQLITE_AttachCreate HI(0x00010) /* ATTACH allowed to create new dbs */ +#define SQLITE_AttachWrite HI(0x00020) /* ATTACH allowed to open for write */ +#define SQLITE_Comments HI(0x00040) /* Enable SQL comments */ /* Flags used only if debugging */ #ifdef SQLITE_DEBUG @@ -18215,6 +19098,8 @@ struct sqlite3 { #define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */ #define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */ #define SQLITE_OrderBySubq 0x10000000 /* ORDER BY in subquery helps outer */ +#define SQLITE_StarQuery 0x20000000 /* Heurists for star queries */ +#define SQLITE_ExistsToJoin 0x40000000 /* The EXISTS-to-JOIN optimization */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* @@ -18251,7 +19136,7 @@ struct sqlite3 { ** field is used by per-connection app-def functions. */ struct FuncDef { - i8 nArg; /* Number of arguments. -1 means unlimited */ + i16 nArg; /* Number of arguments. -1 means unlimited */ u32 funcFlags; /* Some combination of SQLITE_FUNC_* */ void *pUserData; /* User data parameter */ FuncDef *pNext; /* Next function with same name */ @@ -18453,7 +19338,7 @@ struct FuncDestructor { #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - pArg, 0, xFunc, 0, 0, 0, #zName, } + pArg, 0, xFunc, 0, 0, 0, #zName, {0} } #define LIKEFUNC(zName, nArg, arg, flags) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} } @@ -18620,6 +19505,7 @@ struct CollSeq { #define SQLITE_AFF_INTEGER 0x44 /* 'D' */ #define SQLITE_AFF_REAL 0x45 /* 'E' */ #define SQLITE_AFF_FLEXNUM 0x46 /* 'F' */ +#define SQLITE_AFF_DEFER 0x58 /* 'X' - defer computation until later */ #define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) @@ -18744,6 +19630,7 @@ struct Table { } u; Trigger *pTrigger; /* List of triggers on this object */ Schema *pSchema; /* Schema that contains this table */ + u8 aHx[16]; /* Column aHt[K%sizeof(aHt)] might have hash K */ }; /* @@ -18779,6 +19666,7 @@ struct Table { #define TF_Ephemeral 0x00004000 /* An ephemeral table */ #define TF_Eponymous 0x00008000 /* An eponymous virtual table */ #define TF_Strict 0x00010000 /* STRICT mode */ +#define TF_Imposter 0x00020000 /* An imposter table */ /* ** Allowed values for Table.eTabType @@ -18877,9 +19765,13 @@ struct FKey { struct sColMap { /* Mapping of columns in pFrom to columns in zTo */ int iFrom; /* Index of column in pFrom */ char *zCol; /* Name of column in zTo. If NULL use PRIMARY KEY */ - } aCol[1]; /* One entry for each of nCol columns */ + } aCol[FLEXARRAY]; /* One entry for each of nCol columns */ }; +/* The size (in bytes) of an FKey object holding N columns. The answer +** does NOT include space to hold the zTo name. */ +#define SZ_FKEY(N) (offsetof(FKey,aCol)+(N)*sizeof(struct sColMap)) + /* ** SQLite supports many different ways to resolve a constraint ** error. ROLLBACK processing means that a constraint violation @@ -18930,9 +19822,15 @@ struct FKey { ** argument to sqlite3VdbeKeyCompare and is used to control the ** comparison of the two index keys. ** -** Note that aSortOrder[] and aColl[] have nField+1 slots. There -** are nField slots for the columns of an index then one extra slot -** for the rowid at the end. +** The aSortOrder[] and aColl[] arrays have nAllField slots each. There +** are nKeyField slots for the columns of an index then extra slots +** for the rowid or key at the end. The aSortOrder array is located after +** the aColl[] array. +** +** If SQLITE_ENABLE_PREUPDATE_HOOK is defined, then aSortFlags might be NULL +** to indicate that this object is for use by a preupdate hook. When aSortFlags +** is NULL, then nAllField is uninitialized and no space is allocated for +** aColl[], so those fields may not be used. */ struct KeyInfo { u32 nRef; /* Number of references to this KeyInfo object */ @@ -18941,9 +19839,21 @@ struct KeyInfo { u16 nAllField; /* Total columns, including key plus others */ sqlite3 *db; /* The database connection */ u8 *aSortFlags; /* Sort order for each column. */ - CollSeq *aColl[1]; /* Collating sequence for each term of the key */ + CollSeq *aColl[FLEXARRAY]; /* Collating sequence for each term of the key */ }; +/* The size (in bytes) of a KeyInfo object with up to N fields. This includes +** the main body of the KeyInfo object and the aColl[] array of N elements, +** but does not count the memory used to hold aSortFlags[]. */ +#define SZ_KEYINFO(N) (offsetof(KeyInfo,aColl) + (N)*sizeof(CollSeq*)) + +/* The size of a bare KeyInfo with no aColl[] entries */ +#if FLEXARRAY+1 > 1 +# define SZ_KEYINFO_0 offsetof(KeyInfo,aColl) +#else +# define SZ_KEYINFO_0 sizeof(KeyInfo) +#endif + /* ** Allowed bit values for entries in the KeyInfo.aSortFlags[] array. */ @@ -18962,9 +19872,8 @@ struct KeyInfo { ** ** An instance of this object serves as a "key" for doing a search on ** an index b+tree. The goal of the search is to find the entry that -** is closed to the key described by this object. This object might hold -** just a prefix of the key. The number of fields is given by -** pKeyInfo->nField. +** is closest to the key described by this object. This object might hold +** just a prefix of the key. The number of fields is given by nField. ** ** The r1 and r2 fields are the values to return if this key is less than ** or greater than a key in the btree, respectively. These are normally @@ -18974,7 +19883,7 @@ struct KeyInfo { ** The key comparison functions actually return default_rc when they find ** an equals comparison. default_rc can be -1, 0, or +1. If there are ** multiple entries in the b-tree with the same key (when only looking -** at the first pKeyInfo->nFields,) then default_rc can be set to -1 to +** at the first nField elements) then default_rc can be set to -1 to ** cause the search to find the last match, or +1 to cause the search to ** find the first match. ** @@ -18986,8 +19895,8 @@ struct KeyInfo { ** b-tree. */ struct UnpackedRecord { - KeyInfo *pKeyInfo; /* Collation and sort-order information */ - Mem *aMem; /* Values */ + KeyInfo *pKeyInfo; /* Comparison info for the index that is unpacked */ + Mem *aMem; /* Values for columns of the index */ union { char *z; /* Cache of aMem[0].z for vdbeRecordCompareString() */ i64 i; /* Cache of aMem[0].u.i for vdbeRecordCompareInt() */ @@ -19063,7 +19972,7 @@ struct Index { Pgno tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ - u16 nColumn; /* Number of columns stored in the index */ + u16 nColumn; /* Nr columns in btree. Can be 2*Table.nCol */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ @@ -19072,7 +19981,6 @@ struct Index { unsigned isCovering:1; /* True if this is a covering index */ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ - unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */ unsigned bNoQuery:1; /* Do not use this index to optimize queries */ unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ @@ -19162,7 +20070,7 @@ struct AggInfo { ** from source tables rather than from accumulators */ u8 useSortingIdx; /* In direct mode, reference the sorting index rather ** than the source table */ - u16 nSortingColumn; /* Number of columns in the sorting index */ + u32 nSortingColumn; /* Number of columns in the sorting index */ int sortingIdx; /* Cursor number of the sorting index */ int sortingIdxPTab; /* Cursor number of pseudo-table */ int iFirstReg; /* First register in range for aCol[] and aFunc[] */ @@ -19171,8 +20079,8 @@ struct AggInfo { Table *pTab; /* Source table */ Expr *pCExpr; /* The original expression */ int iTable; /* Cursor number of the source table */ - i16 iColumn; /* Column number within the source table */ - i16 iSorterColumn; /* Column number in the sorting index */ + int iColumn; /* Column number within the source table */ + int iSorterColumn; /* Column number in the sorting index */ } *aCol; int nColumn; /* Number of used entries in aCol[] */ int nAccumulator; /* Number of columns that show through to the output. @@ -19347,6 +20255,7 @@ struct Expr { Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL ** for a column of an index on an expression */ Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */ + int nReg; /* TK_NULLS: Number of registers to NULL out */ struct { /* TK_IN, TK_SELECT, and TK_EXISTS */ int iAddr; /* Subroutine entry address */ int regReturn; /* Register used to hold return address */ @@ -19401,10 +20310,10 @@ struct Expr { /* Macros can be used to test, set, or clear bits in the ** Expr.flags field. */ -#define ExprHasProperty(E,P) (((E)->flags&(P))!=0) -#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) -#define ExprSetProperty(E,P) (E)->flags|=(P) -#define ExprClearProperty(E,P) (E)->flags&=~(P) +#define ExprHasProperty(E,P) (((E)->flags&(u32)(P))!=0) +#define ExprHasAllProperty(E,P) (((E)->flags&(u32)(P))==(u32)(P)) +#define ExprSetProperty(E,P) (E)->flags|=(u32)(P) +#define ExprClearProperty(E,P) (E)->flags&=~(u32)(P) #define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue) #define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse) #define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0) @@ -19516,9 +20425,14 @@ struct ExprList { int iConstExprReg; /* Register in which Expr value is cached. Used only ** by Parse.pConstExpr */ } u; - } a[1]; /* One slot for each expression in the list */ + } a[FLEXARRAY]; /* One slot for each expression in the list */ }; +/* The size (in bytes) of an ExprList object that is big enough to hold +** as many as N expressions. */ +#define SZ_EXPRLIST(N) \ + (offsetof(ExprList,a) + (N)*sizeof(struct ExprList_item)) + /* ** Allowed values for Expr.a.eEName */ @@ -19544,16 +20458,14 @@ struct ExprList { */ struct IdList { int nId; /* Number of identifiers on the list */ - u8 eU4; /* Which element of a.u4 is valid */ struct IdList_item { char *zName; /* Name of the identifier */ - union { - int idx; /* Index in some Table.aCol[] of a column named zName */ - Expr *pExpr; /* Expr to implement a USING variable -- NOT USED */ - } u4; - } a[1]; + } a[FLEXARRAY]; }; +/* The size (in bytes) of an IdList object that can hold up to N IDs. */ +#define SZ_IDLIST(N) (offsetof(IdList,a)+(N)*sizeof(struct IdList_item)) + /* ** Allowed values for IdList.eType, which determines which value of the a.u4 ** is valid. @@ -19633,6 +20545,7 @@ struct SrcItem { unsigned rowidUsed :1; /* The ROWID of this table is referenced */ unsigned fixedSchema :1; /* Uses u4.pSchema, not u4.zDatabase */ unsigned hadSchema :1; /* Had u4.zDatabase before u4.pSchema */ + unsigned fromExists :1; /* Comes from WHERE EXISTS(...) */ } fg; int iCursor; /* The VDBE cursor number used to access this table */ Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */ @@ -19673,11 +20586,19 @@ struct OnOrUsing { ** */ struct SrcList { - int nSrc; /* Number of tables or subqueries in the FROM clause */ - u32 nAlloc; /* Number of entries allocated in a[] below */ - SrcItem a[1]; /* One entry for each identifier on the list */ + int nSrc; /* Number of tables or subqueries in the FROM clause */ + u32 nAlloc; /* Number of entries allocated in a[] below */ + SrcItem a[FLEXARRAY]; /* One entry for each identifier on the list */ }; +/* Size (in bytes) of a SrcList object that can hold as many as N +** SrcItem objects. */ +#define SZ_SRCLIST(N) (offsetof(SrcList,a)+(N)*sizeof(SrcItem)) + +/* Size (in bytes( of a SrcList object that holds 1 SrcItem. This is a +** special case of SZ_SRCITEM(1) that comes up often. */ +#define SZ_SRCLIST_1 (offsetof(SrcList,a)+sizeof(SrcItem)) + /* ** Permitted values of the SrcList.a.jointype field */ @@ -19835,19 +20756,6 @@ struct Upsert { /* ** An instance of the following structure contains all information ** needed to generate code for a single SELECT statement. -** -** See the header comment on the computeLimitRegisters() routine for a -** detailed description of the meaning of the iLimit and iOffset fields. -** -** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes. -** These addresses must be stored so that we can go back and fill in -** the P4_KEYINFO and P2 parameters later. Neither the KeyInfo nor -** the number of columns in P2 can be computed at the same time -** as the OP_OpenEphm instruction is coded because not -** enough information about the compound query is known at that point. -** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences -** for the result set. The KeyInfo for addrOpenEphm[2] contains collating -** sequences for the ORDER BY clause. */ struct Select { u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ @@ -19855,7 +20763,6 @@ struct Select { u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ u32 selId; /* Unique identifier number for this SELECT */ - int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ ExprList *pEList; /* The fields of the result */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ @@ -19887,7 +20794,7 @@ struct Select { #define SF_Resolved 0x0000004 /* Identifiers have been resolved */ #define SF_Aggregate 0x0000008 /* Contains agg functions or a GROUP BY */ #define SF_HasAgg 0x0000010 /* Contains aggregate functions */ -#define SF_UsesEphemeral 0x0000020 /* Uses the OpenEphemeral opcode */ +#define SF_ClonedRhsIn 0x0000020 /* Cloned RHS of an IN operator */ #define SF_Expanded 0x0000040 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0000080 /* FROM subqueries have Table metadata */ #define SF_Compound 0x0000100 /* Part of a compound query */ @@ -19897,14 +20804,14 @@ struct Select { #define SF_MinMaxAgg 0x0001000 /* Aggregate containing min() or max() */ #define SF_Recursive 0x0002000 /* The recursive part of a recursive CTE */ #define SF_FixedLimit 0x0004000 /* nSelectRow set by a constant LIMIT */ -#define SF_MaybeConvert 0x0008000 /* Need convertCompoundSelectToSubquery() */ +/* 0x0008000 // available for reuse */ #define SF_Converted 0x0010000 /* By convertCompoundSelectToSubquery() */ #define SF_IncludeHidden 0x0020000 /* Include hidden columns in output */ #define SF_ComplexResult 0x0040000 /* Result contains subquery or function */ #define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */ #define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */ #define SF_View 0x0200000 /* SELECT statement is a view */ -#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */ +/* 0x0400000 // available for reuse */ #define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */ #define SF_PushDown 0x1000000 /* Modified by WHERE-clause push-down opt */ #define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */ @@ -19912,6 +20819,7 @@ struct Select { #define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */ #define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */ #define SF_Correlated 0x20000000 /* True if references the outer context */ +#define SF_OnToWhere 0x40000000 /* One or more ON clauses moved to WHERE */ /* True if SrcItem X is a subquery that has SF_NestedFrom */ #define IsNestedFrom(X) \ @@ -19923,11 +20831,6 @@ struct Select { ** by one of the following macros. The "SRT" prefix means "SELECT Result ** Type". ** -** SRT_Union Store results as a key in a temporary index -** identified by pDest->iSDParm. -** -** SRT_Except Remove results from the temporary index pDest->iSDParm. -** ** SRT_Exists Store a 1 in memory cell pDest->iSDParm if the result ** set is not empty. ** @@ -19991,30 +20894,28 @@ struct Select { ** table. (pDest->iSDParm) is the number of key columns in ** each index record in this case. */ -#define SRT_Union 1 /* Store result as keys in an index */ -#define SRT_Except 2 /* Remove result from a UNION index */ -#define SRT_Exists 3 /* Store 1 if the result is not empty */ -#define SRT_Discard 4 /* Do not save the results anywhere */ -#define SRT_DistFifo 5 /* Like SRT_Fifo, but unique results only */ -#define SRT_DistQueue 6 /* Like SRT_Queue, but unique results only */ +#define SRT_Exists 1 /* Store 1 if the result is not empty */ +#define SRT_Discard 2 /* Do not save the results anywhere */ +#define SRT_DistFifo 3 /* Like SRT_Fifo, but unique results only */ +#define SRT_DistQueue 4 /* Like SRT_Queue, but unique results only */ /* The DISTINCT clause is ignored for all of the above. Not that ** IgnorableDistinct() implies IgnorableOrderby() */ #define IgnorableDistinct(X) ((X->eDest)<=SRT_DistQueue) -#define SRT_Queue 7 /* Store result in an queue */ -#define SRT_Fifo 8 /* Store result as data with an automatic rowid */ +#define SRT_Queue 5 /* Store result in an queue */ +#define SRT_Fifo 6 /* Store result as data with an automatic rowid */ /* The ORDER BY clause is ignored for all of the above */ #define IgnorableOrderby(X) ((X->eDest)<=SRT_Fifo) -#define SRT_Output 9 /* Output each row of result */ -#define SRT_Mem 10 /* Store result in a memory cell */ -#define SRT_Set 11 /* Store results as keys in an index */ -#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */ -#define SRT_Coroutine 13 /* Generate a single row of result */ -#define SRT_Table 14 /* Store result as data with an automatic rowid */ -#define SRT_Upfrom 15 /* Store result as data with rowid */ +#define SRT_Output 7 /* Output each row of result */ +#define SRT_Mem 8 /* Store result in a memory cell */ +#define SRT_Set 9 /* Store results as keys in an index */ +#define SRT_EphemTab 10 /* Create transient tab and store like SRT_Table */ +#define SRT_Coroutine 11 /* Generate a single row of result */ +#define SRT_Table 12 /* Store result as data with an automatic rowid */ +#define SRT_Upfrom 13 /* Store result as data with rowid */ /* ** An instance of this object describes where to put of the results of @@ -20146,25 +21047,33 @@ struct Parse { char *zErrMsg; /* An error message */ Vdbe *pVdbe; /* An engine for executing database bytecode */ int rc; /* Return code from execution */ - u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ - u8 checkSchema; /* Causes schema cookie check after an error */ + LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ - u8 mayAbort; /* True if statement may throw an ABORT exception */ - u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ - u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ - u8 bHasWith; /* True if statement contains WITH */ u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */ + u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ + u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif #ifdef SQLITE_DEBUG u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */ -#endif + u8 isCreate; /* CREATE TABLE, INDEX, or VIEW (but not TRIGGER) + ** and ALTER TABLE ADD COLUMN. */ +#endif + bft disableTriggers:1; /* True to disable triggers */ + bft mayAbort :1; /* True if statement may throw an ABORT exception */ + bft hasCompound :1; /* Need to invoke convertCompoundSelectToSubquery() */ + bft bReturning :1; /* Coding a RETURNING trigger */ + bft bHasExists :1; /* Has a correlated "EXISTS (SELECT ....)" expression */ + bft colNamesSet :1; /* TRUE after OP_ColumnName has been issued to pVdbe */ + bft bHasWith :1; /* True if statement contains WITH */ + bft okConstFactor:1; /* OK to factor out constants */ + bft checkSchema :1; /* Causes schema cookie check after an error */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ @@ -20173,18 +21082,16 @@ struct Parse { int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ int iSelfTab; /* Table associated with an index on expr, or negative ** of the base register during check-constraint eval */ + int nNestSel; /* Number of nested SELECT statements and/or VIEWs */ int nLabel; /* The *negative* of the number of labels used */ int nLabelAlloc; /* Number of slots in aLabel */ int *aLabel; /* Space to hold the labels */ ExprList *pConstExpr;/* Constant expressions */ IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */ IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */ - Token constraintName;/* Name of the constraint currently being parsed */ yDbMask writeMask; /* Start a write transaction on these databases */ yDbMask cookieMask; /* Bitmask of schema verified databases */ - int regRowid; /* Register holding rowid of CREATE TABLE entry */ - int regRoot; /* Register holding root page number for new objects */ - int nMaxArg; /* Max args passed to user function by sub-program */ + int nMaxArg; /* Max args to xUpdate and xFilter vtab methods */ int nSelect; /* Number of SELECT stmts. Counter for Select.selId */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */ @@ -20198,17 +21105,6 @@ struct Parse { Table *pTriggerTab; /* Table triggers are being coded for */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */ - union { - int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */ - Returning *pReturning; /* The RETURNING clause */ - } u1; - u32 oldmask; /* Mask of old.* columns referenced */ - u32 newmask; /* Mask of new.* columns referenced */ - LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ - u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ - u8 bReturning; /* Coding a RETURNING trigger */ - u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ - u8 disableTriggers; /* True to disable triggers */ /************************************************************************** ** Fields above must be initialized to zero. The fields that follow, @@ -20220,6 +21116,19 @@ struct Parse { int aTempReg[8]; /* Holding area for temporary registers */ Parse *pOuterParse; /* Outer Parse object when nested */ Token sNameToken; /* Token with unqualified schema object name */ + u32 oldmask; /* Mask of old.* columns referenced */ + u32 newmask; /* Mask of new.* columns referenced */ + union { + struct { /* These fields available when isCreate is true */ + int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */ + int regRowid; /* Register holding rowid of CREATE TABLE entry */ + int regRoot; /* Register holding root page for new objects */ + Token constraintName; /* Name of the constraint currently being parsed */ + } cr; + struct { /* These fields available to all other statements */ + Returning *pReturning; /* The RETURNING clause */ + } d; + } u1; /************************************************************************ ** Above is constant between recursions. Below is reset before and after @@ -20237,9 +21146,7 @@ struct Parse { int nVtabLock; /* Number of virtual tables to lock */ #endif int nHeight; /* Expression tree height of current sub-select */ -#ifndef SQLITE_OMIT_EXPLAIN int addrExplain; /* Address of current OP_Explain opcode */ -#endif VList *pVList; /* Mapping between variable names and numbers */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ const char *zTail; /* All SQL text past the last semicolon parsed */ @@ -20396,19 +21303,19 @@ struct Trigger { ** orconf -> stores the ON CONFLICT algorithm ** pSelect -> The content to be inserted - either a SELECT statement or ** a VALUES clause. -** zTarget -> Dequoted name of the table to insert into. +** pSrc -> Table to insert into. ** pIdList -> If this is an INSERT INTO ... () VALUES ... ** statement, then this stores the column-names to be ** inserted into. ** pUpsert -> The ON CONFLICT clauses for an Upsert ** ** (op == TK_DELETE) -** zTarget -> Dequoted name of the table to delete from. +** pSrc -> Table to delete from ** pWhere -> The WHERE clause of the DELETE statement if one is specified. ** Otherwise NULL. ** ** (op == TK_UPDATE) -** zTarget -> Dequoted name of the table to update. +** pSrc -> Table to update, followed by any FROM clause tables. ** pWhere -> The WHERE clause of the UPDATE statement if one is specified. ** Otherwise NULL. ** pExprList -> A list of the columns to update and the expressions to update @@ -20428,8 +21335,7 @@ struct TriggerStep { u8 orconf; /* OE_Rollback etc. */ Trigger *pTrig; /* The trigger that this step is a part of */ Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */ - char *zTarget; /* Target table for DELETE, UPDATE, INSERT */ - SrcList *pFrom; /* FROM clause for UPDATE statement (if any) */ + SrcList *pSrc; /* Table to insert/update/delete */ Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ ExprList *pExprList; /* SET clause for UPDATE, or RETURNING clause */ IdList *pIdList; /* Column names for INSERT */ @@ -20512,10 +21418,11 @@ typedef struct { /* ** Allowed values for mInitFlags */ -#define INITFLAG_AlterMask 0x0003 /* Types of ALTER */ +#define INITFLAG_AlterMask 0x0007 /* Types of ALTER */ #define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */ #define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */ #define INITFLAG_AlterAdd 0x0003 /* Reparse after an ADD COLUMN */ +#define INITFLAG_AlterDropCons 0x0004 /* Reparse after an ADD COLUMN */ /* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled ** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning @@ -20645,6 +21552,7 @@ struct Walker { NameContext *pNC; /* Naming context */ int n; /* A counter */ int iCur; /* A cursor number */ + int sz; /* String literal length */ SrcList *pSrcList; /* FROM clause */ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */ @@ -20660,6 +21568,7 @@ struct Walker { SrcItem *pSrcItem; /* A single FROM clause item */ DbFixer *pFix; /* See sqlite3FixSelect() */ Mem *aMem; /* See sqlite3BtreeCursorHint() */ + struct CheckOnCtx *pCheckOnCtx; /* See selectCheckOnClauses() */ } u; }; @@ -20737,9 +21646,13 @@ struct With { int nCte; /* Number of CTEs in the WITH clause */ int bView; /* Belongs to the outermost Select of a view */ With *pOuter; /* Containing WITH clause, or NULL */ - Cte a[1]; /* For each CTE in the WITH clause.... */ + Cte a[FLEXARRAY]; /* For each CTE in the WITH clause.... */ }; +/* The size (in bytes) of a With object that can hold as many +** as N different CTEs. */ +#define SZ_WITH(N) (offsetof(With,a) + (N)*sizeof(Cte)) + /* ** The Cte object is not guaranteed to persist for the entire duration ** of code generation. (The query flattener or other parser tree @@ -20768,9 +21681,13 @@ struct DbClientData { DbClientData *pNext; /* Next in a linked list */ void *pData; /* The data */ void (*xDestructor)(void*); /* Destructor. Might be NULL */ - char zName[1]; /* Name of this client data. MUST BE LAST */ + char zName[FLEXARRAY]; /* Name of this client data. MUST BE LAST */ }; +/* The size (in bytes) of a DbClientData object that can has a name +** that is N bytes long, including the zero-terminator. */ +#define SZ_DBCLIENTDATA(N) (offsetof(DbClientData,zName)+(N)) + #ifdef SQLITE_DEBUG /* ** An instance of the TreeView object is used for printing the content of @@ -21040,7 +21957,20 @@ SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3*,int*); SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void); SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void); -#if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT) + +/* The SQLITE_THREAD_MISUSE_WARNINGS compile-time option used to be called +** SQLITE_ENABLE_MULTITHREADED_CHECKS. Keep that older macro for backwards +** compatibility, at least for a while... */ +#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +# define SQLITE_THREAD_MISUSE_WARNINGS 1 +#endif + +/* SQLITE_THREAD_MISUSE_ABORT implies SQLITE_THREAD_MISUSE_WARNINGS */ +#ifdef SQLITE_THREAD_MISUSE_ABORT +# define SQLITE_THREAD_MISUSE_WARNINGS 1 +#endif + +#if defined(SQLITE_THREAD_MISUSE_WARNINGS) && !defined(SQLITE_MUTEX_OMIT) SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex*); #else # define sqlite3MutexWarnOnContention(x) @@ -21069,17 +21999,22 @@ struct PrintfArguments { sqlite3_value **apArg; /* The argument values */ }; +/* +** Maxium number of base-10 digits in an unsigned 64-bit integer +*/ +#define SQLITE_U64_DIGITS 20 + /* ** An instance of this object receives the decoding of a floating point ** value into an approximate decimal representation. */ struct FpDecode { - char sign; /* '+' or '-' */ - char isSpecial; /* 1: Infinity 2: NaN */ - int n; /* Significant digits in the decode */ - int iDP; /* Location of the decimal point */ - char *z; /* Start of significant digits */ - char zBuf[24]; /* Storage for significant digits */ + int n; /* Significant digits in the decode */ + int iDP; /* Location of the decimal point */ + char *z; /* Start of significant digits */ + char zBuf[SQLITE_U64_DIGITS+1]; /* Storage for significant digits */ + char sign; /* '+' or '-' */ + char isSpecial; /* 1: Infinity 2: NaN */ }; SQLITE_PRIVATE void sqlite3FpDecode(FpDecode*,double,int,int); @@ -21139,6 +22074,7 @@ SQLITE_PRIVATE void sqlite3ShowTriggerList(const Trigger*); SQLITE_PRIVATE void sqlite3ShowWindow(const Window*); SQLITE_PRIVATE void sqlite3ShowWinFunc(const Window*); #endif +SQLITE_PRIVATE void sqlite3ShowBitvec(Bitvec*); #endif SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*); @@ -21167,6 +22103,7 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int); #endif SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int); SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*); +SQLITE_PRIVATE Expr *sqlite3ExprInt32(sqlite3*,int); SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*); @@ -21213,7 +22150,7 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char); SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int); SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*); -SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index*, i16); +SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index*, int); #ifdef SQLITE_OMIT_GENERATED_COLUMNS # define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */ # define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */ @@ -21311,7 +22248,7 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*); SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*); SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*); SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*); -SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); +SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,int,int,char**); SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int, u8); SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); @@ -21320,6 +22257,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList Expr*,ExprList*,u32,Expr*); SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*); SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3*,void*); +SQLITE_PRIVATE void sqlite3SelectCheckOnClauses(Parse *pParse, Select *pSelect); SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*); SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, Trigger*); SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); @@ -21358,6 +22296,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int) SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int); +SQLITE_PRIVATE void sqlite3ExprNullRegisterRange(Parse*, int, int); SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); @@ -21416,6 +22355,7 @@ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*); SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*, Parse*); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); +SQLITE_PRIVATE int sqlite3ExprIsLikeOperator(const Expr*); SQLITE_PRIVATE int sqlite3IsRowid(const char*); SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab); SQLITE_PRIVATE void sqlite3GenerateRowDelete( @@ -21447,19 +22387,24 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int); SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*); SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); -SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*); +SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*,int); +SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char*, u32); SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void); SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) -SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3*); +SQLITE_PRIVATE Module *sqlite3JsonVtabRegister(sqlite3*,const char*); #endif SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*); SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*); SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int); SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p); +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_CARRAY) +SQLITE_PRIVATE Module *sqlite3CarrayRegister(sqlite3*); +#endif + #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int); #endif @@ -21479,17 +22424,16 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, i SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*, const char*,const char*); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*, +SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(Parse*,SrcList*, IdList*, Select*,u8,Upsert*, const char*,const char*); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,SrcList*,ExprList*, +SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(Parse*,SrcList*,SrcList*,ExprList*, Expr*, u8, const char*,const char*); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*, +SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(Parse*,SrcList*, Expr*, const char*,const char*); SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3*, Trigger*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int); -SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*); # define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p)) # define sqlite3IsToplevel(p) ((p)->pToplevel==0) #else @@ -21503,7 +22447,6 @@ SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*); # define sqlite3ParseToplevel(p) p # define sqlite3IsToplevel(p) 1 # define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0 -# define sqlite3TriggerStepSrc(A,B) 0 #endif SQLITE_PRIVATE int sqlite3JoinType(Parse*, Token*, Token*, Token*); @@ -21536,7 +22479,7 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64); SQLITE_PRIVATE i64 sqlite3RealToI64(double); SQLITE_PRIVATE int sqlite3Int64ToText(i64,char*); -SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); +SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*); SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*); SQLITE_PRIVATE int sqlite3Atoi(const char*); @@ -21680,10 +22623,21 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*); SQLITE_PRIVATE void sqlite3AlterFunctions(void); SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); -SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *); +SQLITE_PRIVATE void sqlite3AlterDropConstraint(Parse*,SrcList*,Token*,Token*); +SQLITE_PRIVATE void sqlite3AlterAddConstraint( + Parse *pParse, /* Parse context */ + SrcList *pSrc, /* Table to add constraint to */ + Token *pFirst, /* First token of new constraint */ + Token *pName, /* Name of new constraint. NULL if name omitted. */ + const char *zExpr, /* Text of CHECK expression */ + int nExpr, /* Size of pExpr in bytes */ + Expr *pExpr /* The parsed CHECK expression */ +); +SQLITE_PRIVATE void sqlite3AlterSetNotNull(Parse*, SrcList*, Token*, Token*); +SQLITE_PRIVATE i64 sqlite3GetToken(const unsigned char *, int *); SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int); -SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int); +SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int, int); SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr*); SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*); SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, SrcItem*); @@ -21756,6 +22710,7 @@ SQLITE_PRIVATE char *sqlite3RCStrResize(char*,u64); SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, i64); +SQLITE_PRIVATE int sqlite3StrAccumEnlargeIfNeeded(StrAccum*, i64); SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*); SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum*, u8); SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*); @@ -22312,6 +23267,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_BUG_COMPATIBLE_20160819 "BUG_COMPATIBLE_20160819", #endif +#ifdef SQLITE_BUG_COMPATIBLE_20250510 + "BUG_COMPATIBLE_20250510", +#endif #ifdef SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif @@ -22443,6 +23401,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_ENABLE_BYTECODE_VTAB "ENABLE_BYTECODE_VTAB", #endif +#ifdef SQLITE_ENABLE_CARRAY + "ENABLE_CARRAY", +#endif #ifdef SQLITE_ENABLE_CEROD "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD), #endif @@ -22533,6 +23494,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK "ENABLE_OVERSIZE_CELL_CHECK", #endif +#ifdef SQLITE_ENABLE_PERCENTILE + "ENABLE_PERCENTILE", +#endif #ifdef SQLITE_ENABLE_PREUPDATE_HOOK "ENABLE_PREUPDATE_HOOK", #endif @@ -22548,6 +23512,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_ENABLE_SESSION "ENABLE_SESSION", #endif +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + "ENABLE_SETLK_TIMEOUT", +#endif #ifdef SQLITE_ENABLE_SNAPSHOT "ENABLE_SNAPSHOT", #endif @@ -22602,6 +23569,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_EXTRA_INIT "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), #endif +#ifdef SQLITE_EXTRA_INIT_MUTEXED + "EXTRA_INIT_MUTEXED=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT_MUTEXED), +#endif #ifdef SQLITE_EXTRA_SHUTDOWN "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), #endif @@ -22968,6 +23938,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_STMTJRNL_SPILL "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL), #endif +#ifdef SQLITE_STRICT_SUBTYPE + "STRICT_SUBTYPE", +#endif #ifdef SQLITE_SUBSTR_COMPATIBILITY "SUBSTR_COMPATIBILITY", #endif @@ -22999,9 +23972,6 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_UNTESTABLE "UNTESTABLE", #endif -#ifdef SQLITE_USER_AUTHENTICATION - "USER_AUTHENTICATION", -#endif #ifdef SQLITE_USE_ALLOCA "USE_ALLOCA", #endif @@ -23589,12 +24559,19 @@ struct VdbeCursor { #endif VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */ - /* 2*nField extra array elements allocated for aType[], beyond the one - ** static element declared in the structure. nField total array slots for - ** aType[] and nField+1 array slots for aOffset[] */ - u32 aType[1]; /* Type values record decode. MUST BE LAST */ + /* Space is allocated for aType to hold at least 2*nField+1 entries: + ** nField slots for aType[] and nField+1 array slots for aOffset[] */ + u32 aType[FLEXARRAY]; /* Type values record decode. MUST BE LAST */ }; +/* +** The size (in bytes) of a VdbeCursor object that has an nField value of N +** or less. The value of SZ_VDBECURSOR(n) is guaranteed to be a multiple +** of 8. +*/ +#define SZ_VDBECURSOR(N) \ + (ROUND8(offsetof(VdbeCursor,aType)) + ((N)+1)*sizeof(u64)) + /* Return true if P is a null-only cursor */ #define IsNullCursor(P) \ @@ -23700,6 +24677,7 @@ struct sqlite3_value { #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ u16 mScopyFlags; /* flags value immediately after the shallow copy */ + u8 bScopy; /* The pScopyFrom of some other Mem *might* point here */ #endif }; @@ -23736,7 +24714,7 @@ struct sqlite3_value { ** MEM_Int, MEM_Real, and MEM_IntReal. ** ** * MEM_Blob|MEM_Zero A blob in Mem.z of length Mem.n plus -** MEM.u.i extra 0x00 bytes at the end. +** Mem.u.nZero extra 0x00 bytes at the end. ** ** * MEM_Int Integer stored in Mem.u.i. ** @@ -23849,14 +24827,17 @@ struct sqlite3_context { int isError; /* Error code returned by the function. */ u8 enc; /* Encoding to use for results */ u8 skipFlag; /* Skip accumulator loading if true */ - u8 argc; /* Number of arguments */ - sqlite3_value *argv[1]; /* Argument set */ + u16 argc; /* Number of arguments */ + sqlite3_value *argv[FLEXARRAY]; /* Argument set */ }; -/* A bitfield type for use inside of structures. Always follow with :N where -** N is the number of bits. +/* +** The size (in bytes) of an sqlite3_context object that holds N +** argv[] arguments. */ -typedef unsigned bft; /* Bit Field Type */ +#define SZ_CONTEXT(N) \ + (offsetof(sqlite3_context,argv)+(N)*sizeof(sqlite3_value*)) + /* The ScanStatus object holds a single value for the ** sqlite3_stmt_scanstatus() interface. @@ -23917,7 +24898,7 @@ struct Vdbe { i64 nStmtDefCons; /* Number of def. constraints when stmt started */ i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ Mem *aMem; /* The memory locations */ - Mem **apArg; /* Arguments to currently executing user function */ + Mem **apArg; /* Arguments xUpdate and xFilter vtab methods */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ Mem *aVar; /* Values for the OP_Variable opcode. */ @@ -23937,6 +24918,7 @@ struct Vdbe { #ifdef SQLITE_DEBUG int rcApp; /* errcode set by sqlite3_result_error_code() */ u32 nWrite; /* Number of write operations that have occurred */ + int napArg; /* Size of the apArg[] array */ #endif u16 nResColumn; /* Number of columns in one row of the result set */ u16 nResAlloc; /* Column slots allocated to aColName[] */ @@ -23989,17 +24971,21 @@ struct PreUpdate { VdbeCursor *pCsr; /* Cursor to read old values from */ int op; /* One of SQLITE_INSERT, UPDATE, DELETE */ u8 *aRecord; /* old.* database record */ - KeyInfo keyinfo; + KeyInfo *pKeyinfo; /* Key information */ UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */ UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */ int iNewReg; /* Register for new.* values */ int iBlobWrite; /* Value returned by preupdate_blobwrite() */ i64 iKey1; /* First key value passed to hook */ i64 iKey2; /* Second key value passed to hook */ + Mem oldipk; /* Memory cell holding "old" IPK value */ Mem *aNew; /* Array of new.* values */ Table *pTab; /* Schema object being updated */ Index *pPk; /* PK index if pTab is WITHOUT ROWID */ sqlite3_value **apDflt; /* Array of default values, if required */ + struct { + u8 keyinfoSpace[SZ_KEYINFO_0]; /* Space to hold pKeyinfo[0] content */ + } uKey; }; /* @@ -24070,6 +25056,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int); SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*); SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, i64, u8, void(*)(void*)); +SQLITE_PRIVATE int sqlite3VdbeMemSetText(Mem*, const char*, i64, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64); #ifdef SQLITE_OMIT_FLOATING_POINT # define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64 @@ -24088,13 +25075,14 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem*,int); SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*); #endif SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*); -SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemZeroTerminateIfAble(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8); SQLITE_PRIVATE int sqlite3IntFloatCompare(i64,double); SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem*); SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*); SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*); +SQLITE_PRIVATE int sqlite3MemRealValueRC(Mem*, double*); SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem*, int ifNull); SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*); @@ -24125,6 +25113,7 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int,int); #endif SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p); +SQLITE_PRIVATE int sqlite3VdbeFindIndexKey(BtCursor*, Index*, UnpackedRecord*, int*, int); SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); @@ -24163,9 +25152,11 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem*); #endif #ifndef SQLITE_OMIT_FOREIGN_KEY -SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int); +SQLITE_PRIVATE int sqlite3VdbeCheckFkImmediate(Vdbe*); +SQLITE_PRIVATE int sqlite3VdbeCheckFkDeferred(Vdbe*); #else -# define sqlite3VdbeCheckFk(p,i) 0 +# define sqlite3VdbeCheckFkImmediate(p) 0 +# define sqlite3VdbeCheckFkDeferred(p) 0 #endif #ifdef SQLITE_DEBUG @@ -24366,30 +25357,33 @@ SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){ nInit += countLookasideSlots(db->lookaside.pSmallInit); nFree += countLookasideSlots(db->lookaside.pSmallFree); #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ - if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit; - return db->lookaside.nSlot - (nInit+nFree); + assert( db->lookaside.nSlot >= nInit+nFree ); + if( pHighwater ) *pHighwater = (int)(db->lookaside.nSlot - nInit); + return (int)(db->lookaside.nSlot - (nInit+nFree)); } /* ** Query status information for a single database connection */ -SQLITE_API int sqlite3_db_status( - sqlite3 *db, /* The database connection whose status is desired */ - int op, /* Status verb */ - int *pCurrent, /* Write current value here */ - int *pHighwater, /* Write high-water mark here */ - int resetFlag /* Reset high-water mark if true */ +SQLITE_API int sqlite3_db_status64( + sqlite3 *db, /* The database connection whose status is desired */ + int op, /* Status verb */ + sqlite3_int64 *pCurrent, /* Write current value here */ + sqlite3_int64 *pHighwtr, /* Write high-water mark here */ + int resetFlag /* Reset high-water mark if true */ ){ int rc = SQLITE_OK; /* Return code */ #ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){ + if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwtr==0 ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); switch( op ){ case SQLITE_DBSTATUS_LOOKASIDE_USED: { - *pCurrent = sqlite3LookasideUsed(db, pHighwater); + int H = 0; + *pCurrent = sqlite3LookasideUsed(db, &H); + *pHighwtr = H; if( resetFlag ){ LookasideSlot *p = db->lookaside.pFree; if( p ){ @@ -24420,7 +25414,7 @@ SQLITE_API int sqlite3_db_status( assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 ); assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 ); *pCurrent = 0; - *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT]; + *pHighwtr = db->lookaside.anStat[op-SQLITE_DBSTATUS_LOOKASIDE_HIT]; if( resetFlag ){ db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0; } @@ -24434,7 +25428,7 @@ SQLITE_API int sqlite3_db_status( */ case SQLITE_DBSTATUS_CACHE_USED_SHARED: case SQLITE_DBSTATUS_CACHE_USED: { - int totalUsed = 0; + sqlite3_int64 totalUsed = 0; int i; sqlite3BtreeEnterAll(db); for(i=0; inDb; i++){ @@ -24450,18 +25444,18 @@ SQLITE_API int sqlite3_db_status( } sqlite3BtreeLeaveAll(db); *pCurrent = totalUsed; - *pHighwater = 0; + *pHighwtr = 0; break; } /* ** *pCurrent gets an accurate estimate of the amount of memory used ** to store the schema for all databases (main, temp, and any ATTACHed - ** databases. *pHighwater is set to zero. + ** databases. *pHighwtr is set to zero. */ case SQLITE_DBSTATUS_SCHEMA_USED: { - int i; /* Used to iterate through schemas */ - int nByte = 0; /* Used to accumulate return value */ + int i; /* Used to iterate through schemas */ + int nByte = 0; /* Used to accumulate return value */ sqlite3BtreeEnterAll(db); db->pnBytesFreed = &nByte; @@ -24495,7 +25489,7 @@ SQLITE_API int sqlite3_db_status( db->lookaside.pEnd = db->lookaside.pTrueEnd; sqlite3BtreeLeaveAll(db); - *pHighwater = 0; + *pHighwtr = 0; *pCurrent = nByte; break; } @@ -24503,7 +25497,7 @@ SQLITE_API int sqlite3_db_status( /* ** *pCurrent gets an accurate estimate of the amount of memory used ** to store all prepared statements. - ** *pHighwater is set to zero. + ** *pHighwtr is set to zero. */ case SQLITE_DBSTATUS_STMT_USED: { struct Vdbe *pVdbe; /* Used to iterate through VMs */ @@ -24518,7 +25512,7 @@ SQLITE_API int sqlite3_db_status( db->lookaside.pEnd = db->lookaside.pTrueEnd; db->pnBytesFreed = 0; - *pHighwater = 0; /* IMP: R-64479-57858 */ + *pHighwtr = 0; /* IMP: R-64479-57858 */ *pCurrent = nByte; break; @@ -24526,7 +25520,7 @@ SQLITE_API int sqlite3_db_status( /* ** Set *pCurrent to the total cache hits or misses encountered by all - ** pagers the database handle is connected to. *pHighwater is always set + ** pagers the database handle is connected to. *pHighwtr is always set ** to zero. */ case SQLITE_DBSTATUS_CACHE_SPILL: @@ -24546,19 +25540,39 @@ SQLITE_API int sqlite3_db_status( sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); } } - *pHighwater = 0; /* IMP: R-42420-56072 */ + *pHighwtr = 0; /* IMP: R-42420-56072 */ /* IMP: R-54100-20147 */ /* IMP: R-29431-39229 */ - *pCurrent = (int)nRet & 0x7fffffff; + *pCurrent = nRet; + break; + } + + /* Set *pCurrent to the number of bytes that the db database connection + ** has spilled to the filesystem in temporary files that could have been + ** stored in memory, had sufficient memory been available. + ** The *pHighwater is always set to zero. + */ + case SQLITE_DBSTATUS_TEMPBUF_SPILL: { + u64 nRet = 0; + if( db->aDb[1].pBt ){ + Pager *pPager = sqlite3BtreePager(db->aDb[1].pBt); + sqlite3PagerCacheStat(pPager, SQLITE_DBSTATUS_CACHE_WRITE, + resetFlag, &nRet); + nRet *= sqlite3BtreeGetPageSize(db->aDb[1].pBt); + } + nRet += db->nSpill; + if( resetFlag ) db->nSpill = 0; + *pHighwtr = 0; + *pCurrent = nRet; break; } /* Set *pCurrent to non-zero if there are unresolved deferred foreign ** key constraints. Set *pCurrent to zero if all foreign key constraints - ** have been satisfied. The *pHighwater is always set to zero. + ** have been satisfied. The *pHighwtr is always set to zero. */ case SQLITE_DBSTATUS_DEFERRED_FKS: { - *pHighwater = 0; /* IMP: R-11967-56545 */ + *pHighwtr = 0; /* IMP: R-11967-56545 */ *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0; break; } @@ -24571,6 +25585,31 @@ SQLITE_API int sqlite3_db_status( return rc; } +/* +** 32-bit variant of sqlite3_db_status64() +*/ +SQLITE_API int sqlite3_db_status( + sqlite3 *db, /* The database connection whose status is desired */ + int op, /* Status verb */ + int *pCurrent, /* Write current value here */ + int *pHighwtr, /* Write high-water mark here */ + int resetFlag /* Reset high-water mark if true */ +){ + sqlite3_int64 C = 0, H = 0; + int rc; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwtr==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + rc = sqlite3_db_status64(db, op, &C, &H, resetFlag); + if( rc==0 ){ + *pCurrent = C & 0x7fffffff; + *pHighwtr = H & 0x7fffffff; + } + return rc; +} + /************** End of status.c **********************************************/ /************** Begin file date.c ********************************************/ /* @@ -24763,6 +25802,10 @@ static int parseTimezone(const char *zDate, DateTime *p){ } zDate += 5; p->tz = sgn*(nMn + nHr*60); + if( p->tz==0 ){ /* Forum post 2025-09-17T10:12:14z */ + p->isLocal = 0; + p->isUtc = 1; + } zulu_time: while( sqlite3Isspace(*zDate) ){ zDate++; } return *zDate!=0; @@ -24797,6 +25840,9 @@ static int parseHhMmSs(const char *zDate, DateTime *p){ zDate++; } ms /= rScale; + /* Truncate to avoid problems with sub-milliseconds + ** rounding. https://sqlite.org/forum/forumpost/766a2c9231 */ + if( ms>0.999 ) ms = 0.999; } }else{ s = 0; @@ -24997,7 +26043,7 @@ static int parseDateOrTime( return 0; }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){ return setDateTimeToCurrent(context, p); - }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){ + }else if( sqlite3AtoF(zDate, &r)>0 ){ setRawDateNumber(p, r); return 0; }else if( (sqlite3StrICmp(zDate,"subsec")==0 @@ -25443,7 +26489,7 @@ static int parseModifier( ** date is already on the appropriate weekday, this is a no-op. */ if( sqlite3_strnicmp(z, "weekday ", 8)==0 - && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0 + && sqlite3AtoF(&z[8], &r)>0 && r>=0.0 && r<7.0 && (n=(int)r)==r ){ sqlite3_int64 Z; computeYMD_HMS(p); @@ -25514,9 +26560,11 @@ static int parseModifier( case '8': case '9': { double rRounder; - int i; + int i, rx; int Y,M,D,h,m,x; const char *z2 = z; + char *zCopy; + sqlite3 *db = sqlite3_context_db_handle(pCtx); char z0 = z[0]; for(n=1; z[n]; n++){ if( z[n]==':' ) break; @@ -25526,7 +26574,11 @@ static int parseModifier( if( n==6 && getDigits(&z[1], "50f", &Y)==1 ) break; } } - if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){ + zCopy = sqlite3DbStrNDup(db, z, n); + if( zCopy==0 ) break; + rx = sqlite3AtoF(zCopy, &r)<=0; + sqlite3DbFree(db, zCopy); + if( rx ){ assert( rc==1 ); break; } @@ -25929,7 +26981,7 @@ static int daysAfterMonday(DateTime *pDate){ ** In other words, return the day of the week according ** to this code: ** -** 0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday +** 0=Sunday, 1=Monday, 2=Tuesday, ..., 6=Saturday */ static int daysAfterSunday(DateTime *pDate){ assert( pDate->validJD ); @@ -25955,8 +27007,8 @@ static int daysAfterSunday(DateTime *pDate){ ** %l hour 1-12 (leading zero converted to space) ** %m month 01-12 ** %M minute 00-59 -** %p "am" or "pm" -** %P "AM" or "PM" +** %p "AM" or "PM" +** %P "am" or "pm" ** %R time as HH:MM ** %s seconds since 1970-01-01 ** %S seconds 00-59 @@ -26004,7 +27056,7 @@ static void strftimeFunc( } case 'f': { /* Fractional seconds. (Non-standard) */ double s = x.s; - if( s>59.999 ) s = 59.999; + if( NEVER(s>59.999) ) s = 59.999; sqlite3_str_appendf(&sRes, "%06.3f", s); break; } @@ -26346,7 +27398,7 @@ static void datedebugFunc( char *zJson; zJson = sqlite3_mprintf( "{iJD:%lld,Y:%d,M:%d,D:%d,h:%d,m:%d,tz:%d," - "s:%.3f,validJD:%d,validYMS:%d,validHMS:%d," + "s:%.3f,validJD:%d,validYMD:%d,validHMS:%d," "nFloor:%d,rawS:%d,isError:%d,useSubsec:%d," "isUtc:%d,isLocal:%d}", x.iJD, x.Y, x.M, x.D, x.h, x.m, x.tz, @@ -26693,7 +27745,7 @@ SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p }else{ double r; rc = pVfs->xCurrentTime(pVfs, &r); - *pTimeOut = (sqlite3_int64)(r*86400000.0); + *pTimeOut = sqlite3RealToI64(r*86400000.0); } return rc; } @@ -29125,23 +30177,28 @@ static SQLITE_WSD int mutexIsInit = 0; #ifndef SQLITE_MUTEX_OMIT -#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +#ifdef SQLITE_THREAD_MISUSE_WARNINGS /* -** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains +** This block (enclosed by SQLITE_THREAD_MISUSE_WARNINGS) contains ** the implementation of a wrapper around the system default mutex ** implementation (sqlite3DefaultMutex()). ** ** Most calls are passed directly through to the underlying default ** mutex implementation. Except, if a mutex is configured by calling ** sqlite3MutexWarnOnContention() on it, then if contention is ever -** encountered within xMutexEnter() a warning is emitted via sqlite3_log(). +** encountered within xMutexEnter() then a warning is emitted via +** sqlite3_log(). Furthermore, if SQLITE_THREAD_MISUSE_ABORT is +** defined then abort() is called after the sqlite3_log() warning. ** -** This type of mutex is used as the database handle mutex when testing -** apps that usually use SQLITE_CONFIG_MULTITHREAD mode. +** This type of mutex is used on the database handle mutex when testing +** apps that usually use SQLITE_CONFIG_MULTITHREAD mode. A failure +** indicates that the app ought to be using SQLITE_OPEN_FULLMUTEX or +** similar because it is trying to use the same database handle from +** two different connections at the same time. */ /* -** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS +** Type for all mutexes used when SQLITE_THREAD_MISUSE_WARNINGS ** is defined. Variable CheckMutex.mutex is a pointer to the real mutex ** allocated by the system mutex implementation. Variable iType is usually set ** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST @@ -29177,11 +30234,12 @@ static int checkMutexNotheld(sqlite3_mutex *p){ */ static int checkMutexInit(void){ pGlobalMutexMethods = sqlite3DefaultMutex(); - return SQLITE_OK; + return pGlobalMutexMethods->xMutexInit(); } static int checkMutexEnd(void){ + int rc = pGlobalMutexMethods->xMutexEnd(); pGlobalMutexMethods = 0; - return SQLITE_OK; + return rc; } /* @@ -29258,6 +30316,9 @@ static void checkMutexEnter(sqlite3_mutex *p){ sqlite3_log(SQLITE_MISUSE, "illegal multi-threaded access to database connection" ); +#if SQLITE_THREAD_MISUSE_ABORT + abort(); +#endif } pGlobalMutexMethods->xMutexEnter(pCheck->mutex); } @@ -29309,7 +30370,7 @@ SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex *p){ pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION; } } -#endif /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */ +#endif /* ifdef SQLITE_THREAD_MISUSE_WARNINGS */ /* ** Initialize the mutex system. @@ -29326,7 +30387,7 @@ SQLITE_PRIVATE int sqlite3MutexInit(void){ sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex; if( sqlite3GlobalConfig.bCoreMutex ){ -#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +#ifdef SQLITE_THREAD_MISUSE_WARNINGS pFrom = multiThreadedCheckMutex(); #else pFrom = sqlite3DefaultMutex(); @@ -30138,6 +31199,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ #ifdef __CYGWIN__ # include +# include /* amalgamator: dontcache */ +# include /* amalgamator: dontcache */ # include /* amalgamator: dontcache */ #endif @@ -30172,14 +31235,6 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ # define SQLITE_OS_WINCE 0 #endif -/* -** Determine if we are dealing with WinRT, which provides only a subset of -** the full Win32 API. -*/ -#if !defined(SQLITE_OS_WINRT) -# define SQLITE_OS_WINRT 0 -#endif - /* ** For WinCE, some API function parameters do not appear to be declared as ** volatile. @@ -30194,7 +31249,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ ** For some Windows sub-platforms, the _beginthreadex() / _endthreadex() ** functions are not available (e.g. those not using MSVC, Cygwin, etc). */ -#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ +#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && \ SQLITE_THREADSAFE>0 && !defined(__CYGWIN__) # define SQLITE_OS_WIN_THREADS 1 #else @@ -30311,11 +31366,7 @@ static int winMutexInit(void){ if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){ int i; for(i=0; itrace = 1; #endif #endif -#if SQLITE_OS_WINRT - InitializeCriticalSectionEx(&p->mutex, 0, 0); -#else InitializeCriticalSection(&p->mutex); -#endif } break; } @@ -30879,27 +31926,6 @@ static void mallocWithAlarm(int n, void **pp){ *pp = p; } -/* -** Maximum size of any single memory allocation. -** -** This is not a limit on the total amount of memory used. This is -** a limit on the size parameter to sqlite3_malloc() and sqlite3_realloc(). -** -** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391 -** This provides a 256-byte safety margin for defense against 32-bit -** signed integer overflow bugs when computing memory allocation sizes. -** Paranoid applications might want to reduce the maximum allocation size -** further for an even larger safety margin. 0x3fffffff or 0x0fffffff -** or even smaller would be reasonable upper bounds on the size of a memory -** allocations for most applications. -*/ -#ifndef SQLITE_MAX_ALLOCATION_SIZE -# define SQLITE_MAX_ALLOCATION_SIZE 2147483391 -#endif -#if SQLITE_MAX_ALLOCATION_SIZE>2147483391 -# error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391 -#endif - /* ** Allocate memory. This routine is like sqlite3_malloc() except that it ** assumes the memory subsystem has already been initialized. @@ -31123,8 +32149,7 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ sqlite3_free(pOld); /* IMP: R-26507-47431 */ return 0; } - if( nBytes>=0x7fffff00 ){ - /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */ + if( nBytes>SQLITE_MAX_ALLOCATION_SIZE ){ return 0; } nOld = sqlite3MallocSize(pOld); @@ -31538,17 +32563,17 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ #define etPERCENT 7 /* Percent symbol. %% */ #define etCHARX 8 /* Characters. %c */ /* The rest are extensions, not normally found in printf() */ -#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */ -#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', - NULL pointers replaced by SQL NULL. %Q */ -#define etTOKEN 11 /* a pointer to a Token structure */ -#define etSRCITEM 12 /* a pointer to a SrcItem */ -#define etPOINTER 13 /* The %p conversion */ -#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ -#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ -#define etDECIMAL 16 /* %d or %u, but not %x, %o */ +#define etESCAPE_q 9 /* Strings with '\'' doubled. %q */ +#define etESCAPE_Q 10 /* Strings with '\'' doubled and enclosed in '', + NULL pointers replaced by SQL NULL. %Q */ +#define etTOKEN 11 /* a pointer to a Token structure */ +#define etSRCITEM 12 /* a pointer to a SrcItem */ +#define etPOINTER 13 /* The %p conversion */ +#define etESCAPE_w 14 /* %w -> Strings with '\"' doubled */ +#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ +#define etDECIMAL 16 /* %d or %u, but not %x, %o */ -#define etINVALID 17 /* Any unrecognized conversion type */ +#define etINVALID 17 /* Any unrecognized conversion type */ /* @@ -31567,6 +32592,7 @@ typedef struct et_info { /* Information about each format field */ etByte type; /* Conversion paradigm */ etByte charset; /* Offset into aDigits[] of the digits string */ etByte prefix; /* Offset into aPrefix[] of the prefix string */ + char iNxt; /* Next with same hash, or 0 for end of chain */ } et_info; /* @@ -31575,44 +32601,61 @@ typedef struct et_info { /* Information about each format field */ #define FLAG_SIGNED 1 /* True if the value to convert is signed */ #define FLAG_STRING 4 /* Allow infinite precision */ - /* -** The following table is searched linearly, so it is good to put the -** most frequently used conversion types first. +** The table is searched by hash. In the case of %C where C is the character +** and that character has ASCII value j, then the hash is j%23. +** +** The order of the entries in fmtinfo[] and the hash chain was entered +** manually, but based on the output of the following TCL script: */ +#if 0 /***** Beginning of script ******/ +foreach c {d s g z q Q w c o u x X f e E G i n % p T S r} { + scan $c %c x + set n($c) $x +} +set mx [llength [array names n]] +puts "count: $mx" + +set mx 27 +puts "*********** mx=$mx ************" +for {set r 0} {$r<$mx} {incr r} { + puts -nonewline [format %2d: $r] + foreach c [array names n] { + if {($n($c))%$mx==$r} {puts -nonewline " $c"} + } + puts "" +} +#endif /***** End of script ********/ + static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; static const char aPrefix[] = "-x0\000X0"; -static const et_info fmtinfo[] = { - { 'd', 10, 1, etDECIMAL, 0, 0 }, - { 's', 0, 4, etSTRING, 0, 0 }, - { 'g', 0, 1, etGENERIC, 30, 0 }, - { 'z', 0, 4, etDYNSTRING, 0, 0 }, - { 'q', 0, 4, etSQLESCAPE, 0, 0 }, - { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, - { 'w', 0, 4, etSQLESCAPE3, 0, 0 }, - { 'c', 0, 0, etCHARX, 0, 0 }, - { 'o', 8, 0, etRADIX, 0, 2 }, - { 'u', 10, 0, etDECIMAL, 0, 0 }, - { 'x', 16, 0, etRADIX, 16, 1 }, - { 'X', 16, 0, etRADIX, 0, 4 }, -#ifndef SQLITE_OMIT_FLOATING_POINT - { 'f', 0, 1, etFLOAT, 0, 0 }, - { 'e', 0, 1, etEXP, 30, 0 }, - { 'E', 0, 1, etEXP, 14, 0 }, - { 'G', 0, 1, etGENERIC, 14, 0 }, -#endif - { 'i', 10, 1, etDECIMAL, 0, 0 }, - { 'n', 0, 0, etSIZE, 0, 0 }, - { '%', 0, 0, etPERCENT, 0, 0 }, - { 'p', 16, 0, etPOINTER, 0, 1 }, - - /* All the rest are undocumented and are for internal use only */ - { 'T', 0, 0, etTOKEN, 0, 0 }, - { 'S', 0, 0, etSRCITEM, 0, 0 }, - { 'r', 10, 1, etORDINAL, 0, 0 }, +static const et_info fmtinfo[23] = { + /* 0 */ { 's', 0, 4, etSTRING, 0, 0, 1 }, + /* 1 */ { 'E', 0, 1, etEXP, 14, 0, 0 }, /* Hash: 0 */ + /* 2 */ { 'u', 10, 0, etDECIMAL, 0, 0, 3 }, + /* 3 */ { 'G', 0, 1, etGENERIC, 14, 0, 0 }, /* Hash: 2 */ + /* 4 */ { 'w', 0, 4, etESCAPE_w, 0, 0, 0 }, + /* 5 */ { 'x', 16, 0, etRADIX, 16, 1, 0 }, + /* 6 */ { 'c', 0, 0, etCHARX, 0, 0, 0 }, /* Hash: 7 */ + /* 7 */ { 'z', 0, 4, etDYNSTRING, 0, 0, 6 }, + /* 8 */ { 'd', 10, 1, etDECIMAL, 0, 0, 0 }, + /* 9 */ { 'e', 0, 1, etEXP, 30, 0, 0 }, + /* 10 */ { 'f', 0, 1, etFLOAT, 0, 0, 0 }, + /* 11 */ { 'g', 0, 1, etGENERIC, 30, 0, 0 }, + /* 12 */ { 'Q', 0, 4, etESCAPE_Q, 0, 0, 0 }, + /* 13 */ { 'i', 10, 1, etDECIMAL, 0, 0, 0 }, + /* 14 */ { '%', 0, 0, etPERCENT, 0, 0, 16 }, + /* 15 */ { 'T', 0, 0, etTOKEN, 0, 0, 0 }, + /* 16 */ { 'S', 0, 0, etSRCITEM, 0, 0, 0 }, /* Hash: 14 */ + /* 17 */ { 'X', 16, 0, etRADIX, 0, 4, 0 }, /* Hash: 19 */ + /* 18 */ { 'n', 0, 0, etSIZE, 0, 0, 0 }, + /* 19 */ { 'o', 8, 0, etRADIX, 0, 2, 17 }, + /* 20 */ { 'p', 16, 0, etPOINTER, 0, 1, 0 }, + /* 21 */ { 'q', 0, 4, etESCAPE_q, 0, 0, 0 }, + /* 22 */ { 'r', 10, 1, etORDINAL, 0, 0, 0 } }; -/* Notes: +/* Additional Notes: ** ** %S Takes a pointer to SrcItem. Shows name or database.name ** %!S Like %S but prefer the zName over the zAlias @@ -31660,7 +32703,7 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){ sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG); return 0; } - z = sqlite3DbMallocRaw(pAccum->db, n); + z = sqlite3_malloc(n); if( z==0 ){ sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM); } @@ -31739,7 +32782,10 @@ SQLITE_API void sqlite3_str_vappendf( #if HAVE_STRCHRNUL fmt = strchrnul(fmt, '%'); #else - do{ fmt++; }while( *fmt && *fmt != '%' ); + fmt = strchr(fmt, '%'); + if( fmt==0 ){ + fmt = bufpt + strlen(bufpt); + } #endif sqlite3_str_append(pAccum, bufpt, (int)(fmt - bufpt)); if( *fmt==0 ) break; @@ -31853,6 +32899,9 @@ SQLITE_API void sqlite3_str_vappendf( }while( !done && (c=(*++fmt))!=0 ); /* Fetch the info entry for the field */ +#ifdef SQLITE_EBCDIC + /* The hash table only works for ASCII. For EBCDIC, we need to do + ** a linear search of the table */ infop = &fmtinfo[0]; xtype = etINVALID; for(idx=0; idxtype; + }else{ + infop = &fmtinfo[0]; + xtype = etINVALID; + } +#endif /* ** At this point, variables are initialized as follows: @@ -31929,6 +32992,14 @@ SQLITE_API void sqlite3_str_vappendf( } prefix = 0; } + +#if WHERETRACE_ENABLED + if( xtype==etPOINTER && sqlite3WhereTrace & 0x100000 ) longvalue = 0; +#endif +#if TREETRACE_ENABLED + if( xtype==etPOINTER && sqlite3TreeTrace & 0x100000 ) longvalue = 0; +#endif + if( longvalue==0 ) flag_alternateform = 0; if( flag_zeropad && precision0 ); } length = (int)(&zOut[nOut-1]-bufpt); - while( precision>length ){ - *(--bufpt) = '0'; /* Zero pad */ - length++; + if( precision>length ){ /* zero pad */ + int nn = precision-length; + bufpt -= nn; + memset(bufpt,'0',nn); + length = precision; } if( cThousand ){ int nn = (length - 1)/3; /* Number of "," to insert */ @@ -31996,6 +33069,7 @@ SQLITE_API void sqlite3_str_vappendf( FpDecode s; int iRound; int j; + i64 szBufNeeded; /* Size needed to hold the output */ if( bArgList ){ realvalue = getDoubleArg(pArgList); @@ -32016,7 +33090,7 @@ SQLITE_API void sqlite3_str_vappendf( }else{ iRound = precision+1; } - sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16); + sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 20 : 16); if( s.isSpecial ){ if( s.isSpecial==2 ){ bufpt = flag_zeropad ? "null" : "NaN"; @@ -32041,7 +33115,21 @@ SQLITE_API void sqlite3_str_vappendf( } } if( s.sign=='-' ){ - prefix = '-'; + if( flag_alternateform + && !flag_prefix + && xtype==etFLOAT + && s.iDP<=iRound + ){ + /* Suppress the minus sign if all of the following are true: + ** * The value displayed is zero + ** * The '#' flag is used + ** * The '+' flag is not used, and + ** * The format is %f + */ + prefix = 0; + }else{ + prefix = '-'; + } }else{ prefix = flag_prefix; } @@ -32070,17 +33158,31 @@ SQLITE_API void sqlite3_str_vappendf( }else{ e2 = s.iDP - 1; } - bufpt = buf; - { - i64 szBufNeeded; /* Size of a temporary buffer needed */ - szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15; - if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3; - if( szBufNeeded > etBUFSIZE ){ - bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded); - if( bufpt==0 ) return; + + szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+10; + if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3; + if( szBufNeeded + pAccum->nChar >= pAccum->nAlloc ){ + if( pAccum->mxAlloc==0 && pAccum->accError==0 ){ + /* Unable to allocate space in pAccum, perhaps because it + ** is coming from sqlite3_snprintf() or similar. We'll have + ** to render into temporary space and the memcpy() it over. */ + bufpt = sqlite3_malloc(szBufNeeded); + if( bufpt==0 ){ + sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM); + return; + } + zExtra = bufpt; + }else if( sqlite3StrAccumEnlarge(pAccum, szBufNeeded)zText + pAccum->nChar; } + }else{ + bufpt = pAccum->zText + pAccum->nChar; } zOut = bufpt; + flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2; /* The sign in front of the number */ if( prefix ){ @@ -32088,12 +33190,24 @@ SQLITE_API void sqlite3_str_vappendf( } /* Digits prior to the decimal point */ j = 0; + assert( s.n>0 ); if( e2<0 ){ *(bufpt++) = '0'; - }else{ + }else if( cThousand ){ for(; e2>=0; e2--){ *(bufpt++) = j1 ) *(bufpt++) = ','; + if( (e2%3)==0 && e2>1 ) *(bufpt++) = ','; + } + }else{ + j = e2+1; + if( j>s.n ) j = s.n; + memcpy(bufpt, s.z, j); + bufpt += j; + e2 -= j; + if( e2>=0 ){ + memset(bufpt, '0', e2+1); + bufpt += e2+1; + e2 = -1; } } /* The decimal point */ @@ -32102,12 +33216,26 @@ SQLITE_API void sqlite3_str_vappendf( } /* "0" digits after the decimal point but before the first ** significant digit of the number */ - for(e2++; e2<0 && precision>0; precision--, e2++){ - *(bufpt++) = '0'; + if( e2<(-1) && precision>0 ){ + int nn = -1-e2; + if( nn>precision ) nn = precision; + memset(bufpt, '0', nn); + bufpt += nn; + precision -= nn; } /* Significant digits after the decimal point */ - while( (precision--)>0 ){ - *(bufpt++) = j0 ){ + int nn = s.n - j; + if( NEVER(nn>precision) ) nn = precision; + if( nn>0 ){ + memcpy(bufpt, s.z+j, nn); + bufpt += nn; + precision -= nn; + } + if( precision>0 && !flag_rtz ){ + memset(bufpt, '0', precision); + bufpt += precision; + } } /* Remove trailing zeros and the "." if no digits follow the "." */ if( flag_rtz && flag_dp ){ @@ -32137,27 +33265,39 @@ SQLITE_API void sqlite3_str_vappendf( *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */ *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */ } - *bufpt = 0; - /* The converted number is in buf[] and zero terminated. Output it. - ** Note that the number is in the usual order, not reversed as with - ** integer conversions. */ length = (int)(bufpt-zOut); - bufpt = zOut; - - /* Special case: Add leading zeros if the flag_zeropad flag is - ** set and we are not left justified */ - if( flag_zeropad && !flag_leftjustify && length < width){ - int i; - int nPad = width - length; - for(i=width; i>=nPad; i--){ - bufpt[i] = bufpt[i-nPad]; + assert( length <= szBufNeeded ); + if( lengthnChar += length; + zOut[length] = 0; + continue; + }else{ + /* We were unable to render directly into pAccum because we + ** couldn't allocate sufficient memory. We need to memcpy() + ** the rendering (or some prefix thereof) into the output + ** buffer. */ + bufpt[0] = 0; + bufpt = zExtra; + break; + } } case etSIZE: if( !bArgList ){ @@ -32186,25 +33326,7 @@ SQLITE_API void sqlite3_str_vappendf( } }else{ unsigned int ch = va_arg(ap,unsigned int); - if( ch<0x00080 ){ - buf[0] = ch & 0xff; - length = 1; - }else if( ch<0x00800 ){ - buf[0] = 0xc0 + (u8)((ch>>6)&0x1f); - buf[1] = 0x80 + (u8)(ch & 0x3f); - length = 2; - }else if( ch<0x10000 ){ - buf[0] = 0xe0 + (u8)((ch>>12)&0x0f); - buf[1] = 0x80 + (u8)((ch>>6) & 0x3f); - buf[2] = 0x80 + (u8)(ch & 0x3f); - length = 3; - }else{ - buf[0] = 0xf0 + (u8)((ch>>18) & 0x07); - buf[1] = 0x80 + (u8)((ch>>12) & 0x3f); - buf[2] = 0x80 + (u8)((ch>>6) & 0x3f); - buf[3] = 0x80 + (u8)(ch & 0x3f); - length = 4; - } + length = sqlite3AppendOneUtf8Character(buf, ch); } if( precision>1 ){ i64 nPrior = 1; @@ -32219,10 +33341,9 @@ SQLITE_API void sqlite3_str_vappendf( i64 nCopyBytes; if( nPrior > precision-1 ) nPrior = precision - 1; nCopyBytes = length*nPrior; - if( nCopyBytes + pAccum->nChar >= pAccum->nAlloc ){ - sqlite3StrAccumEnlarge(pAccum, nCopyBytes); + if( sqlite3StrAccumEnlargeIfNeeded(pAccum, nCopyBytes) ){ + break; } - if( pAccum->accError ) break; sqlite3_str_append(pAccum, &pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes); precision -= nPrior; @@ -32284,22 +33405,31 @@ SQLITE_API void sqlite3_str_vappendf( while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++; } break; - case etSQLESCAPE: /* %q: Escape ' characters */ - case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */ - case etSQLESCAPE3: { /* %w: Escape " characters */ + case etESCAPE_q: /* %q: Escape ' characters */ + case etESCAPE_Q: /* %Q: Escape ' and enclose in '...' */ + case etESCAPE_w: { /* %w: Escape " characters */ i64 i, j, k, n; - int needQuote, isnull; + int needQuote = 0; char ch; - char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ char *escarg; + char q; if( bArgList ){ escarg = getTextArg(pArgList); }else{ escarg = va_arg(ap,char*); } - isnull = escarg==0; - if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)"); + if( escarg==0 ){ + escarg = (xtype==etESCAPE_Q ? "NULL" : "(NULL)"); + }else if( xtype==etESCAPE_Q ){ + needQuote = 1; + } + if( xtype==etESCAPE_w ){ + q = '"'; + flag_alternateform = 0; + }else{ + q = '\''; + } /* For %q, %Q, and %w, the precision is the number of bytes (or ** characters if the ! flags is present) to use from the input. ** Because of the extra quoting characters inserted, the number @@ -32312,7 +33442,30 @@ SQLITE_API void sqlite3_str_vappendf( while( (escarg[i+1]&0xc0)==0x80 ){ i++; } } } - needQuote = !isnull && xtype==etSQLESCAPE2; + if( flag_alternateform ){ + /* For %#q, do unistr()-style backslash escapes for + ** all control characters, and for backslash itself. + ** For %#Q, do the same but only if there is at least + ** one control character. */ + i64 nBack = 0; + i64 nCtrl = 0; + for(k=0; ketBUFSIZE ){ bufpt = zExtra = printfTempBuf(pAccum, n); @@ -32321,13 +33474,41 @@ SQLITE_API void sqlite3_str_vappendf( bufpt = buf; } j = 0; - if( needQuote ) bufpt[j++] = q; + if( needQuote ){ + if( needQuote==2 ){ + memcpy(&bufpt[j], "unistr('", 8); + j += 8; + }else{ + bufpt[j++] = '\''; + } + } k = i; - for(i=0; i=0x10 ? '1' : '0'; + bufpt[j++] = "0123456789abcdef"[ch&0xf]; + } + } + }else{ + for(i=0; ipLeft; } if( pExpr==0 ) return; + if( ExprHasProperty(pExpr, EP_FromDDL) ) return; db->errByteOffset = pExpr->w.iOfst; } @@ -32508,6 +33690,13 @@ SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, i64 N){ return (int)N; } +SQLITE_PRIVATE int sqlite3StrAccumEnlargeIfNeeded(StrAccum *p, i64 N){ + if( N + p->nChar >= p->nAlloc ){ + sqlite3StrAccumEnlarge(p, N); + } + return p->accError; +} + /* ** Append N copies of character c to the given string buffer. */ @@ -32569,7 +33758,7 @@ SQLITE_API void sqlite3_str_appendall(sqlite3_str *p, const char *z){ static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){ char *zText; assert( p->mxAlloc>0 && !isMalloced(p) ); - zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); + zText = sqlite3DbMallocRaw(p->db, 1+(u64)p->nChar ); if( zText ){ memcpy(zText, p->zText, p->nChar+1); p->printfFlags |= SQLITE_PRINTF_MALLOCED; @@ -32638,6 +33827,14 @@ SQLITE_API int sqlite3_str_length(sqlite3_str *p){ return p ? p->nChar : 0; } +/* Truncate the text of the string to be no more than N bytes. */ +SQLITE_API void sqlite3_str_truncate(sqlite3_str *p, int N){ + if( p!=0 && N>=0 && (u32)NnChar ){ + p->nChar = N; + p->zText[p->nChar] = 0; + } +} + /* Return the current value for p */ SQLITE_API char *sqlite3_str_value(sqlite3_str *p){ if( p==0 || p->nChar==0 ) return 0; @@ -32658,6 +33855,17 @@ SQLITE_API void sqlite3_str_reset(StrAccum *p){ p->zText = 0; } +/* +** Destroy a dynamically allocate sqlite3_str object and all +** of its content, all in one call. +*/ +SQLITE_API void sqlite3_str_free(sqlite3_str *p){ + if( p!=0 && p!=&sqlite3OomStr ){ + sqlite3_str_reset(p); + sqlite3_free(p); + } +} + /* ** Initialize a string accumulator. ** @@ -32814,6 +34022,15 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ return zBuf; } +/* Maximum size of an sqlite3_log() message. */ +#if defined(SQLITE_MAX_LOG_MESSAGE) + /* Leave the definition as supplied */ +#elif SQLITE_PRINT_BUF_SIZE*10>10000 +# define SQLITE_MAX_LOG_MESSAGE 10000 +#else +# define SQLITE_MAX_LOG_MESSAGE (SQLITE_PRINT_BUF_SIZE*10) +#endif + /* ** This is the routine that actually formats the sqlite3_log() message. ** We house it in a separate routine from sqlite3_log() to avoid using @@ -32830,7 +34047,7 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ */ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ StrAccum acc; /* String accumulator */ - char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ + char zMsg[SQLITE_MAX_LOG_MESSAGE]; /* Complete log message */ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); sqlite3_str_vappendf(&acc, zFormat, ap); @@ -33177,10 +34394,13 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc) sqlite3_str_appendf(&x, " DDL"); } if( pItem->fg.isCte ){ - sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse); + static const char *aMat[] = {",MAT", "", ",NO-MAT"}; + sqlite3_str_appendf(&x, " CteUse=%d%s", + pItem->u2.pCteUse->nUse, + aMat[pItem->u2.pCteUse->eM10d]); } if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){ - sqlite3_str_appendf(&x, " ON"); + sqlite3_str_appendf(&x, " isOn"); } if( pItem->fg.isTabFunc ) sqlite3_str_appendf(&x, " isTabFunc"); if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated"); @@ -33197,9 +34417,13 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc) n = 0; if( pItem->fg.isSubquery ) n++; if( pItem->fg.isTabFunc ) n++; - if( pItem->fg.isUsing ) n++; + if( pItem->fg.isUsing || pItem->u3.pOn!=0 ) n++; if( pItem->fg.isUsing ){ sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING"); + }else if( pItem->u3.pOn!=0 ){ + sqlite3TreeViewItem(pView, "ON", (--n)>0); + sqlite3TreeViewExpr(pView, pItem->u3.pOn, 0); + sqlite3TreeViewPop(&pView); } if( pItem->fg.isSubquery ){ assert( n==1 ); @@ -33208,9 +34432,6 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc) sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1); } assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) ); - sqlite3TreeViewPush(&pView, 0); - sqlite3TreeViewLine(pView, "SUBQUERY"); - sqlite3TreeViewPop(&pView); sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, 0); } if( pItem->fg.isTabFunc ){ @@ -33940,21 +35161,7 @@ SQLITE_PRIVATE void sqlite3TreeViewBareIdList( if( zName==0 ) zName = "(null)"; sqlite3TreeViewPush(&pView, moreToFollow); sqlite3TreeViewLine(pView, 0); - if( pList->eU4==EU4_NONE ){ - fprintf(stdout, "%s\n", zName); - }else if( pList->eU4==EU4_IDX ){ - fprintf(stdout, "%s (%d)\n", zName, pList->a[i].u4.idx); - }else{ - assert( pList->eU4==EU4_EXPR ); - if( pList->a[i].u4.pExpr==0 ){ - fprintf(stdout, "%s (pExpr=NULL)\n", zName); - }else{ - fprintf(stdout, "%s\n", zName); - sqlite3TreeViewPush(&pView, inId-1); - sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0); - sqlite3TreeViewPop(&pView); - } - } + fprintf(stdout, "%s\n", zName); sqlite3TreeViewPop(&pView); } } @@ -34264,11 +35471,21 @@ SQLITE_PRIVATE void sqlite3TreeViewTrigger( ** accessible to the debugging, and to avoid warnings about unused ** functions. But these routines only exist in debugging builds, so they ** do not contaminate the interface. +** +** See Also: +** +** sqlite3ShowWhereTerm() in where.c */ SQLITE_PRIVATE void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); } SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);} SQLITE_PRIVATE void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); } -SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); } +SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ + TreeView *pView = 0; + sqlite3TreeViewPush(&pView, 0); + sqlite3TreeViewLine(pView, "SRCLIST"); + sqlite3TreeViewSrcList(pView,p); + sqlite3TreeViewPop(&pView); +} SQLITE_PRIVATE void sqlite3ShowSelect(const Select *p){ sqlite3TreeViewSelect(0,p,0); } SQLITE_PRIVATE void sqlite3ShowWith(const With *p){ sqlite3TreeViewWith(0,p,0); } SQLITE_PRIVATE void sqlite3ShowUpsert(const Upsert *p){ sqlite3TreeViewUpsert(0,p,0); } @@ -34649,6 +35866,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ rc = sqlite3Win32Wait((HANDLE)p->tid); assert( rc!=WAIT_IO_COMPLETION ); bRc = CloseHandle((HANDLE)p->tid); + (void)bRc; /* Prevent warning when assert() is a no-op */ assert( bRc ); } if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; @@ -34835,6 +36053,35 @@ static const unsigned char sqlite3Utf8Trans1[] = { } \ } +/* +** Write a single UTF8 character whose value is v into the +** buffer starting at zOut. zOut must be sized to hold at +** least four bytes. Return the number of bytes needed +** to encode the new character. +*/ +SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char *zOut, u32 v){ + if( v<0x00080 ){ + zOut[0] = (u8)(v & 0xff); + return 1; + } + if( v<0x00800 ){ + zOut[0] = 0xc0 + (u8)((v>>6) & 0x1f); + zOut[1] = 0x80 + (u8)(v & 0x3f); + return 2; + } + if( v<0x10000 ){ + zOut[0] = 0xe0 + (u8)((v>>12) & 0x0f); + zOut[1] = 0x80 + (u8)((v>>6) & 0x3f); + zOut[2] = 0x80 + (u8)(v & 0x3f); + return 3; + } + zOut[0] = 0xf0 + (u8)((v>>18) & 0x07); + zOut[1] = 0x80 + (u8)((v>>12) & 0x3f); + zOut[2] = 0x80 + (u8)((v>>6) & 0x3f); + zOut[3] = 0x80 + (u8)(v & 0x3f); + return 4; +} + /* ** Translate a single UTF-8 character. Return the unicode value. ** @@ -35256,7 +36503,7 @@ SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nByte, int nChar){ int n = 0; if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++; - while( n=0xd8 && c<0xdc && z<=zEnd && z[0]>=0xdc && z[0]<0xe0 ) z += 2; @@ -35759,255 +37006,618 @@ SQLITE_PRIVATE u8 sqlite3StrIHash(const char *z){ return h; } -/* Double-Double multiplication. (x[0],x[1]) *= (y,yy) -** -** Reference: -** T. J. Dekker, "A Floating-Point Technique for Extending the -** Available Precision". 1971-07-26. +#if !defined(SQLITE_DISABLE_INTRINSIC) \ + && (defined(__GNUC__) || defined(__clang__)) \ + && (defined(__x86_64__) || defined(__aarch64__) || \ + (defined(__riscv) && defined(__riscv_xlen) && (__riscv_xlen>32))) +#define SQLITE_USE_UINT128 +#endif + +/* +** Two inputs are multiplied to get a 128-bit result. Write the +** lower 64-bits of the result into *pLo, and return the high-order +** 64 bits. */ -static void dekkerMul2(volatile double *x, double y, double yy){ - /* - ** The "volatile" keywords on parameter x[] and on local variables - ** below are needed force intermediate results to be truncated to - ** binary64 rather than be carried around in an extended-precision - ** format. The truncation is necessary for the Dekker algorithm to - ** work. Intel x86 floating point might omit the truncation without - ** the use of volatile. - */ - volatile double tx, ty, p, q, c, cc; - double hx, hy; - u64 m; - memcpy(&m, (void*)&x[0], 8); - m &= 0xfffffffffc000000LL; - memcpy(&hx, &m, 8); - tx = x[0] - hx; - memcpy(&m, &y, 8); - m &= 0xfffffffffc000000LL; - memcpy(&hy, &m, 8); - ty = y - hy; - p = hx*hy; - q = hx*ty + tx*hy; - c = p+q; - cc = p - c + q + tx*ty; - cc = x[0]*yy + x[1]*y + cc; - x[0] = c + cc; - x[1] = c - x[0]; - x[1] += cc; +static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){ +#if defined(SQLITE_USE_UINT128) + __uint128_t r = (__uint128_t)a * b; + *pLo = (u64)r; + return (u64)(r>>64); +#elif defined(_WIN64) && !defined(SQLITE_DISABLE_INTRINSIC) + *pLo = a*b; + return __umulh(a, b); +#else + u64 a0 = (u32)a; + u64 a1 = a >> 32; + u64 b0 = (u32)b; + u64 b1 = b >> 32; + u64 a0b0 = a0 * b0; + u64 a1b1 = a1 * b1; + u64 a0b1 = a0 * b1; + u64 a1b0 = a1 * b0; + u64 t = (a0b0 >> 32) + (u32)a0b1 + (u32)a1b0; + *pLo = (a0b0 & UINT64_C(0xffffffff)) | (t << 32); + return a1b1 + (a0b1>>32) + (a1b0>>32) + (t>>32); +#endif +} + +/* +** A is an unsigned 96-bit integer formed by (a<<32)+aLo. +** B is an unsigned 64-bit integer. +** +** Compute the upper 96 bits of 160-bit result of A*B. +** +** Write ((A*B)>>64 & 0xffffffff) (the middle 32 bits of A*B) +** into *pLo. Return the upper 64 bits of A*B. +** +** The lower 64 bits of A*B are discarded. +*/ +static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){ +#if defined(SQLITE_USE_UINT128) + __uint128_t r = (__uint128_t)a * b; + r += ((__uint128_t)aLo * b) >> 32; + *pLo = (r>>32)&0xffffffff; + return r>>64; +#elif defined(_WIN64) && !defined(SQLITE_DISABLE_INTRINSIC) + u64 r1_hi = __umulh(a,b); + u64 r1_lo = a*b; + u64 r2 = (__umulh((u64)aLo,b)<<32) + ((aLo*b)>>32); + u64 t = r1_lo + r2; + if( t>32; + return r1_hi; +#else + u64 x2 = a>>32; + u64 x1 = a&0xffffffff; + u64 x0 = aLo; + u64 y1 = b>>32; + u64 y0 = b&0xffffffff; + u64 x2y1 = x2*y1; + u64 r4 = x2y1>>32; + u64 x2y0 = x2*y0; + u64 x1y1 = x1*y1; + u64 r3 = (x2y1 & 0xffffffff) + (x2y0 >>32) + (x1y1 >>32); + u64 x1y0 = x1*y0; + u64 x0y1 = x0*y1; + u64 r2 = (x2y0 & 0xffffffff) + (x1y1 & 0xffffffff) + + (x1y0 >>32) + (x0y1>>32); + u64 x0y0 = x0*y0; + u64 r1 = (x1y0 & 0xffffffff) + (x0y1 & 0xffffffff) + + (x0y0 >>32); + r2 += r1>>32; + r3 += r2>>32; + *pLo = r2&0xffffffff; + return (r4<<32) + r3; +#endif } +#undef SQLITE_USE_UINT128 + /* -** The string z[] is an text representation of a real number. -** Convert this string to a double and write it into *pResult. +** Return a u64 with the N-th bit set. +*/ +#define U64_BIT(N) (((u64)1)<<(N)) + +/* +** Range of powers of 10 that we need to deal with when converting +** IEEE754 doubles to and from decimal. +*/ +#define POWERSOF10_FIRST (-348) +#define POWERSOF10_LAST (+347) + +/* +** For any p between -348 and +347, return the integer part of ** -** The string z[] is length bytes in length (bytes, not characters) and -** uses the encoding enc. The string is not necessarily zero-terminated. +** pow(10,p) * pow(2,63-pow10to2(p)) ** -** Return TRUE if the result is a valid real number (or integer) and FALSE -** if the string is empty or contains extraneous text. More specifically -** return -** 1 => The input string is a pure integer -** 2 or more => The input has a decimal point or eNNN clause -** 0 or less => The input string is not a valid number -** -1 => Not a valid number, but has a valid prefix which -** includes a decimal point and/or an eNNN clause +** Or, in other words, for any p in range, return the most significant +** 64 bits of pow(10,p). The pow(10,p) value is shifted left or right, +** as appropriate so the most significant 64 bits fit exactly into a +** 64-bit unsigned integer. ** -** Valid numbers are in one of these formats: +** Write into *pLo the next 32 significant bits of the answer after +** the first 64. ** -** [+-]digits[E[+-]digits] -** [+-]digits.[digits][E[+-]digits] -** [+-].digits[E[+-]digits] +** Algorithm: +** +** (1) For p between 0 and 26, return the value directly from the aBase[] +** lookup table. +** +** (2) For p outside the range 0 to 26, use aScale[] for the initial value +** then refine that result (if necessary) by a single multiplication +** against aBase[]. +** +** The constant tables aBase[], aScale[], and aScaleLo[] are generated +** by the C program at ../tool/mkfptab.c run with the --round option. +*/ +static u64 powerOfTen(int p, u32 *pLo){ + static const u64 aBase[] = { + UINT64_C(0x8000000000000000), /* 0: 1.0e+0 << 63 */ + UINT64_C(0xa000000000000000), /* 1: 1.0e+1 << 60 */ + UINT64_C(0xc800000000000000), /* 2: 1.0e+2 << 57 */ + UINT64_C(0xfa00000000000000), /* 3: 1.0e+3 << 54 */ + UINT64_C(0x9c40000000000000), /* 4: 1.0e+4 << 50 */ + UINT64_C(0xc350000000000000), /* 5: 1.0e+5 << 47 */ + UINT64_C(0xf424000000000000), /* 6: 1.0e+6 << 44 */ + UINT64_C(0x9896800000000000), /* 7: 1.0e+7 << 40 */ + UINT64_C(0xbebc200000000000), /* 8: 1.0e+8 << 37 */ + UINT64_C(0xee6b280000000000), /* 9: 1.0e+9 << 34 */ + UINT64_C(0x9502f90000000000), /* 10: 1.0e+10 << 30 */ + UINT64_C(0xba43b74000000000), /* 11: 1.0e+11 << 27 */ + UINT64_C(0xe8d4a51000000000), /* 12: 1.0e+12 << 24 */ + UINT64_C(0x9184e72a00000000), /* 13: 1.0e+13 << 20 */ + UINT64_C(0xb5e620f480000000), /* 14: 1.0e+14 << 17 */ + UINT64_C(0xe35fa931a0000000), /* 15: 1.0e+15 << 14 */ + UINT64_C(0x8e1bc9bf04000000), /* 16: 1.0e+16 << 10 */ + UINT64_C(0xb1a2bc2ec5000000), /* 17: 1.0e+17 << 7 */ + UINT64_C(0xde0b6b3a76400000), /* 18: 1.0e+18 << 4 */ + UINT64_C(0x8ac7230489e80000), /* 19: 1.0e+19 >> 0 */ + UINT64_C(0xad78ebc5ac620000), /* 20: 1.0e+20 >> 3 */ + UINT64_C(0xd8d726b7177a8000), /* 21: 1.0e+21 >> 6 */ + UINT64_C(0x878678326eac9000), /* 22: 1.0e+22 >> 10 */ + UINT64_C(0xa968163f0a57b400), /* 23: 1.0e+23 >> 13 */ + UINT64_C(0xd3c21bcecceda100), /* 24: 1.0e+24 >> 16 */ + UINT64_C(0x84595161401484a0), /* 25: 1.0e+25 >> 20 */ + UINT64_C(0xa56fa5b99019a5c8), /* 26: 1.0e+26 >> 23 */ + }; + static const u64 aScale[] = { + UINT64_C(0x8049a4ac0c5811ae), /* 0: 1.0e-351 << 1229 */ + UINT64_C(0xcf42894a5dce35ea), /* 1: 1.0e-324 << 1140 */ + UINT64_C(0xa76c582338ed2621), /* 2: 1.0e-297 << 1050 */ + UINT64_C(0x873e4f75e2224e68), /* 3: 1.0e-270 << 960 */ + UINT64_C(0xda7f5bf590966848), /* 4: 1.0e-243 << 871 */ + UINT64_C(0xb080392cc4349dec), /* 5: 1.0e-216 << 781 */ + UINT64_C(0x8e938662882af53e), /* 6: 1.0e-189 << 691 */ + UINT64_C(0xe65829b3046b0afa), /* 7: 1.0e-162 << 602 */ + UINT64_C(0xba121a4650e4ddeb), /* 8: 1.0e-135 << 512 */ + UINT64_C(0x964e858c91ba2655), /* 9: 1.0e-108 << 422 */ + UINT64_C(0xf2d56790ab41c2a2), /* 10: 1.0e-81 << 333 */ + UINT64_C(0xc428d05aa4751e4c), /* 11: 1.0e-54 << 243 */ + UINT64_C(0x9e74d1b791e07e48), /* 12: 1.0e-27 << 153 */ + UINT64_C(0xcccccccccccccccc), /* 13: 1.0e-1 << 67 (special case) */ + UINT64_C(0xcecb8f27f4200f3a), /* 14: 1.0e+27 >> 26 */ + UINT64_C(0xa70c3c40a64e6c51), /* 15: 1.0e+54 >> 116 */ + UINT64_C(0x86f0ac99b4e8dafd), /* 16: 1.0e+81 >> 206 */ + UINT64_C(0xda01ee641a708de9), /* 17: 1.0e+108 >> 295 */ + UINT64_C(0xb01ae745b101e9e4), /* 18: 1.0e+135 >> 385 */ + UINT64_C(0x8e41ade9fbebc27d), /* 19: 1.0e+162 >> 475 */ + UINT64_C(0xe5d3ef282a242e81), /* 20: 1.0e+189 >> 564 */ + UINT64_C(0xb9a74a0637ce2ee1), /* 21: 1.0e+216 >> 654 */ + UINT64_C(0x95f83d0a1fb69cd9), /* 22: 1.0e+243 >> 744 */ + UINT64_C(0xf24a01a73cf2dccf), /* 23: 1.0e+270 >> 833 */ + UINT64_C(0xc3b8358109e84f07), /* 24: 1.0e+297 >> 923 */ + UINT64_C(0x9e19db92b4e31ba9), /* 25: 1.0e+324 >> 1013 */ + }; + static const unsigned int aScaleLo[] = { + 0x205b896d, /* 0: 1.0e-351 << 1229 */ + 0x52064cad, /* 1: 1.0e-324 << 1140 */ + 0xaf2af2b8, /* 2: 1.0e-297 << 1050 */ + 0x5a7744a7, /* 3: 1.0e-270 << 960 */ + 0xaf39a475, /* 4: 1.0e-243 << 871 */ + 0xbd8d794e, /* 5: 1.0e-216 << 781 */ + 0x547eb47b, /* 6: 1.0e-189 << 691 */ + 0x0cb4a5a3, /* 7: 1.0e-162 << 602 */ + 0x92f34d62, /* 8: 1.0e-135 << 512 */ + 0x3a6a07f9, /* 9: 1.0e-108 << 422 */ + 0xfae27299, /* 10: 1.0e-81 << 333 */ + 0xaa97e14c, /* 11: 1.0e-54 << 243 */ + 0x775ea265, /* 12: 1.0e-27 << 153 */ + 0xcccccccc, /* 13: 1.0e-1 << 67 (special case) */ + 0x00000000, /* 14: 1.0e+27 >> 26 */ + 0x999090b6, /* 15: 1.0e+54 >> 116 */ + 0x69a028bb, /* 16: 1.0e+81 >> 206 */ + 0xe80e6f48, /* 17: 1.0e+108 >> 295 */ + 0x5ec05dd0, /* 18: 1.0e+135 >> 385 */ + 0x14588f14, /* 19: 1.0e+162 >> 475 */ + 0x8f1668c9, /* 20: 1.0e+189 >> 564 */ + 0x6d953e2c, /* 21: 1.0e+216 >> 654 */ + 0x4abdaf10, /* 22: 1.0e+243 >> 744 */ + 0xbc633b39, /* 23: 1.0e+270 >> 833 */ + 0x0a862f81, /* 24: 1.0e+297 >> 923 */ + 0x6c07a2c2, /* 25: 1.0e+324 >> 1013 */ + }; + int g, n; + u64 s, x; + u32 lo; + + assert( p>=POWERSOF10_FIRST && p<=POWERSOF10_LAST ); + if( p<0 ){ + if( p==(-1) ){ + *pLo = aScaleLo[13]; + return aScale[13]; + } + g = p/27; + n = p%27; + if( n ){ + g--; + n += 27; + } + }else if( p<27 ){ + *pLo = 0; + return aBase[p]; + }else{ + g = p/27; + n = p%27; + } + s = aScale[g+13]; + if( n==0 ){ + *pLo = aScaleLo[g+13]; + return s; + } + x = sqlite3Multiply160(s,aScaleLo[g+13],aBase[n],&lo); + if( (U64_BIT(63) & x)==0 ){ + x = x<<1 | ((lo>>31)&1); + lo = (lo<<1) | 1; + } + *pLo = lo; + return x; +} + +/* +** pow10to2(x) computes floor(log2(pow(10,x))). +** pow2to10(y) computes floor(log10(pow(2,y))). +** +** Conceptually, pow10to2(p) converts a base-10 exponent p into +** a corresponding base-2 exponent, and pow2to10(e) converts a base-2 +** exponent into a base-10 exponent. ** -** Leading and trailing whitespace is ignored for the purpose of determining -** validity. +** The conversions are based on the observation that: ** -** If some prefix of the input string is a valid number, this routine -** returns FALSE but it still converts the prefix and writes the result -** into *pResult. +** ln(10.0)/ln(2.0) == 108853/32768 (approximately) +** ln(2.0)/ln(10.0) == 78913/262144 (approximately) +** +** These ratios are approximate, but they are accurate to 5 digits, +** which is close enough for the usage here. Right-shift is used +** for division so that rounding of negative numbers happens in the +** right direction. */ -#if defined(_MSC_VER) -#pragma warning(disable : 4756) -#endif -SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ -#ifndef SQLITE_OMIT_FLOATING_POINT - int incr; - const char *zEnd; - /* sign * significand * (10 ^ (esign * exponent)) */ - int sign = 1; /* sign of significand */ - u64 s = 0; /* significand */ - int d = 0; /* adjust exponent for shifting decimal point */ - int esign = 1; /* sign of exponent */ - int e = 0; /* exponent */ - int eValid = 1; /* True exponent is either not used or is well-formed */ - int nDigit = 0; /* Number of digits processed */ - int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ - double rr[2]; - u64 s2; +static int pwr10to2(int p){ return (p*108853) >> 15; } +static int pwr2to10(int p){ return (p*78913) >> 18; } - assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); - *pResult = 0.0; /* Default return value, in case of an error */ - if( length==0 ) return 0; +/* +** Count leading zeros for a 64-bit unsigned integer. +*/ +static int countLeadingZeros(u64 m){ +#if (defined(__GNUC__) || defined(__clang__)) \ + && !defined(SQLITE_DISABLE_INTRINSIC) + return __builtin_clzll(m); +#else + int n = 0; + if( m <= 0x00000000ffffffffULL) { n += 32; m <<= 32; } + if( m <= 0x0000ffffffffffffULL) { n += 16; m <<= 16; } + if( m <= 0x00ffffffffffffffULL) { n += 8; m <<= 8; } + if( m <= 0x0fffffffffffffffULL) { n += 4; m <<= 4; } + if( m <= 0x3fffffffffffffffULL) { n += 2; m <<= 2; } + if( m <= 0x7fffffffffffffffULL) { n += 1; } + return n; +#endif +} - if( enc==SQLITE_UTF8 ){ - incr = 1; - zEnd = z + length; +/* +** Given m and e, which represent a quantity r == m*pow(2,e), +** return values *pD and *pP such that r == (*pD)*pow(10,*pP), +** approximately. *pD should contain at least n significant digits. +** +** The input m is required to have its highest bit set. In other words, +** m should be left-shifted, and e decremented, to maximize the value of m. +*/ +static void sqlite3Fp2Convert10(u64 m, int e, int n, u64 *pD, int *pP){ + int p; + u64 h, d1; + u32 d2; + assert( n>=1 && n<=18 ); + p = n - 1 - pwr2to10(e+63); + h = sqlite3Multiply128(m, powerOfTen(p,&d2), &d1); + assert( -(e + pwr10to2(p) + 2) >= 0 ); + assert( -(e + pwr10to2(p) + 1) <= 63 ); + if( n==18 ){ + h >>= -(e + pwr10to2(p) + 2); + *pD = (h + ((h<<1)&2))>>1; }else{ - int i; - incr = 2; - length &= ~1; - assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); - testcase( enc==SQLITE_UTF16LE ); - testcase( enc==SQLITE_UTF16BE ); - for(i=3-enc; i> -(e + pwr10to2(p) + 1); } + *pP = -p; +} - /* skip leading spaces */ - while( z=zEnd ) return 0; - - /* get sign of significand */ - if( *z=='-' ){ - sign = -1; - z+=incr; - }else if( *z=='+' ){ - z+=incr; - } +/* +** Return an IEEE754 floating point value that approximates d*pow(10,p). +** +** The (current) algorithm is adapted from the work of Ross Cox at +** https://github.com/rsc/fpfmt +*/ +static double sqlite3Fp10Convert2(u64 d, int p){ + int b, lp, e, adj, s; + u32 pwr10l, mid1; + u64 pwr10h, x, hi, lo, sticky, u, m; + double r; + if( pPOWERSOF10_LAST ) return INFINITY; + b = 64 - countLeadingZeros(d); + lp = pwr10to2(p); + e = 53 - b - lp; + if( e > 1074 ){ + if( e>=1130 ) return 0.0; + e = 1074; + } + s = -(e-(64-b) + lp + 3); + pwr10h = powerOfTen(p, &pwr10l); + if( pwr10l!=0 ){ + pwr10h++; + pwr10l = ~pwr10l; + } + x = d<<(64-b); + hi = sqlite3Multiply128(x,pwr10h,&lo); + mid1 = lo>>32; + sticky = 1; + if( (hi & (U64_BIT(s)-1))==0 ) { + u32 mid2 = sqlite3Multiply128(x,((u64)pwr10l)<<32,&lo)>>32; + sticky = (mid1-mid2 > 1); + hi -= mid1 < mid2; + } + u = (hi>>s) | sticky; + adj = (u >= U64_BIT(55)-2); + if( adj ){ + u = (u>>adj) | (u&1); + e -= adj; + } + m = (u + 1 + ((u>>2)&1)) >> 2; + if( e<=(-972) ) return INFINITY; + if((m & U64_BIT(52)) != 0){ + m = (m & ~U64_BIT(52)) | ((u64)(1075-e)<<52); + } + memcpy(&r,&m,8); + return r; +} - /* copy max significant digits to significand */ - while( z=((LARGEST_UINT64-9)/10) ){ - /* skip non-significant significand digits - ** (increase exponent by d to shift decimal left) */ - while( z Set if any prefix of the input is valid. Clear if +** there is no prefix of the input that can be seen as +** a valid floating point number. +** bit 1 => Set if the input contains a decimal point or eNNN +** clause. Zero if the input is an integer. +** bit 2 => The input is exactly 0.0, not an underflow from +** some value near zero. +** bit 3 => Set if there are more than about 19 significant +** digits in the input. +** +** If the input contains a syntax error but begins with text that might +** be a valid number of some kind, then the result is negative. The +** result is only zero if no prefix of the input could be interpreted as +** a number. +** +** Leading and trailing whitespace is ignored. Valid numbers are in +** one of the formats below: +** +** [+-]digits[E[+-]digits] +** [+-]digits.[digits][E[+-]digits] +** [+-].digits[E[+-]digits] +** +** Algorithm sketch: Compute an unsigned 64-bit integer s and a base-10 +** exponent d such that the value encoding by the input is s*pow(10,d). +** Then invoke sqlite3Fp10Convert2() to calculated the closest possible +** IEEE754 double. The sign is added back afterwards, if the input string +** starts with a "-". The use of an unsigned 64-bit s mantissa means that +** only about the first 19 significant digits of the input can contribute +** to the result. This can result in suboptimal rounding decisions when +** correct rounding requires more than 19 input digits. For example, +** this routine renders "3500000000000000.2500001" as +** 3500000000000000.0 instead of 3500000000000000.5 because the decision +** to round up instead of using banker's rounding to round down is determined +** by the 23rd significant digit, which this routine ignores. It is not +** possible to do better without some kind of BigNum. +*/ +SQLITE_PRIVATE int sqlite3AtoF(const char *zIn, double *pResult){ +#ifndef SQLITE_OMIT_FLOATING_POINT + const unsigned char *z = (const unsigned char*)zIn; + int neg = 0; /* True for a negative value */ + u64 s = 0; /* mantissa */ + int d = 0; /* Value is s * pow(10,d) */ + int mState = 0; /* 1: digit seen 2: fp 4: hard-zero */ + unsigned v; /* Value of a single digit */ + + start_of_text: + if( (v = (unsigned)z[0] - '0')<10 ){ + parse_integer_part: + mState = 1; + s = v; + z++; + while( (v = (unsigned)z[0] - '0')<10 ){ + s = s*10 + v; + z++; + if( s>=(LARGEST_UINT64-9)/10 ){ + mState = 9; + while( sqlite3Isdigit(z[0]) ){ z++; d++; } + break; + } } + }else if( z[0]=='-' ){ + neg = 1; + z++; + if( (v = (unsigned)z[0] - '0')<10 ) goto parse_integer_part; + }else if( z[0]=='+' ){ + z++; + if( (v = (unsigned)z[0] - '0')<10 ) goto parse_integer_part; + }else if( sqlite3Isspace(z[0]) ){ + do{ z++; }while( sqlite3Isspace(z[0]) ); + goto start_of_text; + }else{ + s = 0; } - if( z>=zEnd ) goto do_atof_calc; /* if decimal point is present */ if( *z=='.' ){ - z+=incr; - eType++; - /* copy digits from after decimal to significand - ** (decrease exponent by d to shift decimal right) */ - while( z=zEnd ) goto do_atof_calc; /* if exponent is present */ if( *z=='e' || *z=='E' ){ - z+=incr; - eValid = 0; - eType++; - - /* This branch is needed to avoid a (harmless) buffer overread. The - ** special comment alerts the mutation tester that the correct answer - ** is obtained even if the branch is omitted */ - if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/ + int esign; + z++; /* get sign of exponent */ if( *z=='-' ){ esign = -1; - z+=incr; - }else if( *z=='+' ){ - z+=incr; + z++; + }else{ + esign = +1; + if( *z=='+' ){ + z++; + } } /* copy digits to exponent */ - while( z0 && s<(LARGEST_UINT64/10) ){ - s *= 10; - e--; - } - while( e<0 && (s%10)==0 ){ - s /= 10; - e++; - } - - rr[0] = (double)s; - s2 = (u64)rr[0]; -#if defined(_MSC_VER) && _MSC_VER<1700 - if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); } -#endif - rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); - if( e>0 ){ - while( e>=100 ){ - e -= 100; - dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); - } - while( e>=10 ){ - e -= 10; - dekkerMul2(rr, 1.0e+10, 0.0); - } - while( e>=1 ){ - e -= 1; - dekkerMul2(rr, 1.0e+01, 0.0); - } + *pResult = 0.0; + mState |= 4; }else{ - while( e<=-100 ){ - e += 100; - dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); - } - while( e<=-10 ){ - e += 10; - dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); - } - while( e<=-1 ){ - e += 1; - dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); - } + *pResult = sqlite3Fp10Convert2(s,d); } - *pResult = rr[0]+rr[1]; - if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300; - if( sign<0 ) *pResult = -*pResult; + if( neg ) *pResult = -*pResult; assert( !sqlite3IsNaN(*pResult) ); -atof_return: /* return true if number and no extra non-whitespace characters after */ - if( z==zEnd && nDigit>0 && eValid && eType>0 ){ - return eType; - }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){ - return -1; - }else{ - return 0; + if( z[0]==0 ){ + return mState; + } + if( sqlite3Isspace(z[0]) ){ + do{ z++; }while( sqlite3Isspace(*z) ); + if( z[0]==0 ){ + return mState; + } } + return 0xfffffff0 | mState; #else - return !sqlite3Atoi64(z, pResult, length, enc); + return sqlite3Atoi64(z, pResult, strlen(z), SQLITE_UTF8)==0; #endif /* SQLITE_OMIT_FLOATING_POINT */ } -#if defined(_MSC_VER) -#pragma warning(default : 4756) + +/* +** Digit pairs used to convert a U64 or I64 into text, two digits +** at a time. +*/ +static const union { + char a[201]; + short int forceAlignment; +} sqlite3DigitPairs = { + "00010203040506070809" + "10111213141516171819" + "20212223242526272829" + "30313233343536373839" + "40414243444546474849" + "50515253545556575859" + "60616263646566676869" + "70717273747576777879" + "80818283848586878889" + "90919293949596979899" +}; + +/* +** ARMv6, ARMv7, PPC32 are known to not support hardware u64 division. +*/ +#if (defined(__arm__) && !defined(__aarch64__)) || \ + (defined(__ppc__) && !defined(__ppc64__)) +# define SQLITE_AVOID_U64_DIVIDE 1 #endif +#ifdef SQLITE_AVOID_U64_DIVIDE +/* +** Render an unsigned 64-bit integer as text onto the end of a 2-byte +** aligned buffer that is SQLITE_U64_DIGIT+1 bytes long. The last byte +** of the buffer will be filled with a \000 byte. +** +** Return the index into the buffer of the first byte. +** +** This routine is used on platforms where u64-division is slow because +** it is not available in hardware and has to be emulated in software. +** It seeks to minimize the number of u64 divisions and use u32 divisions +** instead. It is slower on platforms that have hardware u64 division, +** but much faster on platforms that do not. +*/ +static int sqlite3UInt64ToText(u64 v, char *zOut){ + u32 x32, kk; + int i; + zOut[SQLITE_U64_DIGITS] = 0; + i = SQLITE_U64_DIGITS; + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[0]) ); + assert( TWO_BYTE_ALIGNMENT(zOut) ); + while( (v>>32)!=0 ){ + u32 y, x0, x1, y0, y1; + x32 = v % 100000000; + v = v / 100000000; + y = x32 % 10000; + x32 /= 10000; + x1 = x32 / 100; + x0 = x32 % 100; + y1 = y / 100; + y0 = y % 100; + assert( i>=8 ); + i -= 8; + *(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[x1*2]; + *(u16*)(&zOut[i+2]) = *(u16*)&sqlite3DigitPairs.a[x0*2]; + *(u16*)(&zOut[i+4]) = *(u16*)&sqlite3DigitPairs.a[y1*2]; + *(u16*)(&zOut[i+6]) = *(u16*)&sqlite3DigitPairs.a[y0*2]; + } + x32 = v; + while( x32>=10 ){ + kk = x32 % 100; + x32 = x32 / 100; + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk*2]) ); + assert( i>=2 ); + i -= 2; + assert( TWO_BYTE_ALIGNMENT(&zOut[i]) ); + *(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[kk*2]; + } + if( x32 ){ + assert( i>0 ); + zOut[--i] = x32 + '0'; + } + return i; +} +#endif /* defined(SQLITE_AVOID_U64_DIVIDE) */ + /* ** Render an signed 64-bit integer as text. Store the result in zOut[] and ** return the length of the string that was stored, in bytes. The value @@ -36019,23 +37629,39 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en SQLITE_PRIVATE int sqlite3Int64ToText(i64 v, char *zOut){ int i; u64 x; - char zTemp[22]; - if( v<0 ){ - x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v; - }else{ + union { + char a[SQLITE_U64_DIGITS+1]; + u16 forceAlignment; + } u; + if( v>0 ){ x = v; + }else if( v==0 ){ + zOut[0] = '0'; + zOut[1] = 0; + return 1; + }else{ + x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v; } - i = sizeof(zTemp)-2; - zTemp[sizeof(zTemp)-1] = 0; - while( 1 /*exit-by-break*/ ){ - zTemp[i] = (x%10) + '0'; - x = x/10; - if( x==0 ) break; - i--; - }; - if( v<0 ) zTemp[--i] = '-'; - memcpy(zOut, &zTemp[i], sizeof(zTemp)-i); - return sizeof(zTemp)-1-i; +#ifdef SQLITE_AVOID_U64_DIVIDE + i = sqlite3UInt64ToText(x, u.a); +#else + i = sizeof(u.a)-1; + u.a[i] = 0; + while( x>=10 ){ + int kk = (x%100)*2; + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk]) ); + assert( TWO_BYTE_ALIGNMENT(&u.a[i-2]) ); + *(u16*)(&u.a[i-2]) = *(u16*)&sqlite3DigitPairs.a[kk]; + i -= 2; + x /= 100; + } + if( x ){ + u.a[--i] = x + '0'; + } +#endif /* SQLITE_AVOID_U64_DIVIDE */ + if( v<0 ) u.a[--i] = '-'; + memcpy(zOut, &u.a[i], sizeof(u.a)-i); + return sizeof(u.a)-1-i; } /* @@ -36089,8 +37715,8 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc int incr; u64 u = 0; int neg = 0; /* assume positive */ - int i; - int c = 0; + int i, j; + unsigned int c = 0; int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ int rc; /* Baseline return code */ const char *zStart; @@ -36118,8 +37744,8 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc } zStart = zNum; while( zNum='0' && c<='9'; i+=incr){ - u = u*10 + c - '0'; + for(i=0; &zNum[i]19*incr ? 1 : compare2pow63(zNum, incr); - if( c<0 ){ + j = i>19*incr ? 1 : compare2pow63(zNum, incr); + if( j<0 ){ /* zNum is less than 9223372036854775808 so it fits */ assert( u<=LARGEST_INT64 ); return rc; }else{ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; - if( c>0 ){ + if( j>0 ){ /* zNum is greater than 9223372036854775808 so it overflows */ return 2; }else{ @@ -36292,7 +37918,7 @@ SQLITE_PRIVATE int sqlite3Atoi(const char *z){ ** representation. ** ** If iRound<=0 then round to -iRound significant digits to the -** the left of the decimal point, or to a maximum of mxRound total +** the right of the decimal point, or to a maximum of mxRound total ** significant digits. ** ** If iRound>0 round to min(iRound,mxRound) significant digits total. @@ -36305,13 +37931,14 @@ SQLITE_PRIVATE int sqlite3Atoi(const char *z){ ** The p->z[] array is *not* zero-terminated. */ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ - int i; - u64 v; - int e, exp = 0; - double rr[2]; + int i; /* Index into zBuf[] where to put next character */ + int n; /* Number of digits */ + u64 v; /* mantissa */ + int e, exp = 0; /* Base-2 and base-10 exponent */ + char *zBuf; /* Local alias for p->zBuf */ + char *z; /* Local alias for p->z */ p->isSpecial = 0; - p->z = p->zBuf; assert( mxRound>0 ); /* Convert negative numbers to positive. Deal with Infinity, 0.0, and @@ -36329,78 +37956,100 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou p->sign = '+'; } memcpy(&v,&r,8); - e = v>>52; - if( (e&0x7ff)==0x7ff ){ + e = (v>>52)&0x7ff; + if( e==0x7ff ){ p->isSpecial = 1 + (v!=0x7ff0000000000000LL); p->n = 0; p->iDP = 0; + p->z = p->zBuf; return; } - - /* Multiply r by powers of ten until it lands somewhere in between - ** 1.0e+19 and 1.0e+17. - ** - ** Use Dekker-style double-double computation to increase the - ** precision. - ** - ** The error terms on constants like 1.0e+100 computed using the - ** decimal extension, for example as follows: - ** - ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100))); - */ - rr[0] = r; - rr[1] = 0.0; - if( rr[0]>9.223372036854774784e+18 ){ - while( rr[0]>9.223372036854774784e+118 ){ - exp += 100; - dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); - } - while( rr[0]>9.223372036854774784e+28 ){ - exp += 10; - dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); - } - while( rr[0]>9.223372036854774784e+18 ){ - exp += 1; - dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); - } + v &= 0x000fffffffffffffULL; + if( e==0 ){ + int nn = countLeadingZeros(v); + v <<= nn; + e = -1074 - nn; }else{ - while( rr[0]<9.223372036854774784e-83 ){ - exp -= 100; - dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); - } - while( rr[0]<9.223372036854774784e+07 ){ - exp -= 10; - dekkerMul2(rr, 1.0e+10, 0.0); - } - while( rr[0]<9.22337203685477478e+17 ){ - exp -= 1; - dekkerMul2(rr, 1.0e+01, 0.0); - } + v = (v<<11) | U64_BIT(63); + e -= 1086; } - v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1]; + sqlite3Fp2Convert10(v, e, (iRound<=0||iRound>=18)?18:iRound+1, &v, &exp); - /* Extract significant digits. */ - i = sizeof(p->zBuf)-1; + /* Extract significant digits, start at the right-most slot in p->zBuf + ** and working back to the right. "i" keeps track of the next slot in + ** which to store a digit. */ + assert( sizeof(p->zBuf)==SQLITE_U64_DIGITS+1 ); assert( v>0 ); - while( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; } - assert( i>=0 && izBuf)-1 ); - p->n = sizeof(p->zBuf) - 1 - i; - assert( p->n>0 ); - assert( p->nzBuf) ); - p->iDP = p->n + exp; + zBuf = p->zBuf; +#ifdef SQLITE_AVOID_U64_DIVIDE + i = sqlite3UInt64ToText(v, zBuf); +#else + i = SQLITE_U64_DIGITS; + while( v>=10 ){ + int kk = (v%100)*2; + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk]) ); + assert( TWO_BYTE_ALIGNMENT(&zBuf[i]) ); + assert( i-2>=0 ); + *(u16*)(&zBuf[i-2]) = *(u16*)&sqlite3DigitPairs.a[kk]; + i -= 2; + v /= 100; + } + if( v ){ + assert( v<10 ); + assert( i>0 ); + zBuf[--i] = v + '0'; + } +#endif /* SQLITE_AVOID_U64_DIVIDE */ + assert( i>=0 && i0 ); + assert( n<=SQLITE_U64_DIGITS ); + p->iDP = n + exp; if( iRound<=0 ){ iRound = p->iDP - iRound; - if( iRound==0 && p->zBuf[i+1]>='5' ){ + if( iRound==0 && zBuf[i]>='5' ){ iRound = 1; - p->zBuf[i--] = '0'; - p->n++; + zBuf[--i] = '0'; + n++; p->iDP++; } } - if( iRound>0 && (iRoundn || p->n>mxRound) ){ - char *z = &p->zBuf[i+1]; + z = &zBuf[i]; /* z points to the first digit */ + if( iRound>0 && (iRoundmxRound) ){ if( iRound>mxRound ) iRound = mxRound; - p->n = iRound; + if( iRound==17 ){ + /* If the precision is exactly 17, which only happens with the "!" + ** flag (ex: "%!.17g") then try to reduce the precision if that + ** yields text that will round-trip to the original floating-point. + ** value. Thus, for exaple, 49.47 will render as 49.47, rather than + ** as 49.469999999999999. */ + if( z[15]=='9' && z[14]=='9' ){ + int jj, kk; + u64 v2; + for(jj=14; jj>0 && z[jj-1]=='9'; jj--){} + if( jj==0 ){ + v2 = 1; + }else{ + v2 = z[0] - '0'; + for(kk=1; kkiDP>=n || (z[15]=='0' && z[14]=='0' && z[13]=='0') ){ + int jj, kk; + u64 v2; + assert( z[0]!='0' ); + for(jj=13; z[jj-1]=='0'; jj--){} + v2 = z[0] - '0'; + for(kk=1; kk='5' ){ int j = iRound-1; while( 1 /*exit-by-break*/ ){ @@ -36408,8 +38057,9 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou if( z[j]<='9' ) break; z[j] = '0'; if( j==0 ){ - p->z[i--] = '1'; - p->n++; + z--; + z[0] = '1'; + n++; p->iDP++; break; }else{ @@ -36418,9 +38068,13 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou } } } - p->z = &p->zBuf[i+1]; - assert( i+p->n < sizeof(p->zBuf) ); - while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; } + assert( n>0 ); + while( z[n-1]=='0' ){ + n--; + assert( n>0 ); + } + p->n = n; + p->z = z; } /* @@ -36925,7 +38579,7 @@ SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){ } /* -** Compute the absolute value of a 32-bit signed integer, of possible. Or +** Compute the absolute value of a 32-bit signed integer, if possible. Or ** if the integer has a value of -2147483648, return +2147483647 */ SQLITE_PRIVATE int sqlite3AbsInt32(int x){ @@ -37206,12 +38860,19 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){ */ static unsigned int strHash(const char *z){ unsigned int h = 0; - unsigned char c; - while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/ + while( z[0] ){ /*OPTIMIZATION-IF-TRUE*/ /* Knuth multiplicative hashing. (Sorting & Searching, p. 510). ** 0x9e3779b1 is 2654435761 which is the closest prime number to - ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */ - h += sqlite3UpperToLower[c]; + ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. + ** + ** Only bits 0xdf for ASCII and bits 0xbf for EBCDIC each octet are + ** hashed since the omitted bits determine the upper/lower case difference. + */ +#ifdef SQLITE_EBCDIC + h += 0xbf & (unsigned char)*(z++); +#else + h += 0xdf & (unsigned char)*(z++); +#endif h *= 0x9e3779b1; } return h; @@ -37284,9 +38945,8 @@ static int rehash(Hash *pH, unsigned int new_size){ pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht); memset(new_ht, 0, new_size*sizeof(struct _ht)); for(elem=pH->first, pH->first=0; elem; elem = next_elem){ - unsigned int h = strHash(elem->pKey) % new_size; next_elem = elem->next; - insertElement(pH, &new_ht[h], elem); + insertElement(pH, &new_ht[elem->h % new_size], elem); } return 1; } @@ -37304,23 +38964,22 @@ static HashElem *findElementWithHash( HashElem *elem; /* Used to loop thru the element list */ unsigned int count; /* Number of elements left to test */ unsigned int h; /* The computed hash */ - static HashElem nullElement = { 0, 0, 0, 0 }; + static HashElem nullElement = { 0, 0, 0, 0, 0 }; + h = strHash(pKey); if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/ struct _ht *pEntry; - h = strHash(pKey) % pH->htsize; - pEntry = &pH->ht[h]; + pEntry = &pH->ht[h % pH->htsize]; elem = pEntry->chain; count = pEntry->count; }else{ - h = 0; elem = pH->first; count = pH->count; } if( pHash ) *pHash = h; while( count ){ assert( elem!=0 ); - if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ + if( h==elem->h && sqlite3StrICmp(elem->pKey,pKey)==0 ){ return elem; } elem = elem->next; @@ -37332,10 +38991,9 @@ static HashElem *findElementWithHash( /* Remove a single entry from the hash table given a pointer to that ** element and a hash on the element's key. */ -static void removeElementGivenHash( +static void removeElement( Hash *pH, /* The pH containing "elem" */ - HashElem* elem, /* The element to be removed from the pH */ - unsigned int h /* Hash value for the element */ + HashElem *elem /* The element to be removed from the pH */ ){ struct _ht *pEntry; if( elem->prev ){ @@ -37347,7 +39005,7 @@ static void removeElementGivenHash( elem->next->prev = elem->prev; } if( pH->ht ){ - pEntry = &pH->ht[h]; + pEntry = &pH->ht[elem->h % pH->htsize]; if( pEntry->chain==elem ){ pEntry->chain = elem->next; } @@ -37398,7 +39056,7 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ if( elem->data ){ void *old_data = elem->data; if( data==0 ){ - removeElementGivenHash(pH,elem,h); + removeElement(pH,elem); }else{ elem->data = data; elem->pKey = pKey; @@ -37409,18 +39067,17 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) ); if( new_elem==0 ) return data; new_elem->pKey = pKey; + new_elem->h = h; new_elem->data = data; pH->count++; - if( pH->count>=10 && pH->count > 2*pH->htsize ){ - if( rehash(pH, pH->count*2) ){ - assert( pH->htsize>0 ); - h = strHash(pKey) % pH->htsize; - } + if( pH->count>=5 && pH->count > 2*pH->htsize ){ + rehash(pH, pH->count*3); } - insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem); + insertElement(pH, pH->ht ? &pH->ht[new_elem->h % pH->htsize] : 0, new_elem); return 0; } + /************** End of hash.c ************************************************/ /************** Begin file opcodes.c *****************************************/ /* Automatically generated. Do not edit */ @@ -37472,20 +39129,20 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 34 */ "SorterSort" OpHelp(""), /* 35 */ "Sort" OpHelp(""), /* 36 */ "Rewind" OpHelp(""), - /* 37 */ "SorterNext" OpHelp(""), - /* 38 */ "Prev" OpHelp(""), - /* 39 */ "Next" OpHelp(""), - /* 40 */ "IdxLE" OpHelp("key=r[P3@P4]"), - /* 41 */ "IdxGT" OpHelp("key=r[P3@P4]"), - /* 42 */ "IdxLT" OpHelp("key=r[P3@P4]"), + /* 37 */ "IfEmpty" OpHelp("if( empty(P1) ) goto P2"), + /* 38 */ "SorterNext" OpHelp(""), + /* 39 */ "Prev" OpHelp(""), + /* 40 */ "Next" OpHelp(""), + /* 41 */ "IdxLE" OpHelp("key=r[P3@P4]"), + /* 42 */ "IdxGT" OpHelp("key=r[P3@P4]"), /* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), /* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), - /* 45 */ "IdxGE" OpHelp("key=r[P3@P4]"), - /* 46 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), - /* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), - /* 48 */ "Program" OpHelp(""), - /* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), - /* 50 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), + /* 45 */ "IdxLT" OpHelp("key=r[P3@P4]"), + /* 46 */ "IdxGE" OpHelp("key=r[P3@P4]"), + /* 47 */ "IFindKey" OpHelp(""), + /* 48 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 49 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), + /* 50 */ "Program" OpHelp(""), /* 51 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), /* 52 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), /* 53 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), @@ -37495,49 +39152,49 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 57 */ "Lt" OpHelp("IF r[P3]=r[P1]"), /* 59 */ "ElseEq" OpHelp(""), - /* 60 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), - /* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), - /* 62 */ "IncrVacuum" OpHelp(""), - /* 63 */ "VNext" OpHelp(""), - /* 64 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"), - /* 65 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"), - /* 66 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"), - /* 67 */ "Return" OpHelp(""), - /* 68 */ "EndCoroutine" OpHelp(""), - /* 69 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), - /* 70 */ "Halt" OpHelp(""), - /* 71 */ "Integer" OpHelp("r[P2]=P1"), - /* 72 */ "Int64" OpHelp("r[P2]=P4"), - /* 73 */ "String" OpHelp("r[P2]='P4' (len=P1)"), - /* 74 */ "BeginSubrtn" OpHelp("r[P2]=NULL"), - /* 75 */ "Null" OpHelp("r[P2..P3]=NULL"), - /* 76 */ "SoftNull" OpHelp("r[P1]=NULL"), - /* 77 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), - /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1)"), - /* 79 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), - /* 80 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 81 */ "SCopy" OpHelp("r[P2]=r[P1]"), - /* 82 */ "IntCopy" OpHelp("r[P2]=r[P1]"), - /* 83 */ "FkCheck" OpHelp(""), - /* 84 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 85 */ "CollSeq" OpHelp(""), - /* 86 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), - /* 87 */ "RealAffinity" OpHelp(""), - /* 88 */ "Cast" OpHelp("affinity(r[P1])"), - /* 89 */ "Permutation" OpHelp(""), - /* 90 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 91 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), - /* 92 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"), - /* 93 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), - /* 94 */ "Column" OpHelp("r[P3]=PX cursor P1 column P2"), - /* 95 */ "TypeCheck" OpHelp("typecheck(r[P1@P2])"), - /* 96 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 97 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 98 */ "Count" OpHelp("r[P2]=count()"), - /* 99 */ "ReadCookie" OpHelp(""), - /* 100 */ "SetCookie" OpHelp(""), - /* 101 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), - /* 102 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 60 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 61 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), + /* 62 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), + /* 63 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), + /* 64 */ "IncrVacuum" OpHelp(""), + /* 65 */ "VNext" OpHelp(""), + /* 66 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"), + /* 67 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"), + /* 68 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"), + /* 69 */ "Return" OpHelp(""), + /* 70 */ "EndCoroutine" OpHelp(""), + /* 71 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), + /* 72 */ "Halt" OpHelp(""), + /* 73 */ "Integer" OpHelp("r[P2]=P1"), + /* 74 */ "Int64" OpHelp("r[P2]=P4"), + /* 75 */ "String" OpHelp("r[P2]='P4' (len=P1)"), + /* 76 */ "BeginSubrtn" OpHelp("r[P2]=NULL"), + /* 77 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 78 */ "SoftNull" OpHelp("r[P1]=NULL"), + /* 79 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), + /* 80 */ "Variable" OpHelp("r[P2]=parameter(P1)"), + /* 81 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 82 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 83 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 84 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 85 */ "FkCheck" OpHelp(""), + /* 86 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 87 */ "CollSeq" OpHelp(""), + /* 88 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 89 */ "RealAffinity" OpHelp(""), + /* 90 */ "Cast" OpHelp("affinity(r[P1])"), + /* 91 */ "Permutation" OpHelp(""), + /* 92 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 93 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), + /* 94 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"), + /* 95 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), + /* 96 */ "Column" OpHelp("r[P3]=PX cursor P1 column P2"), + /* 97 */ "TypeCheck" OpHelp("typecheck(r[P1@P2])"), + /* 98 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 99 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 100 */ "Count" OpHelp("r[P2]=count()"), + /* 101 */ "ReadCookie" OpHelp(""), + /* 102 */ "SetCookie" OpHelp(""), /* 103 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), /* 104 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), /* 105 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 161 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), - /* 162 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 163 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 164 */ "AggValue" OpHelp("r[P3]=value N=P2"), - /* 165 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 166 */ "Expire" OpHelp(""), - /* 167 */ "CursorLock" OpHelp(""), - /* 168 */ "CursorUnlock" OpHelp(""), - /* 169 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 170 */ "VBegin" OpHelp(""), - /* 171 */ "VCreate" OpHelp(""), - /* 172 */ "VDestroy" OpHelp(""), - /* 173 */ "VOpen" OpHelp(""), - /* 174 */ "VCheck" OpHelp(""), - /* 175 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"), - /* 176 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 177 */ "VRename" OpHelp(""), - /* 178 */ "Pagecount" OpHelp(""), - /* 179 */ "MaxPgcnt" OpHelp(""), - /* 180 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), - /* 181 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"), - /* 182 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"), - /* 183 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), - /* 184 */ "Trace" OpHelp(""), - /* 185 */ "CursorHint" OpHelp(""), - /* 186 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), - /* 187 */ "Noop" OpHelp(""), - /* 188 */ "Explain" OpHelp(""), - /* 189 */ "Abortable" OpHelp(""), + /* 155 */ "DropIndex" OpHelp(""), + /* 156 */ "DropTrigger" OpHelp(""), + /* 157 */ "IntegrityCk" OpHelp(""), + /* 158 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 159 */ "Param" OpHelp(""), + /* 160 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 161 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 162 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 163 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), + /* 164 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 165 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 166 */ "AggValue" OpHelp("r[P3]=value N=P2"), + /* 167 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 168 */ "Expire" OpHelp(""), + /* 169 */ "CursorLock" OpHelp(""), + /* 170 */ "CursorUnlock" OpHelp(""), + /* 171 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 172 */ "VBegin" OpHelp(""), + /* 173 */ "VCreate" OpHelp(""), + /* 174 */ "VDestroy" OpHelp(""), + /* 175 */ "VOpen" OpHelp(""), + /* 176 */ "VCheck" OpHelp(""), + /* 177 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"), + /* 178 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 179 */ "VRename" OpHelp(""), + /* 180 */ "Pagecount" OpHelp(""), + /* 181 */ "MaxPgcnt" OpHelp(""), + /* 182 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), + /* 183 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"), + /* 184 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"), + /* 185 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), + /* 186 */ "Trace" OpHelp(""), + /* 187 */ "CursorHint" OpHelp(""), + /* 188 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), + /* 189 */ "Noop" OpHelp(""), + /* 190 */ "Explain" OpHelp(""), + /* 191 */ "Abortable" OpHelp(""), }; return azName[i]; } @@ -37655,7 +39314,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ ** Debugging logic */ -/* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */ +/* SQLITE_KV_TRACE() is used for tracing calls to kvrecord routines. */ #if 0 #define SQLITE_KV_TRACE(X) printf X #else @@ -37669,7 +39328,6 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #define SQLITE_KV_LOG(X) #endif - /* ** Forward declaration of objects used by this VFS implementation */ @@ -37677,6 +39335,11 @@ typedef struct KVVfsFile KVVfsFile; /* A single open file. There are only two files represented by this ** VFS - the database and the rollback journal. +** +** Maintenance reminder: if this struct changes in any way, the JSON +** rendering of its structure must be updated in +** sqlite3-wasm.c:sqlite3__wasm_enum_json(). There are no binary +** compatibility concerns, so it does not need an iVersion member. */ struct KVVfsFile { sqlite3_file base; /* IO methods */ @@ -37726,7 +39389,7 @@ static int kvvfsCurrentTime(sqlite3_vfs*, double*); static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); static sqlite3_vfs sqlite3OsKvvfsObject = { - 1, /* iVersion */ + 2, /* iVersion */ sizeof(KVVfsFile), /* szOsFile */ 1024, /* mxPathname */ 0, /* pNext */ @@ -37802,23 +39465,37 @@ static sqlite3_io_methods kvvfs_jrnl_io_methods = { /* Forward declarations for the low-level storage engine */ -static int kvstorageWrite(const char*, const char *zKey, const char *zData); -static int kvstorageDelete(const char*, const char *zKey); -static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf); -#define KVSTORAGE_KEY_SZ 32 +#ifndef SQLITE_WASM +/* In WASM builds these are implemented in JS. */ +static int kvrecordWrite(const char*, const char *zKey, const char *zData); +static int kvrecordDelete(const char*, const char *zKey); +static int kvrecordRead(const char*, const char *zKey, char *zBuf, int nBuf); +#endif +#ifndef KVRECORD_KEY_SZ +#define KVRECORD_KEY_SZ 32 +#endif /* Expand the key name with an appropriate prefix and put the result -** zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least -** KVSTORAGE_KEY_SZ bytes. +** in zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least +** KVRECORD_KEY_SZ bytes. */ -static void kvstorageMakeKey( +static void kvrecordMakeKey( const char *zClass, const char *zKeyIn, char *zKeyOut ){ - sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn); + assert( zKeyIn ); + assert( zKeyOut ); + assert( zClass ); + sqlite3_snprintf(KVRECORD_KEY_SZ, zKeyOut, "kvvfs-%s-%s", + zClass, zKeyIn); } +#ifndef SQLITE_WASM +/* In WASM builds do not define APIs which use fopen(), fwrite(), +** and the like because those APIs are a portability issue for +** WASM. +*/ /* Write content into a key. zClass is the particular namespace of the ** underlying key/value store to use - either "local" or "session". ** @@ -37826,14 +39503,14 @@ static void kvstorageMakeKey( ** ** Return the number of errors. */ -static int kvstorageWrite( +static int kvrecordWrite( const char *zClass, const char *zKey, const char *zData ){ FILE *fd; - char zXKey[KVSTORAGE_KEY_SZ]; - kvstorageMakeKey(zClass, zKey, zXKey); + char zXKey[KVRECORD_KEY_SZ]; + kvrecordMakeKey(zClass, zKey, zXKey); fd = fopen(zXKey, "wb"); if( fd ){ SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey, @@ -37851,9 +39528,9 @@ static int kvstorageWrite( ** namespace given by zClass. If the key does not previously exist, ** this routine is a no-op. */ -static int kvstorageDelete(const char *zClass, const char *zKey){ - char zXKey[KVSTORAGE_KEY_SZ]; - kvstorageMakeKey(zClass, zKey, zXKey); +static int kvrecordDelete(const char *zClass, const char *zKey){ + char zXKey[KVRECORD_KEY_SZ]; + kvrecordMakeKey(zClass, zKey, zXKey); unlink(zXKey); SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey)); return 0; @@ -37867,12 +39544,14 @@ static int kvstorageDelete(const char *zClass, const char *zKey){ ** ** Return the total number of bytes in the data, without truncation, and ** not counting the final zero terminator. Return -1 if the key does -** not exist. +** not exist or its key cannot be read. ** -** If nBuf<=0 then this routine simply returns the size of the data without -** actually reading it. +** If nBuf<=0 then this routine simply returns the size of the data +** without actually reading it. Similarly, if nBuf==1 then it +** zero-terminates zBuf at zBuf[0] and returns the size of the data +** without reading it. */ -static int kvstorageRead( +static int kvrecordRead( const char *zClass, const char *zKey, char *zBuf, @@ -37880,8 +39559,8 @@ static int kvstorageRead( ){ FILE *fd; struct stat buf; - char zXKey[KVSTORAGE_KEY_SZ]; - kvstorageMakeKey(zClass, zKey, zXKey); + char zXKey[KVRECORD_KEY_SZ]; + kvrecordMakeKey(zClass, zKey, zXKey); if( access(zXKey, R_OK)!=0 || stat(zXKey, &buf)!=0 || !S_ISREG(buf.st_mode) @@ -37913,26 +39592,36 @@ static int kvstorageRead( return (int)n; } } +#endif /* #ifndef SQLITE_WASM */ + /* ** An internal level of indirection which enables us to replace the ** kvvfs i/o methods with JavaScript implementations in WASM builds. ** Maintenance reminder: if this struct changes in any way, the JSON ** rendering of its structure must be updated in -** sqlite3_wasm_enum_json(). There are no binary compatibility -** concerns, so it does not need an iVersion member. This file is -** necessarily always compiled together with sqlite3_wasm_enum_json(), -** and JS code dynamically creates the mapping of members based on -** that JSON description. +** sqlite3-wasm.c:sqlite3__wasm_enum_json(). There are no binary +** compatibility concerns, so it does not need an iVersion member. */ typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods; struct sqlite3_kvvfs_methods { - int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf); - int (*xWrite)(const char *zClass, const char *zKey, const char *zData); - int (*xDelete)(const char *zClass, const char *zKey); + int (*xRcrdRead)(const char*, const char *zKey, char *zBuf, int nBuf); + int (*xRcrdWrite)(const char*, const char *zKey, const char *zData); + int (*xRcrdDelete)(const char*, const char *zKey); const int nKeySize; + const int nBufferSize; +#ifndef SQLITE_WASM +# define MAYBE_CONST const +#else +# define MAYBE_CONST +#endif + MAYBE_CONST sqlite3_vfs * pVfs; + MAYBE_CONST sqlite3_io_methods *pIoDb; + MAYBE_CONST sqlite3_io_methods *pIoJrnl; +#undef MAYBE_CONST }; + /* ** This object holds the kvvfs I/O methods which may be swapped out ** for JavaScript-side implementations in WASM builds. In such builds @@ -37940,17 +39629,27 @@ struct sqlite3_kvvfs_methods { ** the compiler can hopefully optimize this level of indirection out. ** That said, kvvfs is intended primarily for use in WASM builds. ** -** Note that this is not explicitly flagged as static because the -** amalgamation build will tag it with SQLITE_PRIVATE. +** This is not explicitly flagged as static because the amalgamation +** build will tag it with SQLITE_PRIVATE. */ #ifndef SQLITE_WASM const #endif SQLITE_PRIVATE sqlite3_kvvfs_methods sqlite3KvvfsMethods = { -kvstorageRead, -kvstorageWrite, -kvstorageDelete, -KVSTORAGE_KEY_SZ +#ifndef SQLITE_WASM + .xRcrdRead = kvrecordRead, + .xRcrdWrite = kvrecordWrite, + .xRcrdDelete = kvrecordDelete, +#else + .xRcrdRead = 0, + .xRcrdWrite = 0, + .xRcrdDelete = 0, +#endif + .nKeySize = KVRECORD_KEY_SZ, + .nBufferSize = SQLITE_KVOS_SZ, + .pVfs = &sqlite3OsKvvfsObject, + .pIoDb = &kvvfs_db_io_methods, + .pIoJrnl = &kvvfs_jrnl_io_methods }; /****** Utility subroutines ************************************************/ @@ -37977,7 +39676,10 @@ KVSTORAGE_KEY_SZ ** of hexadecimal and base-26 numbers, it is always clear where ** one stops and the next begins. */ -static int kvvfsEncode(const char *aData, int nData, char *aOut){ +#ifndef SQLITE_WASM +static +#endif +int kvvfsEncode(const char *aData, int nData, char *aOut){ int i, j; const unsigned char *a = (const unsigned char*)aData; for(i=j=0; i='a' && c<='z' ){ n += (c - 'a')*mult; + if( n>nOut ) return -1 /* oversized/malformed input */; mult *= 26; c = aIn[++i]; } - if( j+n>nOut ) return -1; + if( j+n>nOut ) return -1 /* oversized/malformed input */; memset(&aOut[j], 0, n); j += n; if( c==0 || mult==1 ) break; /* progress stalled if mult==1 */ }else{ aOut[j] = c<<4; c = kvvfsHexValue[aIn[++i]]; - if( c<0 ) break; + if( c<0 ) return -1 /* hex bytes are always in pairs */; aOut[j++] += c; i++; } @@ -38084,7 +39791,7 @@ static void kvvfsDecodeJournal( i = 0; mult = 1; while( (c = zTxt[i++])>='a' && c<='z' ){ - n += (zTxt[i] - 'a')*mult; + n += (c - 'a')*mult; mult *= 26; } sqlite3_free(pFile->aJrnl); @@ -38108,13 +39815,14 @@ static void kvvfsDecodeJournal( static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){ char zData[50]; zData[0] = 0; - sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1); + sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, "sz", zData, + sizeof(zData)-1); return strtoll(zData, 0, 0); } static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){ char zData[50]; sqlite3_snprintf(sizeof(zData), zData, "%lld", sz); - return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData); + return sqlite3KvvfsMethods.xRcrdWrite(pFile->zClass, "sz", zData); } /****** sqlite3_io_methods methods ******************************************/ @@ -38129,6 +39837,7 @@ static int kvvfsClose(sqlite3_file *pProtoFile){ pFile->isJournal ? "journal" : "db")); sqlite3_free(pFile->aJrnl); sqlite3_free(pFile->aData); + memset(pFile, 0, sizeof(*pFile)); return SQLITE_OK; } @@ -38145,16 +39854,23 @@ static int kvvfsReadJrnl( assert( pFile->isJournal ); SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); if( pFile->aJrnl==0 ){ - int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0); + int rc; + int szTxt = sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, "jrnl", + 0, 0); char *aTxt; if( szTxt<=4 ){ return SQLITE_IOERR; } aTxt = sqlite3_malloc64( szTxt+1 ); if( aTxt==0 ) return SQLITE_NOMEM; - kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1); - kvvfsDecodeJournal(pFile, aTxt, szTxt); + rc = sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, "jrnl", + aTxt, szTxt+1); + if( rc>=0 ){ + kvvfsDecodeJournal(pFile, aTxt, szTxt); + rc = 0; + } sqlite3_free(aTxt); + if( rc ) return rc; if( pFile->aJrnl==0 ) return SQLITE_IOERR; } if( iOfst+iAmt>pFile->nJrnl ){ @@ -38194,8 +39910,8 @@ static int kvvfsReadDb( pgno = 1; } sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); - got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey, - aData, SQLITE_KVOS_SZ-1); + got = sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, zKey, + aData, SQLITE_KVOS_SZ-1); if( got<0 ){ n = 0; }else{ @@ -38263,6 +39979,7 @@ static int kvvfsWriteDb( unsigned int pgno; char zKey[30]; char *aData = pFile->aData; + int rc; SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); assert( iAmt>=512 && iAmt<=65536 ); assert( (iAmt & (iAmt-1))==0 ); @@ -38271,13 +39988,13 @@ static int kvvfsWriteDb( pgno = 1 + iOfst/iAmt; sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); kvvfsEncode(zBuf, iAmt, aData); - if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){ - return SQLITE_IOERR; - } - if( iOfst+iAmt > pFile->szDb ){ - pFile->szDb = iOfst + iAmt; + rc = sqlite3KvvfsMethods.xRcrdWrite(pFile->zClass, zKey, aData); + if( 0==rc ){ + if( iOfst+iAmt > pFile->szDb ){ + pFile->szDb = iOfst + iAmt; + } } - return SQLITE_OK; + return rc; } /* @@ -38287,7 +40004,7 @@ static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){ KVVfsFile *pFile = (KVVfsFile *)pProtoFile; SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size)); assert( size==0 ); - sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl"); + sqlite3KvvfsMethods.xRcrdDelete(pFile->zClass, "jrnl"); sqlite3_free(pFile->aJrnl); pFile->aJrnl = 0; pFile->nJrnl = 0; @@ -38306,7 +40023,7 @@ static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){ pgnoMax = 2 + pFile->szDb/pFile->szPage; while( pgno<=pgnoMax ){ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); - sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey); + sqlite3KvvfsMethods.xRcrdDelete(pFile->zClass, zKey); pgno++; } pFile->szDb = size; @@ -38338,7 +40055,7 @@ static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){ }while( n>0 ); zOut[i++] = ' '; kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]); - i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut); + i = sqlite3KvvfsMethods.xRcrdWrite(pFile->zClass, "jrnl", zOut); sqlite3_free(zOut); return i ? SQLITE_IOERR : SQLITE_OK; } @@ -38452,33 +40169,32 @@ static int kvvfsOpen( KVVfsFile *pFile = (KVVfsFile*)pProtoFile; if( zName==0 ) zName = ""; SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName)); - if( strcmp(zName, "local")==0 - || strcmp(zName, "session")==0 - ){ - pFile->isJournal = 0; - pFile->base.pMethods = &kvvfs_db_io_methods; - }else - if( strcmp(zName, "local-journal")==0 - || strcmp(zName, "session-journal")==0 - ){ + assert(!pFile->zClass); + assert(!pFile->aData); + assert(!pFile->aJrnl); + assert(!pFile->nJrnl); + assert(!pFile->base.pMethods); + pFile->szPage = -1; + pFile->szDb = -1; + if( 0==sqlite3_strglob("*-journal", zName) ){ pFile->isJournal = 1; pFile->base.pMethods = &kvvfs_jrnl_io_methods; + if( 0==strcmp("session-journal",zName) ){ + pFile->zClass = "session"; + }else if( 0==strcmp("local-journal",zName) ){ + pFile->zClass = "local"; + } }else{ - return SQLITE_CANTOPEN; + pFile->isJournal = 0; + pFile->base.pMethods = &kvvfs_db_io_methods; } - if( zName[0]=='s' ){ - pFile->zClass = "session"; - }else{ - pFile->zClass = "local"; + if( !pFile->zClass ){ + pFile->zClass = zName; } pFile->aData = sqlite3_malloc64(SQLITE_KVOS_SZ); if( pFile->aData==0 ){ return SQLITE_NOMEM; } - pFile->aJrnl = 0; - pFile->nJrnl = 0; - pFile->szPage = -1; - pFile->szDb = -1; return SQLITE_OK; } @@ -38488,13 +40204,17 @@ static int kvvfsOpen( ** returning. */ static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ + int rc /* The JS impl can fail with OOM in argument conversion */; if( strcmp(zPath, "local-journal")==0 ){ - sqlite3KvvfsMethods.xDelete("local", "jrnl"); + rc = sqlite3KvvfsMethods.xRcrdDelete("local", "jrnl"); }else if( strcmp(zPath, "session-journal")==0 ){ - sqlite3KvvfsMethods.xDelete("session", "jrnl"); + rc = sqlite3KvvfsMethods.xRcrdDelete("session", "jrnl"); } - return SQLITE_OK; + else{ + rc = 0; + } + return rc; } /* @@ -38508,21 +40228,42 @@ static int kvvfsAccess( int *pResOut ){ SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath)); +#if 0 && defined(SQLITE_WASM) + /* + ** This is not having the desired effect in the JS bindings. + ** It's ostensibly the same logic as the #else block, but + ** it's not behaving that way. + ** + ** In JS we map all zPaths to Storage objects, and -journal files + ** are mapped to the storage for the main db (which is is exactly + ** what the mapping of "local-journal" -> "local" is doing). + */ + const char *zKey = (0==sqlite3_strglob("*-journal", zPath)) + ? "jrnl" : "sz"; + *pResOut = + sqlite3KvvfsMethods.xRcrdRead(zPath, zKey, 0, 0)>0; +#else if( strcmp(zPath, "local-journal")==0 ){ - *pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0; + *pResOut = + sqlite3KvvfsMethods.xRcrdRead("local", "jrnl", 0, 0)>0; }else if( strcmp(zPath, "session-journal")==0 ){ - *pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0; + *pResOut = + sqlite3KvvfsMethods.xRcrdRead("session", "jrnl", 0, 0)>0; }else if( strcmp(zPath, "local")==0 ){ - *pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0; + *pResOut = + sqlite3KvvfsMethods.xRcrdRead("local", "sz", 0, 0)>0; }else if( strcmp(zPath, "session")==0 ){ - *pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0; + *pResOut = + sqlite3KvvfsMethods.xRcrdRead("session", "sz", 0, 0)>0; }else { *pResOut = 0; } + /*all current JS tests avoid triggering: assert( *pResOut == 0 ); */ +#endif SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut)); return SQLITE_OK; } @@ -38833,7 +40574,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){ # endif #else /* !SQLITE_WASI */ # ifndef HAVE_FCHMOD -# define HAVE_FCHMOD +# define HAVE_FCHMOD 1 # endif #endif /* SQLITE_WASI */ @@ -38904,6 +40645,7 @@ struct unixFile { #endif #ifdef SQLITE_ENABLE_SETLK_TIMEOUT unsigned iBusyTimeout; /* Wait this many millisec on locks */ + int bBlockOnConnect; /* True to block for SHARED locks */ #endif #if OS_VXWORKS struct vxworksFileId *pId; /* Unique file ID */ @@ -39117,10 +40859,11 @@ static struct unix_syscall { #if defined(HAVE_FCHMOD) { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, +#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) #else { "fchmod", (sqlite3_syscall_ptr)0, 0 }, +#define osFchmod(FID,MODE) 0 #endif -#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, @@ -39214,6 +40957,119 @@ static struct unix_syscall { }; /* End of the overrideable system calls */ +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT) +/* +** Extract Posix Advisory Locking information about file description fd +** from the /proc/PID/fdinfo/FD pseudo-file. Fill the string buffer a[16] +** with characters to indicate which SQLite-relevant locks are held. +** a[16] will be a 15-character zero-terminated string with the following +** schema: +** +** AAA/B.DDD.DDDDD +** +** Each of character A-D will be "w" or "r" or "-" to indicate either a +** write-lock, a read-lock, or no-lock, respectively. The "." and "/" +** characters are delimiters intended to make the string more easily +** readable by humans. Here are the meaning of the specific letters: +** +** AAA -> The main database locks. PENDING_BYTE, RESERVED_BYTE, +** and SHARED_FIRST, respectively. +** +** B -> The deadman switch lock. Offset 128 of the -shm file. +** +** CCC -> WAL locks: WRITE, CKPT, RECOVER +** +** DDDDD -> WAL read-locks 0 through 5 +** +** Note that elements before the "/" apply to the main database file and +** elements after the "/" apply to the -shm file in WAL mode. +** +** Here is another way of thinking about the meaning of the result string: +** +** AAA/B.CCC.DDDDD +** ||| | ||| \___/ +** PENDING--'|| | ||| `----- READ 0-5 +** RESERVED--'| | ||`---- RECOVER +** SHARED ----' | |`----- CKPT +** DMS ------' `------ WRITE +** +** Return SQLITE_OK on success and SQLITE_ERROR_UNABLE if the /proc +** pseudo-filesystem is unavailable. +*/ +static int unixPosixAdvisoryLocks( + int fd, /* The file descriptor to analyze */ + char a[16] /* Write a text description of PALs here */ +){ + int in; + ssize_t n; + char *p, *pNext, *x; + char z[2000]; + + /* 1 */ + /* 012 4 678 01234 */ + memcpy(a, "---/-.---.-----", 16); + sqlite3_snprintf(sizeof(z), z, "/proc/%d/fdinfo/%d", getpid(), fd); + in = osOpen(z, O_RDONLY, 0); + if( in<0 ){ + return SQLITE_ERROR_UNABLE; + } + n = osRead(in, z, sizeof(z)-1); + osClose(in); + if( n<=0 ) return SQLITE_ERROR_UNABLE; + z[n] = 0; + + /* We are looking for lines that begin with "lock:\t". Examples: + ** + ** lock: 1: POSIX ADVISORY READ 494716 08:02:5277597 1073741826 1073742335 + ** lock: 1: POSIX ADVISORY WRITE 494716 08:02:5282282 120 120 + ** lock: 2: POSIX ADVISORY READ 494716 08:02:5282282 123 123 + ** lock: 3: POSIX ADVISORY READ 494716 08:02:5282282 128 128 + */ + pNext = strstr(z, "lock:\t"); + while( pNext ){ + char cType = 0; + sqlite3_int64 iFirst, iLast; + p = pNext+6; + pNext = strstr(p, "lock:\t"); + if( pNext ) pNext[-1] = 0; + if( (x = strstr(p, " READ "))!=0 ){ + cType = 'r'; + x += 6; + }else if( (x = strstr(p, " WRITE "))!=0 ){ + cType = 'w'; + x += 7; + }else{ + continue; + } + x = strrchr(x, ' '); + if( x==0 ) continue; + iLast = strtoll(x+1, 0, 10); + *x = 0; + x = strrchr(p, ' '); + if( x==0 ) continue; + iFirst = strtoll(x+1, 0, 10); + if( iLast>=PENDING_BYTE ){ + if( iFirst<=PENDING_BYTE && iLast>=PENDING_BYTE ) a[0] = cType; + if( iFirst<=PENDING_BYTE+1 && iLast>=PENDING_BYTE+1 ) a[1] = cType; + if( iFirst<=PENDING_BYTE+2 && iLast>=PENDING_BYTE+510 ) a[2] = cType; + }else if( iLast<=128 ){ + if( iFirst<=128 && iLast>=128 ) a[4] = cType; + if( iFirst<=120 && iLast>=120 ) a[6] = cType; + if( iFirst<=121 && iLast>=121 ) a[7] = cType; + if( iFirst<=122 && iLast>=122 ) a[8] = cType; + if( iFirst<=123 && iLast>=123 ) a[10] = cType; + if( iFirst<=124 && iLast>=124 ) a[11] = cType; + if( iFirst<=125 && iLast>=125 ) a[12] = cType; + if( iFirst<=126 && iLast>=126 ) a[13] = cType; + if( iFirst<=127 && iLast>=127 ) a[14] = cType; + } + } + return SQLITE_OK; +} +#else +# define unixPosixAdvisoryLocks(A,B) SQLITE_ERROR_UNABLE +#endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILESTAT */ + /* ** On some systems, calls to fchown() will trigger a message in a security ** log if they come from non-root processes. So avoid calling fchown() if @@ -39378,9 +41234,8 @@ static int robust_open(const char *z, int f, mode_t m){ /* ** Helper functions to obtain and relinquish the global mutex. The -** global mutex is used to protect the unixInodeInfo and -** vxworksFileId objects used by this file, all of which may be -** shared by multiple threads. +** global mutex is used to protect the unixInodeInfo objects used by +** this file, all of which may be shared by multiple threads. ** ** Function unixMutexHeld() is used to assert() that the global mutex ** is held when required. This function is only used as part of assert() @@ -39582,6 +41437,7 @@ struct vxworksFileId { ** variable: */ static struct vxworksFileId *vxworksFileList = 0; +static sqlite3_mutex *vxworksMutex = 0; /* ** Simplify a filename into its canonical form @@ -39647,14 +41503,14 @@ static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){ ** If found, increment the reference count and return a pointer to ** the existing file ID. */ - unixEnterMutex(); + sqlite3_mutex_enter(vxworksMutex); for(pCandidate=vxworksFileList; pCandidate; pCandidate=pCandidate->pNext){ if( pCandidate->nName==n && memcmp(pCandidate->zCanonicalName, pNew->zCanonicalName, n)==0 ){ sqlite3_free(pNew); pCandidate->nRef++; - unixLeaveMutex(); + sqlite3_mutex_leave(vxworksMutex); return pCandidate; } } @@ -39664,7 +41520,7 @@ static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){ pNew->nName = n; pNew->pNext = vxworksFileList; vxworksFileList = pNew; - unixLeaveMutex(); + sqlite3_mutex_leave(vxworksMutex); return pNew; } @@ -39673,7 +41529,7 @@ static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){ ** the object when the reference count reaches zero. */ static void vxworksReleaseFileId(struct vxworksFileId *pId){ - unixEnterMutex(); + sqlite3_mutex_enter(vxworksMutex); assert( pId->nRef>0 ); pId->nRef--; if( pId->nRef==0 ){ @@ -39683,7 +41539,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){ *pp = pId->pNext; sqlite3_free(pId); } - unixLeaveMutex(); + sqlite3_mutex_leave(vxworksMutex); } #endif /* OS_VXWORKS */ /*************** End of Unique File ID Utility Used By VxWorks **************** @@ -40071,6 +41927,10 @@ static int findInodeInfo( storeLastErrno(pFile, errno); return SQLITE_IOERR; } + if( fsync(fd) ){ + storeLastErrno(pFile, errno); + return SQLITE_IOERR_FSYNC; + } rc = osFstat(fd, &statbuf); if( rc!=0 ){ storeLastErrno(pFile, errno); @@ -40240,18 +42100,42 @@ static int osSetPosixAdvisoryLock( struct flock *pLock, /* The description of the lock */ unixFile *pFile /* Structure holding timeout value */ ){ - int tm = pFile->iBusyTimeout; - int rc = osFcntl(h,F_SETLK,pLock); - while( rc<0 && tm>0 ){ - /* On systems that support some kind of blocking file lock with a timeout, - ** make appropriate changes here to invoke that blocking file lock. On - ** generic posix, however, there is no such API. So we simply try the - ** lock once every millisecond until either the timeout expires, or until - ** the lock is obtained. */ - unixSleep(0,1000); + int rc = 0; + + if( pFile->iBusyTimeout==0 ){ + /* unixFile->iBusyTimeout is set to 0. In this case, attempt a + ** non-blocking lock. */ rc = osFcntl(h,F_SETLK,pLock); - tm--; + }else{ + /* unixFile->iBusyTimeout is set to greater than zero. In this case, + ** attempt a blocking-lock with a unixFile->iBusyTimeout ms timeout. + ** + ** On systems that support some kind of blocking file lock operation, + ** this block should be replaced by code to attempt a blocking lock + ** with a timeout of unixFile->iBusyTimeout ms. The code below is + ** placeholder code. If SQLITE_TEST is defined, the placeholder code + ** retries the lock once every 1ms until it succeeds or the timeout + ** is reached. Or, if SQLITE_TEST is not defined, the placeholder + ** code attempts a non-blocking lock and sets unixFile->iBusyTimeout + ** to 0. This causes the caller to return SQLITE_BUSY, instead of + ** SQLITE_BUSY_TIMEOUT to SQLite - as required by a VFS that does not + ** support blocking locks. + */ +#ifdef SQLITE_TEST + int tm = pFile->iBusyTimeout; + while( tm>0 ){ + rc = osFcntl(h,F_SETLK,pLock); + if( rc==0 ) break; + unixSleep(0,1000); + tm--; + } +#else + rc = osFcntl(h,F_SETLK,pLock); + pFile->iBusyTimeout = 0; +#endif + /* End of code to replace with real blocking-locks code. */ } + return rc; } #endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ @@ -40284,7 +42168,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){ if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){ if( pInode->bProcessLock==0 ){ struct flock lock; - assert( pInode->nLock==0 ); + /* assert( pInode->nLock==0 ); <-- Not true if unix-excl READONLY used */ lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; @@ -40297,11 +42181,25 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){ rc = 0; } }else{ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( pFile->bBlockOnConnect && pLock->l_type==F_RDLCK + && pLock->l_start==SHARED_FIRST && pLock->l_len==SHARED_SIZE + ){ + rc = osFcntl(pFile->h, F_SETLKW, pLock); + }else +#endif rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile); } return rc; } +#if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL) +/* Forward reference */ +static int unixIsSharingShmNode(unixFile*); +#else +#define unixIsSharingShmNode(pFile) (0) +#endif + /* ** Lock the file with the lock specified by parameter eFileLock - one ** of the following: @@ -40494,6 +42392,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ rc = SQLITE_BUSY; + }else if( unixIsSharingShmNode(pFile) ){ + /* We are in WAL mode and attempting to delete the SHM and WAL + ** files due to closing the connection or changing out of WAL mode, + ** but another process still holds locks on the SHM file, thus + ** indicating that database locks have been broken, perhaps due + ** to a rogue close(open(dbFile)) or similar. + */ + rc = SQLITE_BUSY; }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is ** assumed that there is a SHARED or greater lock on the file @@ -42585,6 +44491,10 @@ static int unixGetTempname(int nBuf, char *zBuf); #if !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL) static int unixFcntlExternalReader(unixFile*, int*); #endif +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT) + static void unixDescribeShm(sqlite3_str*,unixShm*); +#endif + /* ** Information and control of an open file handle. @@ -42607,6 +44517,11 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ } #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ + case SQLITE_FCNTL_NULL_IO: { + osClose(pFile->h); + pFile->h = -1; + return SQLITE_OK; + } case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->eFileLock; return SQLITE_OK; @@ -42653,8 +44568,9 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT case SQLITE_FCNTL_LOCK_TIMEOUT: { int iOld = pFile->iBusyTimeout; + int iNew = *(int*)pArg; #if SQLITE_ENABLE_SETLK_TIMEOUT==1 - pFile->iBusyTimeout = *(int*)pArg; + pFile->iBusyTimeout = iNew<0 ? 0x7FFFFFFF : (unsigned)iNew; #elif SQLITE_ENABLE_SETLK_TIMEOUT==2 pFile->iBusyTimeout = !!(*(int*)pArg); #else @@ -42663,7 +44579,12 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ *(int*)pArg = iOld; return SQLITE_OK; } -#endif + case SQLITE_FCNTL_BLOCK_ON_CONNECT: { + int iNew = *(int*)pArg; + pFile->bBlockOnConnect = iNew; + return SQLITE_OK; + } +#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; @@ -42716,6 +44637,66 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ return SQLITE_OK; #endif } + +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT) + case SQLITE_FCNTL_FILESTAT: { + sqlite3_str *pStr = (sqlite3_str*)pArg; + char aLck[16]; + unixInodeInfo *pInode; + static const char *azLock[] = { "SHARED", "RESERVED", + "PENDING", "EXCLUSIVE" }; + sqlite3_str_appendf(pStr, "{\"h\":%d", pFile->h); + sqlite3_str_appendf(pStr, ",\"vfs\":\"%s\"", pFile->pVfs->zName); + if( pFile->eFileLock ){ + sqlite3_str_appendf(pStr, ",\"eFileLock\":\"%s\"", + azLock[pFile->eFileLock-1]); + if( unixPosixAdvisoryLocks(pFile->h, aLck)==SQLITE_OK ){ + sqlite3_str_appendf(pStr, ",\"pal\":\"%s\"", aLck); + } + } + unixEnterMutex(); + if( pFile->pShm ){ + sqlite3_str_appendall(pStr, ",\"shm\":"); + unixDescribeShm(pStr, pFile->pShm); + } +#if SQLITE_MAX_MMAP_SIZE>0 + if( pFile->mmapSize ){ + sqlite3_str_appendf(pStr, ",\"mmapSize\":%lld", pFile->mmapSize); + sqlite3_str_appendf(pStr, ",\"nFetchOut\":%d", pFile->nFetchOut); + } +#endif + if( (pInode = pFile->pInode)!=0 ){ + sqlite3_str_appendf(pStr, ",\"inode\":{\"nRef\":%d",pInode->nRef); + sqlite3_mutex_enter(pInode->pLockMutex); + sqlite3_str_appendf(pStr, ",\"nShared\":%d", pInode->nShared); + if( pInode->eFileLock ){ + sqlite3_str_appendf(pStr, ",\"eFileLock\":\"%s\"", + azLock[pInode->eFileLock-1]); + } + if( pInode->pUnused ){ + char cSep = '['; + UnixUnusedFd *pUFd = pFile->pInode->pUnused; + sqlite3_str_appendall(pStr, ",\"unusedFd\":"); + while( pUFd ){ + sqlite3_str_appendf(pStr, "%c{\"fd\":%d,\"flags\":%d", + cSep, pUFd->fd, pUFd->flags); + cSep = ','; + if( unixPosixAdvisoryLocks(pUFd->fd, aLck)==SQLITE_OK ){ + sqlite3_str_appendf(pStr, ",\"pal\":\"%s\"", aLck); + } + sqlite3_str_append(pStr, "}", 1); + pUFd = pUFd->pNext; + } + sqlite3_str_append(pStr, "]", 1); + } + sqlite3_mutex_leave(pInode->pLockMutex); + sqlite3_str_append(pStr, "}", 1); + } + unixLeaveMutex(); + sqlite3_str_append(pStr, "}", 1); + return SQLITE_OK; + } +#endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILESTAT */ } return SQLITE_NOTFOUND; } @@ -42748,6 +44729,7 @@ static void setDeviceCharacteristics(unixFile *pFd){ if( pFd->ctrlFlags & UNIXFILE_PSOW ){ pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; } + pFd->deviceCharacteristics |= SQLITE_IOCAP_SUBPAGE_READ; pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; } @@ -42981,6 +44963,26 @@ struct unixShm { #define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT) +/* +** Describe the pShm object using JSON. Used for diagnostics only. +*/ +static void unixDescribeShm(sqlite3_str *pStr, unixShm *pShm){ + unixShmNode *pNode = pShm->pShmNode; + char aLck[16]; + sqlite3_str_appendf(pStr, "{\"h\":%d", pNode->hShm); + assert( unixMutexHeld() ); + sqlite3_str_appendf(pStr, ",\"nRef\":%d", pNode->nRef); + sqlite3_str_appendf(pStr, ",\"id\":%d", pShm->id); + sqlite3_str_appendf(pStr, ",\"sharedMask\":%d", pShm->sharedMask); + sqlite3_str_appendf(pStr, ",\"exclMask\":%d", pShm->exclMask); + if( unixPosixAdvisoryLocks(pNode->hShm, aLck)==SQLITE_OK ){ + sqlite3_str_appendf(pStr, ",\"pal\":\"%s\"", aLck); + } + sqlite3_str_append(pStr, "}", 1); +} +#endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILESTAT */ + /* ** Use F_GETLK to check whether or not there are any readers with open ** wal-mode transactions in other processes on database file pFile. If @@ -43014,6 +45016,44 @@ static int unixFcntlExternalReader(unixFile *pFile, int *piOut){ return rc; } +/* +** If pFile has a -shm file open and it is sharing that file with some +** other connection, either in the same process or in a separate process, +** then return true. Return false if either pFile does not have a -shm +** file open or if it is the only connection to that -shm file across the +** entire system. +** +** This routine is not required for correct operation. It can always return +** false and SQLite will continue to operate according to spec. However, +** when this routine does its job, it adds extra robustness in cases +** where database file locks have been erroneously deleted in a WAL-mode +** database by doing close(open(DATABASE_PATHNAME)) or similar. +** +** With false negatives, SQLite still operates to spec, though with less +** robustness. With false positives, the last database connection on a +** WAL-mode database will fail to unlink the -wal and -shm files, which +** is annoying but harmless. False positives will also prevent a database +** connection from running "PRAGMA journal_mode=DELETE" in order to take +** the database out of WAL mode, which is perhaps more serious, but is +** still not a disaster. +*/ +static int unixIsSharingShmNode(unixFile *pFile){ + unixShmNode *pShmNode; + struct flock lock; + if( pFile->pShm==0 ) return 0; + if( pFile->ctrlFlags & UNIXFILE_EXCL ) return 0; + pShmNode = pFile->pShm->pShmNode; +#if SQLITE_ATOMIC_INTRINSICS + assert( AtomicLoad(&pShmNode->nRef)==1 ); +#endif + memset(&lock, 0, sizeof(lock)); + lock.l_whence = SEEK_SET; + lock.l_start = UNIX_SHM_DMS; + lock.l_len = 1; + lock.l_type = F_WRLCK; + osFcntl(pShmNode->hShm, F_GETLK, &lock); + return (lock.l_type!=F_UNLCK); +} /* ** Apply posix advisory locks for all bytes from ofst through ofst+n-1. @@ -43059,7 +45099,8 @@ static int unixShmSystemLock( /* Locks are within range */ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); - assert( ofst>=UNIX_SHM_BASE && ofst<=(UNIX_SHM_DMS+SQLITE_SHM_NLOCK) ); + assert( ofst>=UNIX_SHM_BASE && ofst<=UNIX_SHM_DMS ); + assert( ofst+n-1<=UNIX_SHM_DMS ); if( pShmNode->hShm>=0 ){ int res; @@ -43460,9 +45501,9 @@ static int unixShmMap( nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; if( pShmNode->nRegionszRegion = szRegion; @@ -43493,7 +45534,7 @@ static int unixShmMap( */ else{ static const int pgsz = 4096; - int iPg; + i64 iPg; /* Write to the last byte of each newly allocated or extended page */ assert( (nByte % pgsz)==0 ); @@ -43510,7 +45551,7 @@ static int unixShmMap( } /* Map the requested memory region into this processes address space. */ - apNew = (char **)sqlite3_realloc( + apNew = (char **)sqlite3_realloc64( pShmNode->apRegion, nReqRegion*sizeof(char *) ); if( !apNew ){ @@ -43519,8 +45560,8 @@ static int unixShmMap( } pShmNode->apRegion = apNew; while( pShmNode->nRegionhShm>=0 ){ pMem = osMmap(0, nMap, @@ -43591,7 +45632,7 @@ static int assertLockingArrayOk(unixShmNode *pShmNode){ return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0); #endif } -#endif +#endif /* !defined(SQLITE_WASI) && !defined(SQLITE_OMIT_WAL) */ /* ** Change the lock state for a shared-memory segment. @@ -43635,21 +45676,20 @@ static int unixShmLock( /* Check that, if this to be a blocking lock, no locks that occur later ** in the following list than the lock being obtained are already held: ** - ** 1. Checkpointer lock (ofst==1). - ** 2. Write lock (ofst==0). - ** 3. Read locks (ofst>=3 && ofst=3 && ofstexclMask|p->sharedMask); assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( - (ofst!=2) /* not RECOVER */ + (ofst!=2 || lockMask==0) && (ofst!=1 || lockMask==0 || lockMask==2) && (ofst!=0 || lockMask<3) && (ofst<3 || lockMask<(1<=0 ) robust_close(pNew, h, __LINE__); - h = -1; - osUnlink(zFilename); - pNew->ctrlFlags |= UNIXFILE_DELETE; + if( h>=0 ){ + robust_close(pNew, h, __LINE__); + h = -1; + } + if( pNew->ctrlFlags & UNIXFILE_DELETE ){ + osUnlink(zFilename); + } + if( pNew->pId ){ + vxworksReleaseFileId(pNew->pId); + pNew->pId = 0; + } } #endif if( rc!=SQLITE_OK ){ @@ -44601,6 +46648,9 @@ static const char *unixTempFileDir(void){ while(1){ if( zDir!=0 +#if OS_VXWORKS + && zDir[0]=='/' +#endif && osStat(zDir, &buf)==0 && S_ISDIR(buf.st_mode) && osAccess(zDir, 03)==0 @@ -44915,6 +46965,12 @@ static int unixOpen( || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); +#if OS_VXWORKS + /* The file-ID mechanism used in Vxworks requires that all pathnames + ** provided to unixOpen must be absolute pathnames. */ + if( zPath!=0 && zPath[0]!='/' ){ return SQLITE_CANTOPEN; } +#endif + /* Detect a pid change and reset the PRNG. There is a race condition ** here such that two or more threads all trying to open databases at ** the same instant might all reset the PRNG. But multiple resets @@ -45115,8 +47171,11 @@ static int unixOpen( } #endif - assert( zPath==0 || zPath[0]=='/' - || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL + assert( zPath==0 + || zPath[0]=='/' + || eType==SQLITE_OPEN_SUPER_JOURNAL + || eType==SQLITE_OPEN_MAIN_JOURNAL + || eType==SQLITE_OPEN_TEMP_JOURNAL ); rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); @@ -45454,7 +47513,7 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ /* Almost all modern unix systems support nanosleep(). But if you are ** compiling for one of the rare exceptions, you can use - ** -DHAVE_NANOSLEEP=0 (perhaps in conjuction with -DHAVE_USLEEP if + ** -DHAVE_NANOSLEEP=0 (perhaps in conjunction with -DHAVE_USLEEP if ** usleep() is available) in order to bypass the use of nanosleep() */ nanosleep(&sp, NULL); @@ -46845,6 +48904,9 @@ SQLITE_API int sqlite3_os_init(void){ sqlite3KvvfsInit(); #endif unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); +#if OS_VXWORKS + vxworksMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS2); +#endif #ifndef SQLITE_OMIT_WAL /* Validate lock assumptions */ @@ -46879,6 +48941,9 @@ SQLITE_API int sqlite3_os_init(void){ */ SQLITE_API int sqlite3_os_end(void){ unixBigLock = 0; +#if OS_VXWORKS + vxworksMutex = 0; +#endif return SQLITE_OK; } @@ -46931,7 +48996,7 @@ SQLITE_API int sqlite3_os_end(void){ ** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions ** based on the sub-platform)? */ -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(SQLITE_WIN32_NO_ANSI) +#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_ANSI) # define SQLITE_WIN32_HAS_ANSI #endif @@ -46939,7 +49004,7 @@ SQLITE_API int sqlite3_os_end(void){ ** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions ** based on the sub-platform)? */ -#if (SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT) && \ +#if (SQLITE_OS_WINCE || SQLITE_OS_WINNT) && \ !defined(SQLITE_WIN32_NO_WIDE) # define SQLITE_WIN32_HAS_WIDE #endif @@ -47078,16 +49143,7 @@ SQLITE_API int sqlite3_os_end(void){ */ #if SQLITE_WIN32_FILEMAPPING_API && \ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) -/* -** Two of the file mapping APIs are different under WinRT. Figure out which -** set we need. -*/ -#if SQLITE_OS_WINRT -WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \ - LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR); -WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T); -#else #if defined(SQLITE_WIN32_HAS_ANSI) WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \ DWORD, DWORD, DWORD, LPCSTR); @@ -47099,7 +49155,6 @@ WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \ #endif /* defined(SQLITE_WIN32_HAS_WIDE) */ WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T); -#endif /* SQLITE_OS_WINRT */ /* ** These file mapping APIs are common to both Win32 and WinRT. @@ -47175,8 +49230,18 @@ struct winFile { sqlite3_int64 mmapSize; /* Size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + DWORD iBusyTimeout; /* Wait this many millisec on locks */ + int bBlockOnConnect; +#endif }; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT +# define winFileBusyTimeout(pDbFd) pDbFd->iBusyTimeout +#else +# define winFileBusyTimeout(pDbFd) 0 +#endif + /* ** The winVfsAppData structure is used for the pAppData member for all of the ** Win32 VFS variants. @@ -47380,7 +49445,7 @@ static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; ** This function is not available on Windows CE or WinRT. */ -#if SQLITE_OS_WINCE || SQLITE_OS_WINRT +#if SQLITE_OS_WINCE # define osAreFileApisANSI() 1 #endif @@ -47395,7 +49460,7 @@ static struct win_syscall { sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ sqlite3_syscall_ptr pDefault; /* Default value */ } aSyscall[] = { -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 }, #else { "AreFileApisANSI", (SYSCALL)0, 0 }, @@ -47434,7 +49499,7 @@ static struct win_syscall { #define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if defined(SQLITE_WIN32_HAS_WIDE) { "CreateFileW", (SYSCALL)CreateFileW, 0 }, #else { "CreateFileW", (SYSCALL)0, 0 }, @@ -47443,7 +49508,7 @@ static struct win_syscall { #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \ +#if defined(SQLITE_WIN32_HAS_ANSI) && \ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \ SQLITE_WIN32_CREATEFILEMAPPINGA { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 }, @@ -47454,8 +49519,8 @@ static struct win_syscall { #define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent) -#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) +#if (SQLITE_OS_WINCE || defined(SQLITE_WIN32_HAS_WIDE)) && \ + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 }, #else { "CreateFileMappingW", (SYSCALL)0, 0 }, @@ -47464,7 +49529,7 @@ static struct win_syscall { #define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if defined(SQLITE_WIN32_HAS_WIDE) { "CreateMutexW", (SYSCALL)CreateMutexW, 0 }, #else { "CreateMutexW", (SYSCALL)0, 0 }, @@ -47495,7 +49560,7 @@ static struct win_syscall { { "FileTimeToLocalFileTime", (SYSCALL)0, 0 }, #endif -#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \ +#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(const FILETIME*, \ LPFILETIME))aSyscall[11].pCurrent) #if SQLITE_OS_WINCE @@ -47504,7 +49569,7 @@ static struct win_syscall { { "FileTimeToSystemTime", (SYSCALL)0, 0 }, #endif -#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \ +#define osFileTimeToSystemTime ((BOOL(WINAPI*)(const FILETIME*, \ LPSYSTEMTIME))aSyscall[12].pCurrent) { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 }, @@ -47550,7 +49615,7 @@ static struct win_syscall { #define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \ LPDWORD))aSyscall[18].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 }, #else { "GetDiskFreeSpaceW", (SYSCALL)0, 0 }, @@ -47567,7 +49632,7 @@ static struct win_syscall { #define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if defined(SQLITE_WIN32_HAS_WIDE) { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 }, #else { "GetFileAttributesW", (SYSCALL)0, 0 }, @@ -47584,11 +49649,7 @@ static struct win_syscall { #define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \ LPVOID))aSyscall[22].pCurrent) -#if !SQLITE_OS_WINRT { "GetFileSize", (SYSCALL)GetFileSize, 0 }, -#else - { "GetFileSize", (SYSCALL)0, 0 }, -#endif #define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent) @@ -47601,7 +49662,7 @@ static struct win_syscall { #define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \ LPSTR*))aSyscall[24].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 }, #else { "GetFullPathNameW", (SYSCALL)0, 0 }, @@ -47610,6 +49671,12 @@ static struct win_syscall { #define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \ LPWSTR*))aSyscall[25].pCurrent) +/* +** For GetLastError(), MSDN says: +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ { "GetLastError", (SYSCALL)GetLastError, 0 }, #define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent) @@ -47630,16 +49697,10 @@ static struct win_syscall { #define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \ LPCSTR))aSyscall[27].pCurrent) -#if !SQLITE_OS_WINRT { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 }, -#else - { "GetSystemInfo", (SYSCALL)0, 0 }, -#endif - #define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent) { "GetSystemTime", (SYSCALL)GetSystemTime, 0 }, - #define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent) #if !SQLITE_OS_WINCE @@ -47659,7 +49720,7 @@ static struct win_syscall { #define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if defined(SQLITE_WIN32_HAS_WIDE) { "GetTempPathW", (SYSCALL)GetTempPathW, 0 }, #else { "GetTempPathW", (SYSCALL)0, 0 }, @@ -47667,11 +49728,7 @@ static struct win_syscall { #define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent) -#if !SQLITE_OS_WINRT { "GetTickCount", (SYSCALL)GetTickCount, 0 }, -#else - { "GetTickCount", (SYSCALL)0, 0 }, -#endif #define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent) @@ -47684,7 +49741,7 @@ static struct win_syscall { #define osGetVersionExA ((BOOL(WINAPI*)( \ LPOSVERSIONINFOA))aSyscall[34].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ +#if defined(SQLITE_WIN32_HAS_WIDE) && \ SQLITE_WIN32_GETVERSIONEX { "GetVersionExW", (SYSCALL)GetVersionExW, 0 }, #else @@ -47699,20 +49756,12 @@ static struct win_syscall { #define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \ SIZE_T))aSyscall[36].pCurrent) -#if !SQLITE_OS_WINRT { "HeapCreate", (SYSCALL)HeapCreate, 0 }, -#else - { "HeapCreate", (SYSCALL)0, 0 }, -#endif #define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \ SIZE_T))aSyscall[37].pCurrent) -#if !SQLITE_OS_WINRT { "HeapDestroy", (SYSCALL)HeapDestroy, 0 }, -#else - { "HeapDestroy", (SYSCALL)0, 0 }, -#endif #define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[38].pCurrent) @@ -47730,16 +49779,12 @@ static struct win_syscall { #define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \ LPCVOID))aSyscall[41].pCurrent) -#if !SQLITE_OS_WINRT { "HeapValidate", (SYSCALL)HeapValidate, 0 }, -#else - { "HeapValidate", (SYSCALL)0, 0 }, -#endif #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \ LPCVOID))aSyscall[42].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE { "HeapCompact", (SYSCALL)HeapCompact, 0 }, #else { "HeapCompact", (SYSCALL)0, 0 }, @@ -47755,7 +49800,7 @@ static struct win_syscall { #define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[44].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ +#if defined(SQLITE_WIN32_HAS_WIDE) && \ !defined(SQLITE_OMIT_LOAD_EXTENSION) { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 }, #else @@ -47764,21 +49809,17 @@ static struct win_syscall { #define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[45].pCurrent) -#if !SQLITE_OS_WINRT { "LocalFree", (SYSCALL)LocalFree, 0 }, -#else - { "LocalFree", (SYSCALL)0, 0 }, -#endif #define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[46].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE { "LockFile", (SYSCALL)LockFile, 0 }, #else { "LockFile", (SYSCALL)0, 0 }, #endif -#ifndef osLockFile +#if !defined(osLockFile) && defined(SQLITE_WIN32_HAS_ANSI) #define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ DWORD))aSyscall[47].pCurrent) #endif @@ -47794,8 +49835,7 @@ static struct win_syscall { LPOVERLAPPED))aSyscall[48].pCurrent) #endif -#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) +#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 }, #else { "MapViewOfFile", (SYSCALL)0, 0 }, @@ -47823,35 +49863,27 @@ static struct win_syscall { #define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[53].pCurrent) -#if !SQLITE_OS_WINRT { "SetFilePointer", (SYSCALL)SetFilePointer, 0 }, -#else - { "SetFilePointer", (SYSCALL)0, 0 }, -#endif #define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \ DWORD))aSyscall[54].pCurrent) -#if !SQLITE_OS_WINRT { "Sleep", (SYSCALL)Sleep, 0 }, -#else - { "Sleep", (SYSCALL)0, 0 }, -#endif #define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[55].pCurrent) { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 }, -#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \ +#define osSystemTimeToFileTime ((BOOL(WINAPI*)(const SYSTEMTIME*, \ LPFILETIME))aSyscall[56].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE { "UnlockFile", (SYSCALL)UnlockFile, 0 }, #else { "UnlockFile", (SYSCALL)0, 0 }, #endif -#ifndef osUnlockFile +#if !defined(osUnlockFile) && defined(SQLITE_WIN32_HAS_ANSI) #define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ DWORD))aSyscall[57].pCurrent) #endif @@ -47883,23 +49915,16 @@ static struct win_syscall { #define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \ LPOVERLAPPED))aSyscall[61].pCurrent) -#if SQLITE_OS_WINRT - { "CreateEventExW", (SYSCALL)CreateEventExW, 0 }, -#else - { "CreateEventExW", (SYSCALL)0, 0 }, -#endif - -#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \ - DWORD,DWORD))aSyscall[62].pCurrent) - -#if !SQLITE_OS_WINRT +/* +** For WaitForSingleObject(), MSDN says: +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 }, -#else - { "WaitForSingleObject", (SYSCALL)0, 0 }, -#endif #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ - DWORD))aSyscall[63].pCurrent) + DWORD))aSyscall[62].pCurrent) #if !SQLITE_OS_WINCE { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, @@ -47908,69 +49933,10 @@ static struct win_syscall { #endif #define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ - BOOL))aSyscall[64].pCurrent) - -#if SQLITE_OS_WINRT - { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 }, -#else - { "SetFilePointerEx", (SYSCALL)0, 0 }, -#endif - -#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \ - PLARGE_INTEGER,DWORD))aSyscall[65].pCurrent) - -#if SQLITE_OS_WINRT - { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 }, -#else - { "GetFileInformationByHandleEx", (SYSCALL)0, 0 }, -#endif - -#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \ - FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent) - -#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) - { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, -#else - { "MapViewOfFileFromApp", (SYSCALL)0, 0 }, -#endif - -#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \ - SIZE_T))aSyscall[67].pCurrent) - -#if SQLITE_OS_WINRT - { "CreateFile2", (SYSCALL)CreateFile2, 0 }, -#else - { "CreateFile2", (SYSCALL)0, 0 }, -#endif + BOOL))aSyscall[63].pCurrent) -#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \ - LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[68].pCurrent) - -#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION) - { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 }, -#else - { "LoadPackagedLibrary", (SYSCALL)0, 0 }, -#endif - -#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \ - DWORD))aSyscall[69].pCurrent) - -#if SQLITE_OS_WINRT - { "GetTickCount64", (SYSCALL)GetTickCount64, 0 }, -#else - { "GetTickCount64", (SYSCALL)0, 0 }, -#endif - -#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[70].pCurrent) - -#if SQLITE_OS_WINRT - { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 }, -#else { "GetNativeSystemInfo", (SYSCALL)0, 0 }, -#endif - -#define osGetNativeSystemInfo ((VOID(WINAPI*)( \ - LPSYSTEM_INFO))aSyscall[71].pCurrent) + /* ^^^^^^^^^^^^^^^^^^^----------------^------- placeholder only */ #if defined(SQLITE_WIN32_HAS_ANSI) { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 }, @@ -47978,7 +49944,7 @@ static struct win_syscall { { "OutputDebugStringA", (SYSCALL)0, 0 }, #endif -#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[72].pCurrent) +#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[65].pCurrent) #if defined(SQLITE_WIN32_HAS_WIDE) { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 }, @@ -47986,20 +49952,11 @@ static struct win_syscall { { "OutputDebugStringW", (SYSCALL)0, 0 }, #endif -#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[73].pCurrent) +#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[66].pCurrent) { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 }, -#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent) - -#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) - { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 }, -#else - { "CreateFileMappingFromApp", (SYSCALL)0, 0 }, -#endif - -#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ - LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent) +#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[67].pCurrent) /* ** NOTE: On some sub-platforms, the InterlockedCompareExchange "function" @@ -48014,25 +49971,25 @@ static struct win_syscall { { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, #define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \ - SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent) + SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[68].pCurrent) #endif /* defined(InterlockedCompareExchange) */ -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID +#if !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID { "UuidCreate", (SYSCALL)UuidCreate, 0 }, #else { "UuidCreate", (SYSCALL)0, 0 }, #endif -#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent) +#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[69].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID +#if !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 }, #else { "UuidCreateSequential", (SYSCALL)0, 0 }, #endif #define osUuidCreateSequential \ - ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent) + ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[70].pCurrent) #if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0 { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 }, @@ -48041,7 +49998,98 @@ static struct win_syscall { #endif #define osFlushViewOfFile \ - ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent) + ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[71].pCurrent) + +/* +** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CreateEvent() +** to implement blocking locks with timeouts. MSDN says: +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + { "CreateEvent", (SYSCALL)CreateEvent, 0 }, +#else + { "CreateEvent", (SYSCALL)0, 0 }, +#endif + +#define osCreateEvent ( \ + (HANDLE(WINAPI*) (LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR)) \ + aSyscall[72].pCurrent \ +) + +/* +** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CancelIo() +** for the case where a timeout expires and a lock request must be +** cancelled. +** +** Minimum supported client: Windows XP [desktop apps | UWP apps] +** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps] +*/ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + { "CancelIo", (SYSCALL)CancelIo, 0 }, +#else + { "CancelIo", (SYSCALL)0, 0 }, +#endif + +#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[73].pCurrent) + +#if defined(SQLITE_WIN32_HAS_WIDE) && defined(_WIN32) + { "GetModuleHandleW", (SYSCALL)GetModuleHandleW, 0 }, +#else + { "GetModuleHandleW", (SYSCALL)0, 0 }, +#endif + +#define osGetModuleHandleW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[74].pCurrent) + +#ifndef _WIN32 + { "getenv", (SYSCALL)getenv, 0 }, +#else + { "getenv", (SYSCALL)0, 0 }, +#endif + +#define osGetenv ((const char *(*)(const char *))aSyscall[75].pCurrent) + +#ifndef _WIN32 + { "getcwd", (SYSCALL)getcwd, 0 }, +#else + { "getcwd", (SYSCALL)0, 0 }, +#endif + +#define osGetcwd ((char*(*)(char*,size_t))aSyscall[76].pCurrent) + +#ifndef _WIN32 + { "readlink", (SYSCALL)readlink, 0 }, +#else + { "readlink", (SYSCALL)0, 0 }, +#endif + +#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[77].pCurrent) + +#ifndef _WIN32 + { "lstat", (SYSCALL)lstat, 0 }, +#else + { "lstat", (SYSCALL)0, 0 }, +#endif + +#define osLstat ((int(*)(const char*,struct stat*))aSyscall[78].pCurrent) + +#ifndef _WIN32 + { "__errno", (SYSCALL)__errno, 0 }, +#else + { "__errno", (SYSCALL)0, 0 }, +#endif + +#define osErrno (*((int*(*)(void))aSyscall[79].pCurrent)()) + +#ifndef _WIN32 + { "cygwin_conv_path", (SYSCALL)cygwin_conv_path, 0 }, +#else + { "cygwin_conv_path", (SYSCALL)0, 0 }, +#endif + +#define osCygwin_conv_path ((size_t(*)(unsigned int, \ + const void *, void *, size_t))aSyscall[80].pCurrent) }; /* End of the overrideable system calls */ @@ -48145,10 +50193,10 @@ SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE if( (nLargest=osHeapCompact(hHeap, SQLITE_WIN32_HEAP_FLAGS))==0 ){ DWORD lastErrno = osGetLastError(); if( lastErrno==NO_ERROR ){ @@ -48216,6 +50264,7 @@ SQLITE_API int sqlite3_win32_reset_heap(){ } #endif /* SQLITE_WIN32_MALLOC */ +#ifdef _WIN32 /* ** This function outputs the specified (ANSI) string to the Win32 debugger ** (if available). @@ -48258,29 +50307,13 @@ SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){ } #endif } - -/* -** The following routine suspends the current thread for at least ms -** milliseconds. This is equivalent to the Win32 Sleep() interface. -*/ -#if SQLITE_OS_WINRT -static HANDLE sleepObj = NULL; -#endif +#endif /* _WIN32 */ SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){ -#if SQLITE_OS_WINRT - if ( sleepObj==NULL ){ - sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET, - SYNCHRONIZE); - } - assert( sleepObj!=NULL ); - osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE); -#else osSleep(milliseconds); -#endif } -#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ +#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && \ SQLITE_THREADSAFE>0 SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ DWORD rc; @@ -48304,7 +50337,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ #if !SQLITE_WIN32_GETVERSIONEX # define osIsNT() (1) -#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI) +#elif SQLITE_OS_WINCE || !defined(SQLITE_WIN32_HAS_ANSI) # define osIsNT() (1) #elif !defined(SQLITE_WIN32_HAS_WIDE) # define osIsNT() (0) @@ -48317,13 +50350,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ ** based on the NT kernel. */ SQLITE_API int sqlite3_win32_is_nt(void){ -#if SQLITE_OS_WINRT - /* - ** NOTE: The WinRT sub-platform is always assumed to be based on the NT - ** kernel. - */ - return 1; -#elif SQLITE_WIN32_GETVERSIONEX +#if SQLITE_WIN32_GETVERSIONEX if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ #if defined(SQLITE_WIN32_HAS_ANSI) OSVERSIONINFOA sInfo; @@ -48341,7 +50368,9 @@ SQLITE_API int sqlite3_win32_is_nt(void){ } return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; #elif SQLITE_TEST - return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; + return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2 + || osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 + ; #else /* ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are @@ -48363,7 +50392,7 @@ static void *winMemMalloc(int nBytes){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif assert( nBytes>=0 ); @@ -48385,7 +50414,7 @@ static void winMemFree(void *pPrior){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); #endif if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */ @@ -48406,7 +50435,7 @@ static void *winMemRealloc(void *pPrior, int nBytes){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); #endif assert( nBytes>=0 ); @@ -48434,7 +50463,7 @@ static int winMemSize(void *p){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, p) ); #endif if( !p ) return 0; @@ -48464,7 +50493,7 @@ static int winMemInit(void *pAppData){ assert( pWinMemData->magic1==WINMEM_MAGIC1 ); assert( pWinMemData->magic2==WINMEM_MAGIC2 ); -#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE +#if SQLITE_WIN32_HEAP_CREATE if( !pWinMemData->hHeap ){ DWORD dwInitialSize = SQLITE_WIN32_HEAP_INIT_SIZE; DWORD dwMaximumSize = (DWORD)sqlite3GlobalConfig.nHeap; @@ -48497,7 +50526,7 @@ static int winMemInit(void *pAppData){ #endif assert( pWinMemData->hHeap!=0 ); assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif return SQLITE_OK; @@ -48515,7 +50544,7 @@ static void winMemShutdown(void *pAppData){ if( pWinMemData->hHeap ){ assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif if( pWinMemData->bOwned ){ @@ -48556,6 +50585,7 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){ } #endif /* SQLITE_WIN32_MALLOC */ +#ifdef _WIN32 /* ** Convert a UTF-8 string to Microsoft Unicode. ** @@ -48581,6 +50611,7 @@ static LPWSTR winUtf8ToUnicode(const char *zText){ } return zWideText; } +#endif /* _WIN32 */ /* ** Convert a Microsoft Unicode string to UTF-8. @@ -48615,28 +50646,29 @@ static char *winUnicodeToUtf8(LPCWSTR zWideText){ ** Space to hold the returned string is obtained from sqlite3_malloc(). */ static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){ - int nByte; + int nWideChar; LPWSTR zMbcsText; int codepage = useAnsi ? CP_ACP : CP_OEMCP; - nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL, - 0)*sizeof(WCHAR); - if( nByte==0 ){ + nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, NULL, + 0); + if( nWideChar==0 ){ return 0; } - zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) ); + zMbcsText = sqlite3MallocZero( nWideChar*sizeof(WCHAR) ); if( zMbcsText==0 ){ return 0; } - nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText, - nByte); - if( nByte==0 ){ + nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText, + nWideChar); + if( nWideChar==0 ){ sqlite3_free(zMbcsText); zMbcsText = 0; } return zMbcsText; } +#ifdef _WIN32 /* ** Convert a Microsoft Unicode string to a multi-byte character string, ** using the ANSI or OEM code page. @@ -48664,6 +50696,7 @@ static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){ } return zText; } +#endif /* _WIN32 */ /* ** Convert a multi-byte character string to UTF-8. @@ -48683,6 +50716,7 @@ static char *winMbcsToUtf8(const char *zText, int useAnsi){ return zTextUtf8; } +#ifdef _WIN32 /* ** Convert a UTF-8 string to a multi-byte character string. ** @@ -48732,6 +50766,7 @@ SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){ #endif return winUnicodeToUtf8(zWideText); } +#endif /* _WIN32 */ /* ** This is a public wrapper for the winMbcsToUtf8() function. @@ -48749,6 +50784,7 @@ SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){ return winMbcsToUtf8(zText, osAreFileApisANSI()); } +#ifdef _WIN32 /* ** This is a public wrapper for the winMbcsToUtf8() function. */ @@ -48873,6 +50909,7 @@ SQLITE_API int sqlite3_win32_set_directory( ){ return sqlite3_win32_set_directory16(type, zValue); } +#endif /* _WIN32 */ /* ** The return value of winGetLastErrorMsg @@ -48888,17 +50925,6 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ char *zOut = 0; if( osIsNT() ){ -#if SQLITE_OS_WINRT - WCHAR zTempWide[SQLITE_WIN32_MAX_ERRMSG_CHARS+1]; - dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - lastErrno, - 0, - zTempWide, - SQLITE_WIN32_MAX_ERRMSG_CHARS, - 0); -#else LPWSTR zTempWide = NULL; dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | @@ -48909,16 +50935,13 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ (LPWSTR) &zTempWide, 0, 0); -#endif if( dwLen > 0 ){ /* allocate a buffer and convert to UTF8 */ sqlite3BeginBenignMalloc(); zOut = winUnicodeToUtf8(zTempWide); sqlite3EndBenignMalloc(); -#if !SQLITE_OS_WINRT /* free the system buffer allocated by FormatMessage */ osLocalFree(zTempWide); -#endif } } #ifdef SQLITE_WIN32_HAS_ANSI @@ -49421,13 +51444,100 @@ static BOOL winLockFile( ovlp.Offset = offsetLow; ovlp.OffsetHigh = offsetHigh; return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp); +#ifdef SQLITE_WIN32_HAS_ANSI }else{ return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); +#endif } #endif } +#ifndef SQLITE_OMIT_WAL +/* +** Lock a region of nByte bytes starting at offset offset of file hFile. +** Take an EXCLUSIVE lock if parameter bExclusive is true, or a SHARED lock +** otherwise. If nMs is greater than zero and the lock cannot be obtained +** immediately, block for that many ms before giving up. +** +** This function returns SQLITE_OK if the lock is obtained successfully. If +** some other process holds the lock, SQLITE_BUSY is returned if nMs==0, or +** SQLITE_BUSY_TIMEOUT otherwise. Or, if an error occurs, SQLITE_IOERR. +*/ +static int winHandleLockTimeout( + HANDLE hFile, + DWORD offset, + DWORD nByte, + int bExcl, + DWORD nMs +){ + DWORD flags = LOCKFILE_FAIL_IMMEDIATELY | (bExcl?LOCKFILE_EXCLUSIVE_LOCK:0); + int rc = SQLITE_OK; + BOOL ret; + + if( !osIsNT() ){ + ret = winLockFile(&hFile, flags, offset, 0, nByte, 0); + }else{ + OVERLAPPED ovlp; + memset(&ovlp, 0, sizeof(OVERLAPPED)); + ovlp.Offset = offset; + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( nMs!=0 ){ + flags &= ~LOCKFILE_FAIL_IMMEDIATELY; + } + ovlp.hEvent = osCreateEvent(NULL, TRUE, FALSE, NULL); + if( ovlp.hEvent==NULL ){ + return SQLITE_IOERR_LOCK; + } +#endif + + ret = osLockFileEx(hFile, flags, 0, nByte, 0, &ovlp); + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + /* If SQLITE_ENABLE_SETLK_TIMEOUT is defined, then the file-handle was + ** opened with FILE_FLAG_OVERHEAD specified. In this case, the call to + ** LockFileEx() may fail because the request is still pending. This can + ** happen even if LOCKFILE_FAIL_IMMEDIATELY was specified. + ** + ** If nMs is 0, then LOCKFILE_FAIL_IMMEDIATELY was set in the flags + ** passed to LockFileEx(). In this case, if the operation is pending, + ** block indefinitely until it is finished. + ** + ** Otherwise, wait for up to nMs ms for the operation to finish. nMs + ** may be set to INFINITE. + */ + if( !ret && GetLastError()==ERROR_IO_PENDING ){ + DWORD nDelay = (nMs==0 ? INFINITE : nMs); + DWORD res = osWaitForSingleObject(ovlp.hEvent, nDelay); + if( res==WAIT_OBJECT_0 ){ + ret = TRUE; + }else if( res==WAIT_TIMEOUT ){ +#if SQLITE_ENABLE_SETLK_TIMEOUT==1 + rc = SQLITE_BUSY_TIMEOUT; +#else + rc = SQLITE_BUSY; +#endif + }else{ + /* Some other error has occurred */ + rc = SQLITE_IOERR_LOCK; + } + + /* If it is still pending, cancel the LockFileEx() call. */ + osCancelIo(hFile); + } + + osCloseHandle(ovlp.hEvent); +#endif + } + + if( rc==SQLITE_OK && !ret ){ + rc = SQLITE_BUSY; + } + return rc; +} +#endif /* #ifndef SQLITE_OMIT_WAL */ + /* ** Unlock a file region. */ @@ -49452,13 +51562,25 @@ static BOOL winUnlockFile( ovlp.Offset = offsetLow; ovlp.OffsetHigh = offsetHigh; return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp); +#ifdef SQLITE_WIN32_HAS_ANSI }else{ return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow, numBytesHigh); +#endif } #endif } +#ifndef SQLITE_OMIT_WAL +/* +** Remove an nByte lock starting at offset iOff from HANDLE h. +*/ +static int winHandleUnlock(HANDLE h, int iOff, int nByte){ + BOOL ret = winUnlockFile(&h, iOff, 0, nByte, 0); + return (ret ? SQLITE_OK : SQLITE_IOERR_UNLOCK); +} +#endif + /***************************************************************************** ** The next group of routines implement the I/O methods specified ** by the sqlite3_io_methods object. @@ -49472,66 +51594,56 @@ static BOOL winUnlockFile( #endif /* -** Move the current position of the file handle passed as the first -** argument to offset iOffset within the file. If successful, return 0. -** Otherwise, set pFile->lastErrno and return non-zero. +** Seek the file handle h to offset nByte of the file. +** +** If successful, return SQLITE_OK. Or, if an error occurs, return an SQLite +** error code. */ -static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ -#if !SQLITE_OS_WINRT +static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){ + int rc = SQLITE_OK; /* Return value */ + LONG upperBits; /* Most sig. 32 bits of new offset */ LONG lowerBits; /* Least sig. 32 bits of new offset */ DWORD dwRet; /* Value returned by SetFilePointer() */ - DWORD lastErrno; /* Value returned by GetLastError() */ - - OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset)); upperBits = (LONG)((iOffset>>32) & 0x7fffffff); lowerBits = (LONG)(iOffset & 0xffffffff); + dwRet = osSetFilePointer(h, lowerBits, &upperBits, FILE_BEGIN); + /* API oddity: If successful, SetFilePointer() returns a dword ** containing the lower 32-bits of the new file-offset. Or, if it fails, ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine ** whether an error has actually occurred, it is also necessary to call - ** GetLastError(). - */ - dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); - - if( (dwRet==INVALID_SET_FILE_POINTER - && ((lastErrno = osGetLastError())!=NO_ERROR)) ){ - pFile->lastErrno = lastErrno; - winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, - "winSeekFile", pFile->zPath); - OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); - return 1; + ** GetLastError(). */ + if( dwRet==INVALID_SET_FILE_POINTER ){ + DWORD lastErrno = osGetLastError(); + if( lastErrno!=NO_ERROR ){ + rc = SQLITE_IOERR_SEEK; + } } + OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset,sqlite3ErrName(rc))); + return rc; +} - OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); - return 0; -#else - /* - ** Same as above, except that this implementation works for WinRT. - */ - - LARGE_INTEGER x; /* The new offset */ - BOOL bRet; /* Value returned by SetFilePointerEx() */ - - x.QuadPart = iOffset; - bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN); +/* +** Move the current position of the file handle passed as the first +** argument to offset iOffset within the file. If successful, return 0. +** Otherwise, set pFile->lastErrno and return non-zero. +*/ +static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ + int rc; - if(!bRet){ + rc = winHandleSeek(pFile->h, iOffset); + if( rc!=SQLITE_OK ){ pFile->lastErrno = osGetLastError(); - winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, - "winSeekFile", pFile->zPath); - OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); - return 1; + winLogError(rc, pFile->lastErrno, "winSeekFile", pFile->zPath); } - - OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); - return 0; -#endif + return rc; } + #if SQLITE_MAX_MMAP_SIZE>0 /* Forward references to VFS helper methods used for memory mapped files */ static int winMapfile(winFile*, sqlite3_int64); @@ -49791,6 +51903,49 @@ static int winWrite( return SQLITE_OK; } +#ifndef SQLITE_OMIT_WAL +/* +** Truncate the file opened by handle h to nByte bytes in size. +*/ +static int winHandleTruncate(HANDLE h, sqlite3_int64 nByte){ + int rc = SQLITE_OK; /* Return code */ + rc = winHandleSeek(h, nByte); + if( rc==SQLITE_OK ){ + if( 0==osSetEndOfFile(h) ){ + rc = SQLITE_IOERR_TRUNCATE; + } + } + return rc; +} + +/* +** Determine the size in bytes of the file opened by the handle passed as +** the first argument. +*/ +static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){ + int rc = SQLITE_OK; + DWORD upperBits = 0; + DWORD lowerBits = 0; + + assert( pnByte ); + lowerBits = osGetFileSize(h, &upperBits); + *pnByte = (((sqlite3_int64)upperBits)<<32) + lowerBits; + if( lowerBits==INVALID_FILE_SIZE && osGetLastError()!=NO_ERROR ){ + rc = SQLITE_IOERR_FSTAT; + } + return rc; +} + +/* +** Close the handle passed as the only argument. +*/ +static void winHandleClose(HANDLE h){ + if( h!=INVALID_HANDLE_VALUE ){ + osCloseHandle(h); + } +} +#endif /* #ifndef SQLITE_OMIT_WAL */ + /* ** Truncate an open file to a specified size */ @@ -49976,20 +52131,6 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ assert( pSize!=0 ); SimulateIOError(return SQLITE_IOERR_FSTAT); OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize)); - -#if SQLITE_OS_WINRT - { - FILE_STANDARD_INFO info; - if( osGetFileInformationByHandleEx(pFile->h, FileStandardInfo, - &info, sizeof(info)) ){ - *pSize = info.EndOfFile.QuadPart; - }else{ - pFile->lastErrno = osGetLastError(); - rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, - "winFileSize", pFile->zPath); - } - } -#else { DWORD upperBits; DWORD lowerBits; @@ -50004,7 +52145,6 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ "winFileSize", pFile->zPath); } } -#endif OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n", pFile->h, pSize, *pSize, sqlite3ErrName(rc))); return rc; @@ -50046,8 +52186,9 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ ** Different API routines are called depending on whether or not this ** is Win9x or WinNT. */ -static int winGetReadLock(winFile *pFile){ +static int winGetReadLock(winFile *pFile, int bBlock){ int res; + DWORD mask = ~(bBlock ? LOCKFILE_FAIL_IMMEDIATELY : 0); OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); if( osIsNT() ){ #if SQLITE_OS_WINCE @@ -50057,7 +52198,7 @@ static int winGetReadLock(winFile *pFile){ */ res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0); #else - res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0, + res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS&mask, SHARED_FIRST, 0, SHARED_SIZE, 0); #endif } @@ -50066,7 +52207,7 @@ static int winGetReadLock(winFile *pFile){ int lk; sqlite3_randomness(sizeof(lk), &lk); pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1)); - res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, + res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS&mask, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); } #endif @@ -50161,46 +52302,62 @@ static int winLock(sqlite3_file *id, int locktype){ assert( locktype!=PENDING_LOCK ); assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); - /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or + /* Lock the PENDING_LOCK byte if we need to acquire an EXCLUSIVE lock or ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of ** the PENDING_LOCK byte is temporary. */ newLocktype = pFile->locktype; - if( pFile->locktype==NO_LOCK - || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK) + if( locktype==SHARED_LOCK + || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) ){ int cnt = 3; - while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, - PENDING_BYTE, 0, 1, 0))==0 ){ + + /* Flags for the LockFileEx() call. This should be an exclusive lock if + ** this call is to obtain EXCLUSIVE, or a shared lock if this call is to + ** obtain SHARED. */ + int flags = LOCKFILE_FAIL_IMMEDIATELY; + if( locktype==EXCLUSIVE_LOCK ){ + flags |= LOCKFILE_EXCLUSIVE_LOCK; + } + while( cnt>0 ){ /* Try 3 times to get the pending lock. This is needed to work ** around problems caused by indexing and/or anti-virus software on ** Windows systems. + ** ** If you are using this code as a model for alternative VFSes, do not - ** copy this retry logic. It is a hack intended for Windows only. - */ + ** copy this retry logic. It is a hack intended for Windows only. */ + res = winLockFile(&pFile->h, flags, PENDING_BYTE, 0, 1, 0); + if( res ) break; + lastErrno = osGetLastError(); OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n", - pFile->h, cnt, res)); + pFile->h, cnt, res + )); + if( lastErrno==ERROR_INVALID_HANDLE ){ pFile->lastErrno = lastErrno; rc = SQLITE_IOERR_LOCK; OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n", - pFile->h, cnt, sqlite3ErrName(rc))); + pFile->h, cnt, sqlite3ErrName(rc) + )); return rc; } - if( cnt ) sqlite3_win32_sleep(1); + + cnt--; + if( cnt>0 ) sqlite3_win32_sleep(1); } gotPendingLock = res; - if( !res ){ - lastErrno = osGetLastError(); - } } /* Acquire a shared lock */ if( locktype==SHARED_LOCK && res ){ assert( pFile->locktype==NO_LOCK ); - res = winGetReadLock(pFile); +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + res = winGetReadLock(pFile, pFile->bBlockOnConnect); +#else + res = winGetReadLock(pFile, 0); +#endif if( res ){ newLocktype = SHARED_LOCK; }else{ @@ -50238,7 +52395,7 @@ static int winLock(sqlite3_file *id, int locktype){ newLocktype = EXCLUSIVE_LOCK; }else{ lastErrno = osGetLastError(); - winGetReadLock(pFile); + winGetReadLock(pFile, 0); } } @@ -50318,7 +52475,7 @@ static int winUnlock(sqlite3_file *id, int locktype){ type = pFile->locktype; if( type>=EXCLUSIVE_LOCK ){ winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){ + if( locktype==SHARED_LOCK && !winGetReadLock(pFile, 0) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(), @@ -50487,6 +52644,11 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ return SQLITE_OK; } #endif + case SQLITE_FCNTL_NULL_IO: { + (void)osCloseHandle(pFile->h); + pFile->h = NULL; + return SQLITE_OK; + } case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = 0; int rc = winGetTempname(pFile->pVfs, &zTFile); @@ -50523,6 +52685,50 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ return rc; } #endif + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + case SQLITE_FCNTL_LOCK_TIMEOUT: { + int iOld = pFile->iBusyTimeout; + int iNew = *(int*)pArg; +#if SQLITE_ENABLE_SETLK_TIMEOUT==1 + pFile->iBusyTimeout = (iNew < 0) ? INFINITE : (DWORD)iNew; +#elif SQLITE_ENABLE_SETLK_TIMEOUT==2 + pFile->iBusyTimeout = (DWORD)(!!iNew); +#else +# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2" +#endif + *(int*)pArg = iOld; + return SQLITE_OK; + } + case SQLITE_FCNTL_BLOCK_ON_CONNECT: { + int iNew = *(int*)pArg; + pFile->bBlockOnConnect = iNew; + return SQLITE_OK; + } +#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ + +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT) + case SQLITE_FCNTL_FILESTAT: { + sqlite3_str *pStr = (sqlite3_str*)pArg; + sqlite3_str_appendf(pStr, "{\"h\":%llu", (sqlite3_uint64)pFile->h); + sqlite3_str_appendf(pStr, ",\"vfs\":\"%s\"", pFile->pVfs->zName); + if( pFile->locktype ){ + static const char *azLock[] = { "SHARED", "RESERVED", + "PENDING", "EXCLUSIVE" }; + sqlite3_str_appendf(pStr, ",\"locktype\":\"%s\"", + azLock[pFile->locktype-1]); + } +#if SQLITE_MAX_MMAP_SIZE>0 + if( pFile->mmapSize ){ + sqlite3_str_appendf(pStr, ",\"mmapSize\":%lld", pFile->mmapSize); + sqlite3_str_appendf(pStr, ",\"nFetchOut\":%d", pFile->nFetchOut); + } +#endif + sqlite3_str_append(pStr, "}", 1); + return SQLITE_OK; + } +#endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILESTAT */ + } OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h)); return SQLITE_NOTFOUND; @@ -50548,7 +52754,7 @@ static int winSectorSize(sqlite3_file *id){ */ static int winDeviceCharacteristics(sqlite3_file *id){ winFile *p = (winFile*)id; - return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | + return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | SQLITE_IOCAP_SUBPAGE_READ | ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0); } @@ -50560,6 +52766,103 @@ static int winDeviceCharacteristics(sqlite3_file *id){ */ static SYSTEM_INFO winSysInfo; +/* +** Convert a UTF-8 filename into whatever form the underlying +** operating system wants filenames in. Space to hold the result +** is obtained from malloc and must be freed by the calling +** function +** +** On Cygwin, 3 possible input forms are accepted: +** - If the filename starts with ":/" or ":\", +** it is converted to UTF-16 as-is. +** - If the filename contains '/', it is assumed to be a +** Cygwin absolute path, it is converted to a win32 +** absolute path in UTF-16. +** - Otherwise it must be a filename only, the win32 filename +** is returned in UTF-16. +** Note: If the function cygwin_conv_path() fails, only +** UTF-8 -> UTF-16 conversion will be done. This can only +** happen when the file path >32k, in which case winUtf8ToUnicode() +** will fail too. +*/ +static void *winConvertFromUtf8Filename(const char *zFilename){ + void *zConverted = 0; + if( osIsNT() ){ +#ifdef __CYGWIN__ + int nChar; + LPWSTR zWideFilename; + + if( osCygwin_conv_path && !(winIsDriveLetterAndColon(zFilename) + && winIsDirSep(zFilename[2])) ){ + i64 nByte; + int convertflag = CCP_POSIX_TO_WIN_W; + if( !strchr(zFilename, '/') ) convertflag |= CCP_RELATIVE; + nByte = (i64)osCygwin_conv_path(convertflag, + zFilename, 0, 0); + if( nByte>0 ){ + zConverted = sqlite3MallocZero(12+(u64)nByte); + if ( zConverted==0 ){ + return zConverted; + } + zWideFilename = zConverted; + /* Filenames should be prefixed, except when converted + * full path already starts with "\\?\". */ + if( osCygwin_conv_path(convertflag, zFilename, + zWideFilename+4, nByte)==0 ){ + if( (convertflag&CCP_RELATIVE) ){ + memmove(zWideFilename, zWideFilename+4, nByte); + }else if( memcmp(zWideFilename+4, L"\\\\", 4) ){ + memcpy(zWideFilename, L"\\\\?\\", 8); + }else if( zWideFilename[6]!='?' ){ + memmove(zWideFilename+6, zWideFilename+4, nByte); + memcpy(zWideFilename, L"\\\\?\\UNC", 14); + }else{ + memmove(zWideFilename, zWideFilename+4, nByte); + } + return zConverted; + } + sqlite3_free(zConverted); + } + } + nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0); + if( nChar==0 ){ + return 0; + } + zWideFilename = sqlite3MallocZero( nChar*sizeof(WCHAR)+12 ); + if( zWideFilename==0 ){ + return 0; + } + nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, + zWideFilename, nChar); + if( nChar==0 ){ + sqlite3_free(zWideFilename); + zWideFilename = 0; + }else if( nChar>MAX_PATH + && winIsDriveLetterAndColon(zFilename) + && winIsDirSep(zFilename[2]) ){ + memmove(zWideFilename+4, zWideFilename, nChar*sizeof(WCHAR)); + zWideFilename[2] = '\\'; + memcpy(zWideFilename, L"\\\\?\\", 8); + }else if( nChar>MAX_PATH + && winIsDirSep(zFilename[0]) && winIsDirSep(zFilename[1]) + && zFilename[2] != '?' ){ + memmove(zWideFilename+6, zWideFilename, nChar*sizeof(WCHAR)); + memcpy(zWideFilename, L"\\\\?\\UNC", 14); + } + zConverted = zWideFilename; +#else + zConverted = winUtf8ToUnicode(zFilename); +#endif /* __CYGWIN__ */ + } +#if defined(SQLITE_WIN32_HAS_ANSI) && defined(_WIN32) + else{ + zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI()); + } +#endif + /* caller will handle out of memory */ + return zConverted; +} + #ifndef SQLITE_OMIT_WAL /* @@ -50596,30 +52899,40 @@ static int winShmMutexHeld(void) { ** log-summary is opened only once per process. ** ** winShmMutexHeld() must be true when creating or destroying -** this object or while reading or writing the following fields: +** this object, or while editing the global linked list that starts +** at winShmNodeList. ** -** nRef -** pNext +** When reading or writing the linked list starting at winShmNode.pWinShmList, +** pShmNode->mutex must be held. ** -** The following fields are read-only after the object is created: +** The following fields are constant after the object is created: ** -** fid ** zFilename +** hSharedShm +** mutex +** bUseSharedLockHandle ** -** Either winShmNode.mutex must be held or winShmNode.nRef==0 and +** Either winShmNode.mutex must be held or winShmNode.pWinShmList==0 and ** winShmMutexHeld() is true when reading or writing any other field ** in this structure. ** +** File-handle hSharedShm is always used to (a) take the DMS lock, (b) +** truncate the *-shm file if the DMS-locking protocol demands it, and +** (c) map regions of the *-shm file into memory using MapViewOfFile() +** or similar. If bUseSharedLockHandle is true, then other locks are also +** taken on hSharedShm. Or, if bUseSharedLockHandle is false, then other +** locks are taken using each connection's winShm.hShm handles. */ struct winShmNode { sqlite3_mutex *mutex; /* Mutex to access this object */ char *zFilename; /* Name of the file */ - winFile hFile; /* File handle from winOpen */ + HANDLE hSharedShm; /* File handle open on zFilename */ + int bUseSharedLockHandle; /* True to use hSharedShm for everything */ + int isUnlocked; /* DMS lock has not yet been obtained */ + int isReadonly; /* True if read-only */ int szRegion; /* Size of shared-memory regions */ int nRegion; /* Size of array apRegion */ - u8 isReadonly; /* True if read-only */ - u8 isUnlocked; /* True if no DMS lock held */ struct ShmRegion { HANDLE hMap; /* File handle from CreateFileMapping */ @@ -50627,8 +52940,8 @@ struct winShmNode { } *aRegion; DWORD lastErrno; /* The Windows errno from the last I/O error */ - int nRef; /* Number of winShm objects pointing to this */ - winShm *pFirst; /* All winShm objects pointing to this */ + winShm *pWinShmList; /* List of winShm objects with ptrs to this */ + winShmNode *pNext; /* Next in list of all winShmNode objects */ #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) u8 nextShmId; /* Next available winShm.id value */ @@ -50644,26 +52957,19 @@ static winShmNode *winShmNodeList = 0; /* ** Structure used internally by this VFS to record the state of an -** open shared memory connection. -** -** The following fields are initialized when this object is created and -** are read-only thereafter: -** -** winShm.pShmNode -** winShm.id -** -** All other fields are read/write. The winShm.pShmNode->mutex must be held -** while accessing any read/write fields. +** open shared memory connection. There is one such structure for each +** winFile open on a wal mode database. */ struct winShm { winShmNode *pShmNode; /* The underlying winShmNode object */ - winShm *pNext; /* Next winShm with the same winShmNode */ - u8 hasMutex; /* True if holding the winShmNode mutex */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ + HANDLE hShm; /* File-handle on *-shm file. For locking. */ + int bReadonly; /* True if hShm is opened read-only */ #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) u8 id; /* Id of this connection with its winShmNode */ #endif + winShm *pWinShmNext; /* Next winShm object on same winShmNode */ }; /* @@ -50672,56 +52978,12 @@ struct winShm { #define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ -/* -** Apply advisory locks for all n bytes beginning at ofst. -*/ -#define WINSHM_UNLCK 1 -#define WINSHM_RDLCK 2 -#define WINSHM_WRLCK 3 -static int winShmSystemLock( - winShmNode *pFile, /* Apply locks to this open shared-memory segment */ - int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */ - int ofst, /* Offset to first byte to be locked/unlocked */ - int nByte /* Number of bytes to lock or unlock */ -){ - int rc = 0; /* Result code form Lock/UnlockFileEx() */ - - /* Access to the winShmNode object is serialized by the caller */ - assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) ); - - OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n", - pFile->hFile.h, lockType, ofst, nByte)); - - /* Release/Acquire the system-level lock */ - if( lockType==WINSHM_UNLCK ){ - rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); - }else{ - /* Initialize the locking parameters */ - DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; - if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; - rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); - } - - if( rc!= 0 ){ - rc = SQLITE_OK; - }else{ - pFile->lastErrno = osGetLastError(); - rc = SQLITE_BUSY; - } - - OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n", - pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" : - "winLockFile", pFile->lastErrno, sqlite3ErrName(rc))); - - return rc; -} - /* Forward references to VFS methods */ static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*); static int winDelete(sqlite3_vfs *,const char*,int); /* -** Purge the winShmNodeList list of all entries with winShmNode.nRef==0. +** Purge the winShmNodeList list of all entries with winShmNode.pWinShmList==0. ** ** This is not a VFS shared-memory method; it is a utility function called ** by VFS shared-memory methods. @@ -50734,7 +52996,7 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ osGetCurrentProcessId(), deleteFlag)); pp = &winShmNodeList; while( (p = *pp)!=0 ){ - if( p->nRef==0 ){ + if( p->pWinShmList==0 ){ int i; if( p->mutex ){ sqlite3_mutex_free(p->mutex); } for(i=0; inRegion; i++){ @@ -50747,11 +53009,7 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); UNUSED_VARIABLE_VALUE(bRc); } - if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){ - SimulateIOErrorBenign(1); - winClose((sqlite3_file *)&p->hFile); - SimulateIOErrorBenign(0); - } + winHandleClose(p->hSharedShm); if( deleteFlag ){ SimulateIOErrorBenign(1); sqlite3BeginBenignMalloc(); @@ -50769,42 +53027,199 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ } /* -** The DMS lock has not yet been taken on shm file pShmNode. Attempt to -** take it now. Return SQLITE_OK if successful, or an SQLite error -** code otherwise. -** -** If the DMS cannot be locked because this is a readonly_shm=1 -** connection and no other process already holds a lock, return -** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1. +** The DMS lock has not yet been taken on the shm file associated with +** pShmNode. Take the lock. Truncate the *-shm file if required. +** Return SQLITE_OK if successful, or an SQLite error code otherwise. */ -static int winLockSharedMemory(winShmNode *pShmNode){ - int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1); +static int winLockSharedMemory(winShmNode *pShmNode, DWORD nMs){ + HANDLE h = pShmNode->hSharedShm; + int rc = SQLITE_OK; + assert( sqlite3_mutex_held(pShmNode->mutex) ); + rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 1, 0); if( rc==SQLITE_OK ){ + /* We have an EXCLUSIVE lock on the DMS byte. This means that this + ** is the first process to open the file. Truncate it to zero bytes + ** in this case. */ if( pShmNode->isReadonly ){ - pShmNode->isUnlocked = 1; - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); - return SQLITE_READONLY_CANTINIT; - }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){ - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); - return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(), - "winLockSharedMemory", pShmNode->zFilename); + rc = SQLITE_READONLY_CANTINIT; + }else{ + rc = winHandleTruncate(h, 0); } + + /* Release the EXCLUSIVE lock acquired above. */ + winUnlockFile(&h, WIN_SHM_DMS, 0, 1, 0); + }else if( (rc & 0xFF)==SQLITE_BUSY ){ + rc = SQLITE_OK; } if( rc==SQLITE_OK ){ - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); + /* Take a SHARED lock on the DMS byte. */ + rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 0, nMs); + if( rc==SQLITE_OK ){ + pShmNode->isUnlocked = 0; + } } - return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1); + return rc; } + /* -** Open the shared-memory area associated with database file pDbFd. +** This function is used to open a handle on a *-shm file. ** -** When opening a new shared-memory file, if no other instances of that -** file are currently open, in this process or in other processes, then -** the file must be truncated to zero length or have its header cleared. +** If SQLITE_ENABLE_SETLK_TIMEOUT is defined at build time, then the file +** is opened with FILE_FLAG_OVERLAPPED specified. If not, it is not. +*/ +static int winHandleOpen( + const char *zUtf8, /* File to open */ + int *pbReadonly, /* IN/OUT: True for readonly handle */ + HANDLE *ph /* OUT: New HANDLE for file */ +){ + int rc = SQLITE_OK; + void *zConverted = 0; + int bReadonly = *pbReadonly; + HANDLE h = INVALID_HANDLE_VALUE; + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + const DWORD flag_overlapped = FILE_FLAG_OVERLAPPED; +#else + const DWORD flag_overlapped = 0; +#endif + + /* Convert the filename to the system encoding. */ + zConverted = winConvertFromUtf8Filename(zUtf8); + if( zConverted==0 ){ + OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8)); + rc = SQLITE_IOERR_NOMEM_BKPT; + goto winopenfile_out; + } + + /* Ensure the file we are trying to open is not actually a directory. */ + if( winIsDir(zConverted) ){ + OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8)); + rc = SQLITE_CANTOPEN_ISDIR; + goto winopenfile_out; + } + + /* TODO: platforms. + ** TODO: retry-on-ioerr. + */ + if( osIsNT() ){ + h = osCreateFileW((LPCWSTR)zConverted, /* lpFileName */ + (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */ + FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ + NULL, /* lpSecurityAttributes */ + OPEN_ALWAYS, /* dwCreationDisposition */ + FILE_ATTRIBUTE_NORMAL|flag_overlapped, + NULL + ); + }else{ + /* Due to pre-processor directives earlier in this file, + ** SQLITE_WIN32_HAS_ANSI is always defined if osIsNT() is false. */ +#ifdef SQLITE_WIN32_HAS_ANSI + h = osCreateFileA((LPCSTR)zConverted, + (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */ + FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ + NULL, /* lpSecurityAttributes */ + OPEN_ALWAYS, /* dwCreationDisposition */ + FILE_ATTRIBUTE_NORMAL|flag_overlapped, + NULL + ); +#endif + } + + if( h==INVALID_HANDLE_VALUE ){ + if( bReadonly==0 ){ + bReadonly = 1; + rc = winHandleOpen(zUtf8, &bReadonly, &h); + }else{ + rc = SQLITE_CANTOPEN_BKPT; + } + } + + winopenfile_out: + sqlite3_free(zConverted); + *pbReadonly = bReadonly; + *ph = h; + return rc; +} + +/* +** Close pDbFd's connection to shared-memory. Delete the underlying +** *-shm file if deleteFlag is true. +*/ +static int winCloseSharedMemory(winFile *pDbFd, int deleteFlag){ + winShm *p; /* The connection to be closed */ + winShm **pp; /* Iterator for pShmNode->pWinShmList */ + winShmNode *pShmNode; /* The underlying shared-memory file */ + + p = pDbFd->pShm; + if( p==0 ) return SQLITE_OK; + if( p->hShm!=INVALID_HANDLE_VALUE ){ + osCloseHandle(p->hShm); + } + + winShmEnterMutex(); + pShmNode = p->pShmNode; + + /* Remove this connection from the winShmNode.pWinShmList list */ + sqlite3_mutex_enter(pShmNode->mutex); + for(pp=&pShmNode->pWinShmList; *pp!=p; pp=&(*pp)->pWinShmNext){} + *pp = p->pWinShmNext; + sqlite3_mutex_leave(pShmNode->mutex); + + winShmPurge(pDbFd->pVfs, deleteFlag); + winShmLeaveMutex(); + + /* Free the connection p */ + sqlite3_free(p); + pDbFd->pShm = 0; + return SQLITE_OK; +} + +/* +** testfixture builds may set this global variable to true via a +** Tcl interface. This forces the VFS to use the locking normally +** only used for UNC paths for all files. +*/ +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_win_test_unc_locking = 0; +#else +# define sqlite3_win_test_unc_locking 0 +#endif + +/* +** Return true if the string passed as the only argument is likely +** to be a UNC path. Return false if note. +** +** Return true if: +** +** (1) The name begins with "\\" +** (2) But does not begin with "\\?\C:\" where C can be any alphabetic +** character. +** +** For testing, also return true in all cases if the global variable +** sqlite3_win_test_unc_locking is true. +*/ +static int winIsUNCPath(const char *zFile){ + if( zFile[0]=='\\' && zFile[1]=='\\' ){ + if( zFile[2]=='?' + && zFile[3]=='\\' + && sqlite3Isalpha(zFile[4]) + && zFile[5]==':' + && winIsDirSep(zFile[6]) + ){ + return sqlite3_win_test_unc_locking; + }else{ + return 1; + } + } + return sqlite3_win_test_unc_locking; +} + +/* +** Open the shared-memory area associated with database file pDbFd. */ static int winOpenSharedMemory(winFile *pDbFd){ struct winShm *p; /* The connection to be opened */ @@ -50816,98 +53231,93 @@ static int winOpenSharedMemory(winFile *pDbFd){ assert( pDbFd->pShm==0 ); /* Not previously opened */ /* Allocate space for the new sqlite3_shm object. Also speculatively - ** allocate space for a new winShmNode and filename. - */ + ** allocate space for a new winShmNode and filename. */ p = sqlite3MallocZero( sizeof(*p) ); if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT; nName = sqlite3Strlen30(pDbFd->zPath); - pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 ); + pNew = sqlite3MallocZero( sizeof(*pShmNode) + (i64)nName + 17 ); if( pNew==0 ){ sqlite3_free(p); return SQLITE_IOERR_NOMEM_BKPT; } pNew->zFilename = (char*)&pNew[1]; + pNew->hSharedShm = INVALID_HANDLE_VALUE; + pNew->isUnlocked = 1; + pNew->bUseSharedLockHandle = winIsUNCPath(pDbFd->zPath); sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); /* Look to see if there is an existing winShmNode that can be used. - ** If no matching winShmNode currently exists, create a new one. - */ + ** If no matching winShmNode currently exists, then create a new one. */ winShmEnterMutex(); for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){ /* TBD need to come up with better match here. Perhaps - ** use FILE_ID_BOTH_DIR_INFO Structure. - */ + ** use FILE_ID_BOTH_DIR_INFO Structure. */ if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break; } - if( pShmNode ){ - sqlite3_free(pNew); - }else{ - int inFlags = SQLITE_OPEN_WAL; - int outFlags = 0; - + if( pShmNode==0 ){ pShmNode = pNew; - pNew = 0; - ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE; - pShmNode->pNext = winShmNodeList; - winShmNodeList = pShmNode; + /* Allocate a mutex for this winShmNode object, if one is required. */ if( sqlite3GlobalConfig.bCoreMutex ){ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pShmNode->mutex==0 ){ - rc = SQLITE_IOERR_NOMEM_BKPT; - goto shm_open_err; - } + if( pShmNode->mutex==0 ) rc = SQLITE_IOERR_NOMEM_BKPT; } - if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ - inFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; - }else{ - inFlags |= SQLITE_OPEN_READONLY; - } - rc = winOpen(pDbFd->pVfs, pShmNode->zFilename, - (sqlite3_file*)&pShmNode->hFile, - inFlags, &outFlags); - if( rc!=SQLITE_OK ){ - rc = winLogError(rc, osGetLastError(), "winOpenShm", - pShmNode->zFilename); - goto shm_open_err; + /* Open a file-handle to use for mappings, and for the DMS lock. */ + if( rc==SQLITE_OK ){ + HANDLE h = INVALID_HANDLE_VALUE; + pShmNode->isReadonly = sqlite3_uri_boolean(pDbFd->zPath,"readonly_shm",0); + rc = winHandleOpen(pNew->zFilename, &pShmNode->isReadonly, &h); + pShmNode->hSharedShm = h; } - if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1; - rc = winLockSharedMemory(pShmNode); - if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err; + /* If successful, link the new winShmNode into the global list. If an + ** error occurred, free the object. */ + if( rc==SQLITE_OK ){ + pShmNode->pNext = winShmNodeList; + winShmNodeList = pShmNode; + pNew = 0; + }else{ + sqlite3_mutex_free(pShmNode->mutex); + if( pShmNode->hSharedShm!=INVALID_HANDLE_VALUE ){ + osCloseHandle(pShmNode->hSharedShm); + } + } } - /* Make the new connection a child of the winShmNode */ - p->pShmNode = pShmNode; + /* If no error has occurred, link the winShm object to the winShmNode and + ** the winShm to pDbFd. */ + if( rc==SQLITE_OK ){ + sqlite3_mutex_enter(pShmNode->mutex); + p->pShmNode = pShmNode; + p->pWinShmNext = pShmNode->pWinShmList; + pShmNode->pWinShmList = p; #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) - p->id = pShmNode->nextShmId++; + p->id = pShmNode->nextShmId++; #endif - pShmNode->nRef++; - pDbFd->pShm = p; + pDbFd->pShm = p; + sqlite3_mutex_leave(pShmNode->mutex); + }else if( p ){ + sqlite3_free(p); + } + + assert( rc!=SQLITE_OK || pShmNode->isUnlocked==0 || pShmNode->nRegion==0 ); winShmLeaveMutex(); + sqlite3_free(pNew); - /* The reference count on pShmNode has already been incremented under - ** the cover of the winShmEnterMutex() mutex and the pointer from the - ** new (struct winShm) object to the pShmNode has been set. All that is - ** left to do is to link the new object into the linked list starting - ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex - ** mutex. - */ - sqlite3_mutex_enter(pShmNode->mutex); - p->pNext = pShmNode->pFirst; - pShmNode->pFirst = p; - sqlite3_mutex_leave(pShmNode->mutex); - return rc; + /* Open a file-handle on the *-shm file for this connection. This file-handle + ** is only used for locking. The mapping of the *-shm file is created using + ** the shared file handle in winShmNode.hSharedShm. */ + if( rc==SQLITE_OK && pShmNode->bUseSharedLockHandle==0 ){ + p->bReadonly = sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0); + rc = winHandleOpen(pShmNode->zFilename, &p->bReadonly, &p->hShm); + if( rc!=SQLITE_OK ){ + assert( p->hShm==INVALID_HANDLE_VALUE ); + winCloseSharedMemory(pDbFd, 0); + } + } - /* Jump here on any error */ -shm_open_err: - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); - winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */ - sqlite3_free(p); - sqlite3_free(pNew); - winShmLeaveMutex(); return rc; } @@ -50919,38 +53329,7 @@ static int winShmUnmap( sqlite3_file *fd, /* Database holding shared memory */ int deleteFlag /* Delete after closing if true */ ){ - winFile *pDbFd; /* Database holding shared-memory */ - winShm *p; /* The connection to be closed */ - winShmNode *pShmNode; /* The underlying shared-memory file */ - winShm **pp; /* For looping over sibling connections */ - - pDbFd = (winFile*)fd; - p = pDbFd->pShm; - if( p==0 ) return SQLITE_OK; - pShmNode = p->pShmNode; - - /* Remove connection p from the set of connections associated - ** with pShmNode */ - sqlite3_mutex_enter(pShmNode->mutex); - for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} - *pp = p->pNext; - - /* Free the connection p */ - sqlite3_free(p); - pDbFd->pShm = 0; - sqlite3_mutex_leave(pShmNode->mutex); - - /* If pShmNode->nRef has reached 0, then close the underlying - ** shared-memory file, too */ - winShmEnterMutex(); - assert( pShmNode->nRef>0 ); - pShmNode->nRef--; - if( pShmNode->nRef==0 ){ - winShmPurge(pDbFd->pVfs, deleteFlag); - } - winShmLeaveMutex(); - - return SQLITE_OK; + return winCloseSharedMemory((winFile*)fd, deleteFlag); } /* @@ -50964,10 +53343,9 @@ static int winShmLock( ){ winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */ winShm *p = pDbFd->pShm; /* The shared memory being locked */ - winShm *pX; /* For looping over all siblings */ winShmNode *pShmNode; int rc = SQLITE_OK; /* Result code */ - u16 mask; /* Mask of locks to take or release */ + u16 mask = (u16)((1U<<(ofst+n)) - (1U<pShmNode; @@ -50981,85 +53359,127 @@ static int winShmLock( || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); - mask = (u16)((1U<<(ofst+n)) - (1U<1 || mask==(1<mutex); - if( flags & SQLITE_SHM_UNLOCK ){ - u16 allMask = 0; /* Mask of locks held by siblings */ + /* Check that, if this to be a blocking lock, no locks that occur later + ** in the following list than the lock being obtained are already held: + ** + ** 1. Recovery lock (ofst==2). + ** 2. Checkpointer lock (ofst==1). + ** 3. Write lock (ofst==0). + ** 4. Read locks (ofst>=3 && ofstexclMask|p->sharedMask); + assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( + (ofst!=2 || lockMask==0) + && (ofst!=1 || lockMask==0 || lockMask==2) + && (ofst!=0 || lockMask<3) + && (ofst<3 || lockMask<(1<pFirst; pX; pX=pX->pNext){ - if( pX==p ) continue; - assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); - allMask |= pX->sharedMask; - } + /* Check if there is any work to do. There are three cases: + ** + ** a) An unlock operation where there are locks to unlock, + ** b) An shared lock where the requested lock is not already held + ** c) An exclusive lock where the requested lock is not already held + ** + ** The SQLite core never requests an exclusive lock that it already holds. + ** This is assert()ed immediately below. */ + assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK) + || 0==(p->exclMask & mask) + ); + if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask)) + || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask)) + || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)) + ){ + HANDLE h = p->hShm; - /* Unlock the system-level locks */ - if( (mask & allMask)==0 ){ - rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n); - }else{ - rc = SQLITE_OK; - } + if( flags & SQLITE_SHM_UNLOCK ){ + /* Case (a) - unlock. */ - /* Undo the local locks */ - if( rc==SQLITE_OK ){ - p->exclMask &= ~mask; - p->sharedMask &= ~mask; - } - }else if( flags & SQLITE_SHM_SHARED ){ - u16 allShared = 0; /* Union of locks held by connections other than "p" */ + assert( (p->exclMask & p->sharedMask)==0 ); + assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask ); + assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask ); - /* Find out which shared locks are already held by sibling connections. - ** If any sibling already holds an exclusive lock, go ahead and return - ** SQLITE_BUSY. - */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( (pX->exclMask & mask)!=0 ){ - rc = SQLITE_BUSY; - break; + assert( !(flags & SQLITE_SHM_SHARED) || n==1 ); + if( pShmNode->bUseSharedLockHandle ){ + h = pShmNode->hSharedShm; + if( flags & SQLITE_SHM_SHARED ){ + winShm *pShm; + sqlite3_mutex_enter(pShmNode->mutex); + for(pShm=pShmNode->pWinShmList; pShm; pShm=pShm->pWinShmNext){ + if( pShm!=p && (pShm->sharedMask & mask) ){ + /* Another connection within this process is also holding this + ** SHARED lock. So do not actually release the OS lock. */ + h = INVALID_HANDLE_VALUE; + break; + } + } + sqlite3_mutex_leave(pShmNode->mutex); + } } - allShared |= pX->sharedMask; - } - /* Get shared locks at the system level, if necessary */ - if( rc==SQLITE_OK ){ - if( (allShared & mask)==0 ){ - rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n); - }else{ - rc = SQLITE_OK; + if( h!=INVALID_HANDLE_VALUE ){ + rc = winHandleUnlock(h, ofst+WIN_SHM_BASE, n); } - } - /* Get the local shared locks */ - if( rc==SQLITE_OK ){ - p->sharedMask |= mask; - } - }else{ - /* Make sure no sibling connections hold locks that will block this - ** lock. If any do, return SQLITE_BUSY right away. - */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ - rc = SQLITE_BUSY; - break; + /* If successful, also clear the bits in sharedMask/exclMask */ + if( rc==SQLITE_OK ){ + p->exclMask = (p->exclMask & ~mask); + p->sharedMask = (p->sharedMask & ~mask); + } + }else{ + int bExcl = ((flags & SQLITE_SHM_EXCLUSIVE) ? 1 : 0); + DWORD nMs = winFileBusyTimeout(pDbFd); + + if( pShmNode->bUseSharedLockHandle ){ + winShm *pShm; + h = pShmNode->hSharedShm; + sqlite3_mutex_enter(pShmNode->mutex); + for(pShm=pShmNode->pWinShmList; pShm; pShm=pShm->pWinShmNext){ + if( bExcl ){ + if( (pShm->sharedMask|pShm->exclMask) & mask ){ + rc = SQLITE_BUSY; + h = INVALID_HANDLE_VALUE; + } + }else{ + if( pShm->sharedMask & mask ){ + h = INVALID_HANDLE_VALUE; + }else if( pShm->exclMask & mask ){ + rc = SQLITE_BUSY; + h = INVALID_HANDLE_VALUE; + } + } + } + sqlite3_mutex_leave(pShmNode->mutex); } - } - /* Get the exclusive locks at the system level. Then if successful - ** also mark the local connection as being locked. - */ - if( rc==SQLITE_OK ){ - rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n); + if( h!=INVALID_HANDLE_VALUE ){ + rc = winHandleLockTimeout(h, ofst+WIN_SHM_BASE, n, bExcl, nMs); + } if( rc==SQLITE_OK ){ - assert( (p->sharedMask & mask)==0 ); - p->exclMask |= mask; + if( bExcl ){ + p->exclMask = (p->exclMask | mask); + }else{ + p->sharedMask = (p->sharedMask | mask); + } } } } - sqlite3_mutex_leave(pShmNode->mutex); - OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n", - osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask, - sqlite3ErrName(rc))); + + OSTRACE(( + "SHM-LOCK(%d,%d,%d) pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x," + " rc=%s\n", + ofst, n, flags, + osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask, + sqlite3ErrName(rc)) + ); return rc; } @@ -51121,15 +53541,17 @@ static int winShmMap( sqlite3_mutex_enter(pShmNode->mutex); if( pShmNode->isUnlocked ){ - rc = winLockSharedMemory(pShmNode); + /* Take the DMS lock. */ + assert( pShmNode->nRegion==0 ); + rc = winLockSharedMemory(pShmNode, winFileBusyTimeout(pDbFd)); if( rc!=SQLITE_OK ) goto shmpage_out; - pShmNode->isUnlocked = 0; } - assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); + assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); if( pShmNode->nRegion<=iRegion ){ + HANDLE hShared = pShmNode->hSharedShm; struct ShmRegion *apNew; /* New aRegion[] array */ - int nByte = (iRegion+1)*szRegion; /* Minimum required file size */ + i64 nByte = ((i64)iRegion+1)*(i64)szRegion; /* Minimum file size */ sqlite3_int64 sz; /* Current size of wal-index file */ pShmNode->szRegion = szRegion; @@ -51138,10 +53560,9 @@ static int winShmMap( ** Check to see if it has been allocated (i.e. if the wal-index file is ** large enough to contain the requested region). */ - rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz); + rc = winHandleSize(hShared, &sz); if( rc!=SQLITE_OK ){ - rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(), - "winShmMap1", pDbFd->zPath); + rc = winLogError(rc, osGetLastError(), "winShmMap1", pDbFd->zPath); goto shmpage_out; } @@ -51150,20 +53571,18 @@ static int winShmMap( ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned. ** ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate - ** the requested memory region. - */ + ** the requested memory region. */ if( !isWrite ) goto shmpage_out; - rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte); + rc = winHandleTruncate(hShared, nByte); if( rc!=SQLITE_OK ){ - rc = winLogError(SQLITE_IOERR_SHMSIZE, osGetLastError(), - "winShmMap2", pDbFd->zPath); + rc = winLogError(rc, osGetLastError(), "winShmMap2", pDbFd->zPath); goto shmpage_out; } } /* Map the requested memory region into this processes address space. */ - apNew = (struct ShmRegion *)sqlite3_realloc64( - pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0]) + apNew = (struct ShmRegion*)sqlite3_realloc64( + pShmNode->aRegion, ((i64)iRegion+1)*sizeof(apNew[0]) ); if( !apNew ){ rc = SQLITE_IOERR_NOMEM_BKPT; @@ -51180,34 +53599,20 @@ static int winShmMap( HANDLE hMap = NULL; /* file-mapping handle */ void *pMap = 0; /* Mapped memory region */ -#if SQLITE_OS_WINRT - hMap = osCreateFileMappingFromApp(pShmNode->hFile.h, - NULL, protect, nByte, NULL - ); -#elif defined(SQLITE_WIN32_HAS_WIDE) - hMap = osCreateFileMappingW(pShmNode->hFile.h, - NULL, protect, 0, nByte, NULL - ); +#if defined(SQLITE_WIN32_HAS_WIDE) + hMap = osCreateFileMappingW(hShared, NULL, protect, 0, nByte, NULL); #elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA - hMap = osCreateFileMappingA(pShmNode->hFile.h, - NULL, protect, 0, nByte, NULL - ); + hMap = osCreateFileMappingA(hShared, NULL, protect, 0, nByte, NULL); #endif - OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n", + OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%lld, rc=%s\n", osGetCurrentProcessId(), pShmNode->nRegion, nByte, hMap ? "ok" : "failed")); if( hMap ){ - int iOffset = pShmNode->nRegion*szRegion; + i64 iOffset = pShmNode->nRegion*szRegion; int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; -#if SQLITE_OS_WINRT - pMap = osMapViewOfFileFromApp(hMap, flags, - iOffset - iOffsetShift, szRegion + iOffsetShift - ); -#else pMap = osMapViewOfFile(hMap, flags, - 0, iOffset - iOffsetShift, szRegion + iOffsetShift + 0, iOffset - iOffsetShift, (i64)szRegion + iOffsetShift ); -#endif OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n", osGetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion, pMap ? "ok" : "failed")); @@ -51228,14 +53633,16 @@ static int winShmMap( shmpage_out: if( pShmNode->nRegion>iRegion ){ - int iOffset = iRegion*szRegion; + i64 iOffset = (i64)iRegion*(i64)szRegion; int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; char *p = (char *)pShmNode->aRegion[iRegion].pMap; *pp = (void *)&p[iOffsetShift]; }else{ *pp = 0; } - if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; + if( pShmNode->isReadonly && rc==SQLITE_OK ){ + rc = SQLITE_READONLY; + } sqlite3_mutex_leave(pShmNode->mutex); return rc; } @@ -51338,9 +53745,7 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ flags |= FILE_MAP_WRITE; } #endif -#if SQLITE_OS_WINRT - pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL); -#elif defined(SQLITE_WIN32_HAS_WIDE) +#if defined(SQLITE_WIN32_HAS_WIDE) pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect, (DWORD)((nMap>>32) & 0xffffffff), (DWORD)(nMap & 0xffffffff), NULL); @@ -51360,11 +53765,7 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ } assert( (nMap % winSysInfo.dwPageSize)==0 ); assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff ); -#if SQLITE_OS_WINRT - pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap); -#else pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap); -#endif if( pNew==NULL ){ osCloseHandle(pFd->hMap); pFd->hMap = NULL; @@ -51555,47 +53956,6 @@ static winVfsAppData winNolockAppData = { ** sqlite3_vfs object. */ -#if defined(__CYGWIN__) -/* -** Convert a filename from whatever the underlying operating system -** supports for filenames into UTF-8. Space to hold the result is -** obtained from malloc and must be freed by the calling function. -*/ -static char *winConvertToUtf8Filename(const void *zFilename){ - char *zConverted = 0; - if( osIsNT() ){ - zConverted = winUnicodeToUtf8(zFilename); - } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI()); - } -#endif - /* caller will handle out of memory */ - return zConverted; -} -#endif - -/* -** Convert a UTF-8 filename into whatever form the underlying -** operating system wants filenames in. Space to hold the result -** is obtained from malloc and must be freed by the calling -** function. -*/ -static void *winConvertFromUtf8Filename(const char *zFilename){ - void *zConverted = 0; - if( osIsNT() ){ - zConverted = winUtf8ToUnicode(zFilename); - } -#ifdef SQLITE_WIN32_HAS_ANSI - else{ - zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI()); - } -#endif - /* caller will handle out of memory */ - return zConverted; -} - /* ** This function returns non-zero if the specified UTF-8 string buffer ** ends with a directory separator character or one was successfully @@ -51608,7 +53968,14 @@ static int winMakeEndInDirSep(int nBuf, char *zBuf){ if( winIsDirSep(zBuf[nLen-1]) ){ return 1; }else if( nLen+1mxPathname; nBuf = nMax + 2; + nMax = pVfs->mxPathname; + nBuf = 2 + (i64)nMax; zBuf = sqlite3MallocZero( nBuf ); if( !zBuf ){ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); @@ -51685,7 +54053,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ } #if defined(__CYGWIN__) - else{ + else if( osGetenv!=NULL ){ static const char *azDirs[] = { 0, /* getenv("SQLITE_TMPDIR") */ 0, /* getenv("TMPDIR") */ @@ -51701,11 +54069,11 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ unsigned int i; const char *zDir = 0; - if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); - if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); - if( !azDirs[2] ) azDirs[2] = getenv("TMP"); - if( !azDirs[3] ) azDirs[3] = getenv("TEMP"); - if( !azDirs[4] ) azDirs[4] = getenv("USERPROFILE"); + if( !azDirs[0] ) azDirs[0] = osGetenv("SQLITE_TMPDIR"); + if( !azDirs[1] ) azDirs[1] = osGetenv("TMPDIR"); + if( !azDirs[2] ) azDirs[2] = osGetenv("TMP"); + if( !azDirs[3] ) azDirs[3] = osGetenv("TEMP"); + if( !azDirs[4] ) azDirs[4] = osGetenv("USERPROFILE"); for(i=0; ih = INVALID_HANDLE_VALUE; -#if SQLITE_OS_WINRT - if( !zUtf8Name && !sqlite3_temp_directory ){ - sqlite3_log(SQLITE_ERROR, - "sqlite3_temp_directory variable should be set for WinRT"); - } -#endif - /* If the second argument to this function is NULL, generate a ** temporary file name to use */ @@ -52075,31 +54409,6 @@ static int winOpen( #endif if( osIsNT() ){ -#if SQLITE_OS_WINRT - CREATEFILE2_EXTENDED_PARAMETERS extendedParameters; - extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); - extendedParameters.dwFileAttributes = - dwFlagsAndAttributes & FILE_ATTRIBUTE_MASK; - extendedParameters.dwFileFlags = dwFlagsAndAttributes & FILE_FLAG_MASK; - extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; - extendedParameters.lpSecurityAttributes = NULL; - extendedParameters.hTemplateFile = NULL; - do{ - h = osCreateFile2((LPCWSTR)zConverted, - dwDesiredAccess, - dwShareMode, - dwCreationDisposition, - &extendedParameters); - if( h!=INVALID_HANDLE_VALUE ) break; - if( isReadWrite ){ - int rc2, isRO = 0; - sqlite3BeginBenignMalloc(); - rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); - sqlite3EndBenignMalloc(); - if( rc2==SQLITE_OK && isRO ) break; - } - }while( winRetryIoerr(&cnt, &lastErrno) ); -#else do{ h = osCreateFileW((LPCWSTR)zConverted, dwDesiredAccess, @@ -52109,14 +54418,13 @@ static int winOpen( NULL); if( h!=INVALID_HANDLE_VALUE ) break; if( isReadWrite ){ - int rc2, isRO = 0; + int rc2; sqlite3BeginBenignMalloc(); - rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); + rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO); sqlite3EndBenignMalloc(); if( rc2==SQLITE_OK && isRO ) break; } }while( winRetryIoerr(&cnt, &lastErrno) ); -#endif } #ifdef SQLITE_WIN32_HAS_ANSI else{ @@ -52129,9 +54437,9 @@ static int winOpen( NULL); if( h!=INVALID_HANDLE_VALUE ) break; if( isReadWrite ){ - int rc2, isRO = 0; + int rc2; sqlite3BeginBenignMalloc(); - rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO); + rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO); sqlite3EndBenignMalloc(); if( rc2==SQLITE_OK && isRO ) break; } @@ -52146,7 +54454,7 @@ static int winOpen( if( h==INVALID_HANDLE_VALUE ){ sqlite3_free(zConverted); sqlite3_free(zTmpname); - if( isReadWrite && !isExclusive ){ + if( isReadWrite && isRO && !isExclusive ){ return winOpen(pVfs, zName, id, ((flags|SQLITE_OPEN_READONLY) & ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), @@ -52253,25 +54561,7 @@ static int winDelete( } if( osIsNT() ){ do { -#if SQLITE_OS_WINRT - WIN32_FILE_ATTRIBUTE_DATA sAttrData; - memset(&sAttrData, 0, sizeof(sAttrData)); - if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard, - &sAttrData) ){ - attr = sAttrData.dwFileAttributes; - }else{ - lastErrno = osGetLastError(); - if( lastErrno==ERROR_FILE_NOT_FOUND - || lastErrno==ERROR_PATH_NOT_FOUND ){ - rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ - }else{ - rc = SQLITE_ERROR; - } - break; - } -#else attr = osGetFileAttributesW(zConverted); -#endif if ( attr==INVALID_FILE_ATTRIBUTES ){ lastErrno = osGetLastError(); if( lastErrno==ERROR_FILE_NOT_FOUND @@ -52348,8 +54638,14 @@ static int winAccess( int rc = 0; DWORD lastErrno = 0; void *zConverted; + int noRetry = 0; /* Do not use winRetryIoerr() */ UNUSED_PARAMETER(pVfs); + if( (flags & NORETRY)!=0 ){ + noRetry = 1; + flags &= ~NORETRY; + } + SimulateIOError( return SQLITE_IOERR_ACCESS; ); OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n", zFilename, flags, pResOut)); @@ -52372,7 +54668,10 @@ static int winAccess( memset(&sAttrData, 0, sizeof(sAttrData)); while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, GetFileExInfoStandard, - &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){} + &sAttrData)) + && !noRetry + && winRetryIoerr(&cnt, &lastErrno) + ){ /* Loop until true */} if( rc ){ /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file ** as if it does not exist. @@ -52385,6 +54684,7 @@ static int winAccess( attr = sAttrData.dwFileAttributes; } }else{ + if( noRetry ) lastErrno = osGetLastError(); winLogIoerr(cnt, __LINE__); if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){ sqlite3_free(zConverted); @@ -52440,6 +54740,7 @@ static BOOL winIsDriveLetterAndColon( return ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' ); } +#ifdef _WIN32 /* ** Returns non-zero if the specified path name should be used verbatim. If ** non-zero is returned from this function, the calling function must simply @@ -52476,6 +54777,70 @@ static BOOL winIsVerbatimPathname( */ return FALSE; } +#endif /* _WIN32 */ + +#ifdef __CYGWIN__ +/* +** Simplify a filename into its canonical form +** by making the following changes: +** +** * convert any '/' to '\' (win32) or reverse (Cygwin) +** * removing any trailing and duplicate / (except for UNC paths) +** * convert /./ into just / +** +** Changes are made in-place. Return the new name length. +** +** The original filename is in z[0..]. If the path is shortened, +** no-longer used bytes will be written by '\0'. +*/ +static void winSimplifyName(char *z){ + int i, j; + for(i=j=0; z[i]; ++i){ + if( winIsDirSep(z[i]) ){ +#if !defined(SQLITE_TEST) + /* Some test-cases assume that "./foo" and "foo" are different */ + if( z[i+1]=='.' && winIsDirSep(z[i+2]) ){ + ++i; + continue; + } +#endif + if( !z[i+1] || (winIsDirSep(z[i+1]) && (i!=0)) ){ + continue; + } + z[j++] = osGetenv?'/':'\\'; + }else{ + z[j++] = z[i]; + } + } + while(jnOut ){ + /* SQLite assumes that xFullPathname() nul-terminates the output buffer + ** even if it returns an error. */ + zOut[iOff] = '\0'; + return SQLITE_CANTOPEN_BKPT; + } + sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); + return SQLITE_OK; +} +#endif /* __CYGWIN__ */ /* ** Turn a relative pathname into a full pathname. Write the full @@ -52488,8 +54853,8 @@ static int winFullPathnameNoMutex( int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) - DWORD nByte; +#if !SQLITE_OS_WINCE + int nByte; void *zConverted; char *zOut; #endif @@ -52502,64 +54867,82 @@ static int winFullPathnameNoMutex( zRelative++; } -#if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); - UNUSED_PARAMETER(nFull); - assert( nFull>=pVfs->mxPathname ); - if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ - /* - ** NOTE: We are dealing with a relative path name and the data - ** directory has been set. Therefore, use it as the basis - ** for converting the relative path name to an absolute - ** one by prepending the data directory and a slash. - */ - char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); - if( !zOut ){ - return SQLITE_IOERR_NOMEM_BKPT; - } - if( cygwin_conv_path( - (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) | - CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){ - sqlite3_free(zOut); - return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, - "winFullPathname1", zRelative); - }else{ - char *zUtf8 = winConvertToUtf8Filename(zOut); - if( !zUtf8 ){ - sqlite3_free(zOut); - return SQLITE_IOERR_NOMEM_BKPT; - } - sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", - sqlite3_data_directory, winGetDirSep(), zUtf8); - sqlite3_free(zUtf8); - sqlite3_free(zOut); - } - }else{ - char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); - if( !zOut ){ - return SQLITE_IOERR_NOMEM_BKPT; - } - if( cygwin_conv_path( - (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A), - zRelative, zOut, pVfs->mxPathname+1)<0 ){ - sqlite3_free(zOut); - return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, - "winFullPathname2", zRelative); - }else{ - char *zUtf8 = winConvertToUtf8Filename(zOut); - if( !zUtf8 ){ - sqlite3_free(zOut); - return SQLITE_IOERR_NOMEM_BKPT; - } - sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8); - sqlite3_free(zUtf8); - sqlite3_free(zOut); + +#ifdef __CYGWIN__ + if( osGetcwd ){ + zFull[nFull-1] = '\0'; + if( !winIsDriveLetterAndColon(zRelative) || !winIsDirSep(zRelative[2]) ){ + int rc = SQLITE_OK; + int nLink = 1; /* Number of symbolic links followed so far */ + const char *zIn = zRelative; /* Input path for each iteration of loop */ + char *zDel = 0; + struct stat buf; + + UNUSED_PARAMETER(pVfs); + + do { + /* Call lstat() on path zIn. Set bLink to true if the path is a symbolic + ** link, or false otherwise. */ + int bLink = 0; + if( osLstat && osReadlink ) { + if( osLstat(zIn, &buf)!=0 ){ + int myErrno = osErrno; + if( myErrno!=ENOENT ){ + rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)myErrno, "lstat", zIn); + } + }else{ + bLink = ((buf.st_mode & 0170000) == 0120000); + } + + if( bLink ){ + if( zDel==0 ){ + zDel = sqlite3MallocZero(nFull); + if( zDel==0 ) rc = SQLITE_NOMEM; + }else if( ++nLink>SQLITE_MAX_SYMLINKS ){ + rc = SQLITE_CANTOPEN_BKPT; + } + + if( rc==SQLITE_OK ){ + nByte = osReadlink(zIn, zDel, nFull-1); + if( nByte ==(DWORD)-1 ){ + rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "readlink", zIn); + }else{ + if( zDel[0]!='/' ){ + int n; + for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); + if( nByte+n+1>nFull ){ + rc = SQLITE_CANTOPEN_BKPT; + }else{ + memmove(&zDel[n], zDel, nByte+1); + memcpy(zDel, zIn, n); + nByte += n; + } + } + zDel[nByte] = '\0'; + } + } + + zIn = zDel; + } + } + + assert( rc!=SQLITE_OK || zIn!=zFull || zIn[0]=='/' ); + if( rc==SQLITE_OK && zIn!=zFull ){ + rc = mkFullPathname(zIn, zFull, nFull); + } + if( bLink==0 ) break; + zIn = zFull; + }while( rc==SQLITE_OK ); + + sqlite3_free(zDel); + winSimplifyName(zFull); + return rc; } } - return SQLITE_OK; -#endif +#endif /* __CYGWIN__ */ -#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__) +#if SQLITE_OS_WINCE && defined(_WIN32) SimulateIOError( return SQLITE_ERROR ); /* WinCE has no concept of a relative pathname, or so I am told. */ /* WinRT has no way to convert a relative path to an absolute one. */ @@ -52578,7 +54961,8 @@ static int winFullPathnameNoMutex( return SQLITE_OK; #endif -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) +#if !SQLITE_OS_WINCE +#if defined(_WIN32) /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. This function could fail if, for example, the @@ -52596,6 +54980,7 @@ static int winFullPathnameNoMutex( sqlite3_data_directory, winGetDirSep(), zRelative); return SQLITE_OK; } +#endif zConverted = winConvertFromUtf8Filename(zRelative); if( zConverted==0 ){ return SQLITE_IOERR_NOMEM_BKPT; @@ -52634,13 +55019,12 @@ static int winFullPathnameNoMutex( return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), "winFullPathname3", zRelative); } - nByte += 3; - zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); + zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) + 3*sizeof(zTemp[0]) ); if( zTemp==0 ){ sqlite3_free(zConverted); return SQLITE_IOERR_NOMEM_BKPT; } - nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0); + nByte = osGetFullPathNameA((char*)zConverted, nByte+3, zTemp, 0); if( nByte==0 ){ sqlite3_free(zConverted); sqlite3_free(zTemp); @@ -52653,7 +55037,26 @@ static int winFullPathnameNoMutex( } #endif if( zOut ){ +#ifdef __CYGWIN__ + if( memcmp(zOut, "\\\\?\\", 4) ){ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut); + }else if( memcmp(zOut+4, "UNC\\", 4) ){ + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+4); + }else{ + char *p = zOut+6; + *p = '\\'; + if( osGetcwd ){ + /* On Cygwin, UNC paths use forward slashes */ + while( *p ){ + if( *p=='\\' ) *p = '/'; + ++p; + } + } + sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+6); + } +#else sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut); +#endif /* __CYGWIN__ */ sqlite3_free(zOut); return SQLITE_OK; }else{ @@ -52683,35 +55086,14 @@ static int winFullPathname( */ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ HANDLE h; -#if defined(__CYGWIN__) - int nFull = pVfs->mxPathname+1; - char *zFull = sqlite3MallocZero( nFull ); - void *zConverted = 0; - if( zFull==0 ){ - OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); - return 0; - } - if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){ - sqlite3_free(zFull); - OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); - return 0; - } - zConverted = winConvertFromUtf8Filename(zFull); - sqlite3_free(zFull); -#else void *zConverted = winConvertFromUtf8Filename(zFilename); UNUSED_PARAMETER(pVfs); -#endif if( zConverted==0 ){ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); return 0; } if( osIsNT() ){ -#if SQLITE_OS_WINRT - h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0); -#else h = osLoadLibraryW((LPCWSTR)zConverted); -#endif } #ifdef SQLITE_WIN32_HAS_ANSI else{ @@ -52793,23 +55175,16 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ DWORD pid = osGetCurrentProcessId(); xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD)); } -#if SQLITE_OS_WINRT - { - ULONGLONG cnt = osGetTickCount64(); - xorMemory(&e, (unsigned char*)&cnt, sizeof(ULONGLONG)); - } -#else { DWORD cnt = osGetTickCount(); xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD)); } -#endif /* SQLITE_OS_WINRT */ { LARGE_INTEGER i; osQueryPerformanceCounter(&i); xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER)); } -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID +#if !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID { UUID id; memset(&id, 0, sizeof(UUID)); @@ -52819,7 +55194,7 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ osUuidCreateSequential(&id); xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); } -#endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */ +#endif /* !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID */ return e.nXor>nBuf ? nBuf : e.nXor; #endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */ } @@ -53050,15 +55425,16 @@ SQLITE_API int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==80 ); + assert( ArraySize(aSyscall)==81 ); + assert( strcmp(aSyscall[0].zName,"AreFileApisANSI")==0 ); + assert( strcmp(aSyscall[20].zName,"GetFileAttributesA")==0 ); + assert( strcmp(aSyscall[40].zName,"HeapReAlloc")==0 ); + assert( strcmp(aSyscall[60].zName,"WideCharToMultiByte")==0 ); + assert( strcmp(aSyscall[80].zName,"cygwin_conv_path")==0 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); -#if SQLITE_OS_WINRT - osGetNativeSystemInfo(&winSysInfo); -#else osGetSystemInfo(&winSysInfo); -#endif assert( winSysInfo.dwAllocationGranularity>0 ); assert( winSysInfo.dwPageSize>0 ); @@ -53082,17 +55458,9 @@ SQLITE_API int sqlite3_os_init(void){ } SQLITE_API int sqlite3_os_end(void){ -#if SQLITE_OS_WINRT - if( sleepObj!=NULL ){ - osCloseHandle(sleepObj); - sleepObj = NULL; - } -#endif - #ifndef SQLITE_OMIT_WAL winBigLock = 0; #endif - return SQLITE_OK; } @@ -53669,13 +56037,13 @@ static int memdbOpen( } if( p==0 ){ MemStore **apNew; - p = sqlite3Malloc( sizeof(*p) + szName + 3 ); + p = sqlite3Malloc( sizeof(*p) + (i64)szName + 3 ); if( p==0 ){ sqlite3_mutex_leave(pVfsMutex); return SQLITE_NOMEM; } apNew = sqlite3Realloc(memdb_g.apMemStore, - sizeof(apNew[0])*(memdb_g.nMemStore+1) ); + sizeof(apNew[0])*(1+(i64)memdb_g.nMemStore) ); if( apNew==0 ){ sqlite3_free(p); sqlite3_mutex_leave(pVfsMutex); @@ -53861,7 +56229,7 @@ SQLITE_API unsigned char *sqlite3_serialize( sqlite3_int64 sz; int szPage = 0; sqlite3_stmt *pStmt = 0; - unsigned char *pOut; + unsigned char *pOut = 0; char *zSql; int rc; @@ -53871,12 +56239,13 @@ SQLITE_API unsigned char *sqlite3_serialize( return 0; } #endif + sqlite3_mutex_enter(db->mutex); if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; p = memdbFromDbSchema(db, zSchema); iDb = sqlite3FindDbName(db, zSchema); if( piSize ) *piSize = -1; - if( iDb<0 ) return 0; + if( iDb<0 ) goto serialize_out; if( p ){ MemStore *pStore = p->pStore; assert( pStore->pMutex==0 ); @@ -53887,19 +56256,17 @@ SQLITE_API unsigned char *sqlite3_serialize( pOut = sqlite3_malloc64( pStore->sz ); if( pOut ) memcpy(pOut, pStore->aData, pStore->sz); } - return pOut; + goto serialize_out; } pBt = db->aDb[iDb].pBt; - if( pBt==0 ) return 0; + if( pBt==0 ) goto serialize_out; szPage = sqlite3BtreeGetPageSize(pBt); zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema); rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM; sqlite3_free(zSql); - if( rc ) return 0; + if( rc ) goto serialize_out; rc = sqlite3_step(pStmt); - if( rc!=SQLITE_ROW ){ - pOut = 0; - }else{ + if( rc==SQLITE_ROW ){ sz = sqlite3_column_int64(pStmt, 0)*szPage; if( sz==0 ){ sqlite3_reset(pStmt); @@ -53933,6 +56300,9 @@ SQLITE_API unsigned char *sqlite3_serialize( } } sqlite3_finalize(pStmt); + + serialize_out: + sqlite3_mutex_leave(db->mutex); return pOut; } @@ -53978,10 +56348,10 @@ SQLITE_API int sqlite3_deserialize( if( rc ) goto end_deserialize; db->init.iDb = (u8)iDb; db->init.reopenMemdb = 1; - rc = sqlite3_step(pStmt); + sqlite3_step(pStmt); db->init.reopenMemdb = 0; - if( rc!=SQLITE_DONE ){ - rc = SQLITE_ERROR; + rc = sqlite3_finalize(pStmt); + if( rc!=SQLITE_OK ){ goto end_deserialize; } p = memdbFromDbSchema(db, zSchema); @@ -54002,7 +56372,6 @@ SQLITE_API int sqlite3_deserialize( } end_deserialize: - sqlite3_finalize(pStmt); if( pData && (mFlags & SQLITE_DESERIALIZE_FREEONCLOSE)!=0 ){ sqlite3_free(pData); } @@ -54108,7 +56477,7 @@ SQLITE_PRIVATE int sqlite3MemdbInit(void){ ** no fewer collisions than the no-op *1. */ #define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT) -#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *)) +#define BITVEC_NPTR ((u32)(BITVEC_USIZE/sizeof(Bitvec *))) /* @@ -54148,6 +56517,7 @@ struct Bitvec { } u; }; + /* ** Create a new bitmap object able to handle bits between 0 and iSize, ** inclusive. Return a pointer to the new object. Return NULL if @@ -54257,7 +56627,9 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){ }else{ memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash)); memset(p->u.apSub, 0, sizeof(p->u.apSub)); - p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR; + p->iDivisor = p->iSize/BITVEC_NPTR; + if( (p->iSize%BITVEC_NPTR)!=0 ) p->iDivisor++; + if( p->iDivisoriDivisor = BITVEC_NBIT; rc = sqlite3BitvecSet(p, i); for(j=0; jiSize<=BITVEC_NBIT ){ - p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1))); + p->u.aBitmap[i/BITVEC_SZELEM] &= ~(BITVEC_TELEM)(1<<(i&(BITVEC_SZELEM-1))); }else{ unsigned int j; u32 *aiValues = pBuf; @@ -54334,6 +56706,52 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){ return p->iSize; } +#ifdef SQLITE_DEBUG +/* +** Show the content of a Bitvec option and its children. Indent +** everything by n spaces. Add x to each bitvec value. +** +** From a debugger such as gdb, one can type: +** +** call sqlite3ShowBitvec(p) +** +** For some Bitvec p and see a recursive view of the Bitvec's content. +*/ +static void showBitvec(Bitvec *p, int n, unsigned x){ + int i; + if( p==0 ){ + printf("NULL\n"); + return; + } + printf("Bitvec 0x%p iSize=%u", p, p->iSize); + if( p->iSize<=BITVEC_NBIT ){ + printf(" bitmap\n"); + printf("%*s bits:", n, ""); + for(i=1; i<=BITVEC_NBIT; i++){ + if( sqlite3BitvecTest(p,i) ) printf(" %u", x+(unsigned)i); + } + printf("\n"); + }else if( p->iDivisor==0 ){ + printf(" hash with %u entries\n", p->nSet); + printf("%*s bits:", n, ""); + for(i=0; iu.aHash[i] ) printf(" %u", x+(unsigned)p->u.aHash[i]); + } + printf("\n"); + }else{ + printf(" sub-bitvec with iDivisor=%u\n", p->iDivisor); + for(i=0; iu.apSub[i]==0 ) continue; + printf("%*s apSub[%d]=", n, "", i); + showBitvec(p->u.apSub[i], n+4, i*p->iDivisor); + } + } +} +SQLITE_PRIVATE void sqlite3ShowBitvec(Bitvec *p){ + showBitvec(p, 0, 0); +} +#endif + #ifndef SQLITE_UNTESTABLE /* ** Let V[] be an array of unsigned characters sufficient to hold @@ -54342,9 +56760,10 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){ ** individual bits within V. */ #define SETBIT(V,I) V[I>>3] |= (1<<(I&7)) -#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7)) +#define CLEARBIT(V,I) V[I>>3] &= ~(BITVEC_TELEM)(1<<(I&7)) #define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0 + /* ** This routine runs an extensive test of the Bitvec code. ** @@ -54353,7 +56772,7 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){ ** by 0, 1, or 3 operands, depending on the opcode. Another ** opcode follows immediately after the last operand. ** -** There are 6 opcodes numbered from 0 through 5. 0 is the +** There are opcodes numbered starting with 0. 0 is the ** "halt" opcode and causes the test to end. ** ** 0 Halt and return the number of errors @@ -54362,18 +56781,25 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){ ** 3 N Set N randomly chosen bits ** 4 N Clear N randomly chosen bits ** 5 N S X Set N bits from S increment X in array only, not in bitvec +** 6 Invoice sqlite3ShowBitvec() on the Bitvec object so far +** 7 X Show compile-time parameters and the hash of X ** ** The opcodes 1 through 4 perform set and clear operations are performed ** on both a Bitvec object and on a linear array of bits obtained from malloc. ** Opcode 5 works on the linear array only, not on the Bitvec. ** Opcode 5 is used to deliberately induce a fault in order to -** confirm that error detection works. +** confirm that error detection works. Opcodes 6 and greater are +** state output opcodes. Opcodes 6 and greater are no-ops unless +** SQLite has been compiled with SQLITE_DEBUG. ** ** At the conclusion of the test the linear array is compared ** against the Bitvec object. If there are any differences, ** an error is returned. If they are the same, zero is returned. ** ** If a memory allocation error occurs, return -1. +** +** sz is the size of the Bitvec. Or if sz is negative, make the size +** 2*(unsigned)(-sz) and disabled the linear vector check. */ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){ Bitvec *pBitvec = 0; @@ -54384,10 +56810,15 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){ /* Allocate the Bitvec to be tested and a linear array of ** bits to act as the reference */ - pBitvec = sqlite3BitvecCreate( sz ); - pV = sqlite3MallocZero( (sz+7)/8 + 1 ); + if( sz<=0 ){ + pBitvec = sqlite3BitvecCreate( 2*(unsigned)(-sz) ); + pV = 0; + }else{ + pBitvec = sqlite3BitvecCreate( sz ); + pV = sqlite3MallocZero( (7+(i64)sz)/8 + 1 ); + } pTmpSpace = sqlite3_malloc64(BITVEC_SZ); - if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; + if( pBitvec==0 || pTmpSpace==0 || (pV==0 && sz>0) ) goto bitvec_end; /* NULL pBitvec tests */ sqlite3BitvecSet(0, 1); @@ -54396,6 +56827,24 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){ /* Run the program */ pc = i = 0; while( (op = aOp[pc])!=0 ){ + if( op>=6 ){ +#ifdef SQLITE_DEBUG + if( op==6 ){ + sqlite3ShowBitvec(pBitvec); + }else if( op==7 ){ + printf("BITVEC_SZ = %d (%d by sizeof)\n", + BITVEC_SZ, (int)sizeof(Bitvec)); + printf("BITVEC_USIZE = %d\n", (int)BITVEC_USIZE); + printf("BITVEC_NELEM = %d\n", (int)BITVEC_NELEM); + printf("BITVEC_NBIT = %d\n", (int)BITVEC_NBIT); + printf("BITVEC_NINT = %d\n", (int)BITVEC_NINT); + printf("BITVEC_MXHASH = %d\n", (int)BITVEC_MXHASH); + printf("BITVEC_NPTR = %d\n", (int)BITVEC_NPTR); + } +#endif + pc++; + continue; + } switch( op ){ case 1: case 2: @@ -54417,12 +56866,12 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){ pc += nx; i = (i & 0x7fffffff)%sz; if( (op & 1)!=0 ){ - SETBIT(pV, (i+1)); + if( pV ) SETBIT(pV, (i+1)); if( op!=5 ){ if( sqlite3BitvecSet(pBitvec, i+1) ) goto bitvec_end; } }else{ - CLEARBIT(pV, (i+1)); + if( pV ) CLEARBIT(pV, (i+1)); sqlite3BitvecClear(pBitvec, i+1, pTmpSpace); } } @@ -54432,14 +56881,18 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){ ** match (rc==0). Change rc to non-zero if a discrepancy ** is found. */ - rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1) - + sqlite3BitvecTest(pBitvec, 0) - + (sqlite3BitvecSize(pBitvec) - sz); - for(i=1; i<=sz; i++){ - if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){ - rc = i; - break; + if( pV ){ + rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1) + + sqlite3BitvecTest(pBitvec, 0) + + (sqlite3BitvecSize(pBitvec) - sz); + for(i=1; i<=sz; i++){ + if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){ + rc = i; + break; + } } + }else{ + rc = 0; } /* Free allocated structure */ @@ -55626,10 +58079,6 @@ static SQLITE_WSD struct PCacheGlobal { sqlite3_mutex *mutex; /* Mutex for accessing the following: */ PgFreeslot *pFree; /* Free page blocks */ int nFreeSlot; /* Number of unused pcache slots */ - /* The following value requires a mutex to change. We skip the mutex on - ** reading because (1) most platforms read a 32-bit integer atomically and - ** (2) even if an incorrect value is read, no great harm is done since this - ** is really just an optimization. */ int bUnderPressure; /* True if low on PAGECACHE memory */ } pcache1_g; @@ -55677,7 +58126,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ pcache1.nReserve = n>90 ? 10 : (n/10 + 1); pcache1.pStart = pBuf; pcache1.pFree = 0; - pcache1.bUnderPressure = 0; + AtomicStore(&pcache1.bUnderPressure,0); while( n-- ){ p = (PgFreeslot*)pBuf; p->pNext = pcache1.pFree; @@ -55707,22 +58156,24 @@ static int pcache1InitBulk(PCache1 *pCache){ if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){ szBulk = pCache->szAlloc*(i64)pCache->nMax; } - zBulk = pCache->pBulk = sqlite3Malloc( szBulk ); - sqlite3EndBenignMalloc(); - if( zBulk ){ - int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc; - do{ - PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; - pX->page.pBuf = zBulk; - pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX)); - assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) ); - pX->isBulkLocal = 1; - pX->isAnchor = 0; - pX->pNext = pCache->pFree; - pX->pLruPrev = 0; /* Initializing this saves a valgrind error */ - pCache->pFree = pX; - zBulk += pCache->szAlloc; - }while( --nBulk ); + if( szBulk>=pCache->szAlloc ){ + zBulk = pCache->pBulk = sqlite3Malloc( szBulk ); + sqlite3EndBenignMalloc(); + if( zBulk ){ + int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc; + do{ + PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; + pX->page.pBuf = zBulk; + pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX)); + assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) ); + pX->isBulkLocal = 1; + pX->isAnchor = 0; + pX->pNext = pCache->pFree; + pX->pLruPrev = 0; /* Initializing this saves a valgrind error */ + pCache->pFree = pX; + zBulk += pCache->szAlloc; + }while( --nBulk ); + } } return pCache->pFree!=0; } @@ -55745,7 +58196,7 @@ static void *pcache1Alloc(int nByte){ if( p ){ pcache1.pFree = pcache1.pFree->pNext; pcache1.nFreeSlot--; - pcache1.bUnderPressure = pcache1.nFreeSlot=0 ); sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte); sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1); @@ -55784,7 +58235,7 @@ static void pcache1Free(void *p){ pSlot->pNext = pcache1.pFree; pcache1.pFree = pSlot; pcache1.nFreeSlot++; - pcache1.bUnderPressure = pcache1.nFreeSlotszPage+pCache->szExtra)<=pcache1.szSlot ){ - return pcache1.bUnderPressure; + return AtomicLoad(&pcache1.bUnderPressure); }else{ return sqlite3HeapNearlyFull(); } @@ -55932,12 +58383,12 @@ static int pcache1UnderMemoryPressure(PCache1 *pCache){ */ static void pcache1ResizeHash(PCache1 *p){ PgHdr1 **apNew; - unsigned int nNew; - unsigned int i; + u64 nNew; + u32 i; assert( sqlite3_mutex_held(p->pGroup->mutex) ); - nNew = p->nHash*2; + nNew = 2*(u64)p->nHash; if( nNew<256 ){ nNew = 256; } @@ -56160,7 +58611,7 @@ static void pcache1Destroy(sqlite3_pcache *p); static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ PCache1 *pCache; /* The newly created page cache */ PGroup *pGroup; /* The group the new page cache will belong to */ - int sz; /* Bytes of memory required to allocate the new cache */ + i64 sz; /* Bytes of memory required to allocate the new cache */ assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 ); assert( szExtra < 300 ); @@ -58048,6 +60499,9 @@ struct Pager { Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ char *zWal; /* File name for write-ahead log */ #endif +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + sqlite3 *dbWal; +#endif }; /* @@ -58137,40 +60591,36 @@ static const unsigned char aJournalMagic[] = { # define USEFETCH(x) 0 #endif -/* -** The argument to this macro is a file descriptor (type sqlite3_file*). -** Return 0 if it is not open, or non-zero (but not 1) if it is. -** -** This is so that expressions can be written as: -** -** if( isOpen(pPager->jfd) ){ ... -** -** instead of -** -** if( pPager->jfd->pMethods ){ ... -*/ -#define isOpen(pFd) ((pFd)->pMethods!=0) - #ifdef SQLITE_DIRECT_OVERFLOW_READ /* ** Return true if page pgno can be read directly from the database file ** by the b-tree layer. This is the case if: ** -** * the database file is open, -** * there are no dirty pages in the cache, and -** * the desired page is not currently in the wal file. +** (1) the database file is open +** (2) the VFS for the database is able to do unaligned sub-page reads +** (3) there are no dirty pages in the cache, and +** (4) the desired page is not currently in the wal file. */ SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ - if( pPager->fd->pMethods==0 ) return 0; - if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; + assert( pPager!=0 ); + assert( pPager->fd!=0 ); + if( pPager->fd->pMethods==0 ) return 0; /* Case (1) */ + if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; /* Failed (3) */ if( sqlite3mcPagerHasCodec(pPager) != 0 ) return 0; #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); - return iRead==0; + if( iRead ) return 0; /* Case (4) */ } +#else + UNUSED_PARAMETER(pgno); #endif + assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 ); + if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd) + & SQLITE_IOCAP_SUBPAGE_READ)==0 ){ + return 0; /* Case (2) */ + } return 1; } #endif @@ -58585,17 +61035,17 @@ static int jrnlBufferSize(Pager *pPager){ */ #ifdef SQLITE_CHECK_PAGES /* -** Return a 32-bit hash of the page data for pPage. +** Return a 64-bit hash of the page data for pPage. */ -static u32 pager_datahash(int nByte, unsigned char *pData){ - u32 hash = 0; +static u64 pager_datahash(int nByte, unsigned char *pData){ + u64 hash = 0; int i; for(i=0; ipPager->pageSize, (unsigned char *)pPage->pData); } static void pager_set_pagehash(PgHdr *pPage){ @@ -58622,39 +61072,43 @@ static void checkPage(PgHdr *pPg){ #endif /* SQLITE_CHECK_PAGES */ /* -** When this is called the journal file for pager pPager must be open. -** This function attempts to read a super-journal file name from the -** end of the file and, if successful, copies it into memory supplied -** by the caller. See comments above writeSuperJournal() for the format -** used to store a super-journal file name at the end of a journal file. -** -** zSuper must point to a buffer of at least nSuper bytes allocated by -** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is -** enough space to write the super-journal name). If the super-journal -** name in the journal is longer than nSuper bytes (including a -** nul-terminator), then this is handled as if no super-journal name -** were present in the journal. +** Free a buffer allocated by the readSuperJournal() function. +*/ +static void freeSuperJournal(char *zSuper){ + if( zSuper ){ + sqlite3_free(&zSuper[-4]); + } +} + +/* +** Parameter pJrnl is a file-handle open on a journal file. This function +** attempts to read a super-journal file name from the end of the journal +** file. If successful, it sets output parameter (*pzSuper) to point to a +** buffer containing the super-journal name as a nul-terminated string. +** The caller is responsible for freeing the buffer using freeSuperJournal(). ** -** If a super-journal file name is present at the end of the journal -** file, then it is copied into the buffer pointed to by zSuper. A -** nul-terminator byte is appended to the buffer following the -** super-journal file name. +** Refer to comments above writeSuperJournal() for the format used to store +** a super-journal file name at the end of a journal file. ** -** If it is determined that no super-journal file name is present -** zSuper[0] is set to 0 and SQLITE_OK returned. +** Parameter nSuper is passed the maximum allowable size of the super journal +** name in bytes. If the super-journal name in the journal is longer than +** nSuper bytes (including a nul-terminator), then this is handled as if no +** super-journal name were present in the journal. ** -** If an error occurs while reading from the journal file, an SQLite -** error code is returned. +** If there is no super-journal name at the end of pJrnl, (*pzSuper) is +** set to 0 and SQLITE_OK is returned. Or, if an error occurs while reading +** the super-journal name, an SQLite error code is returned and (*pzSuper) +** is set to 0. */ -static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){ +static int readSuperJournal(sqlite3_file *pJrnl, u64 nSuper, char **pzSuper){ int rc; /* Return code */ u32 len; /* Length in bytes of super-journal name */ i64 szJ; /* Total size in bytes of journal file pJrnl */ u32 cksum; /* MJ checksum value read from journal */ - u32 u; /* Unsigned loop counter */ unsigned char aMagic[8]; /* A buffer to hold the magic header */ - zSuper[0] = '\0'; + char *zOut = 0; + *pzSuper = 0; if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ)) || szJ<16 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len)) @@ -58664,27 +61118,34 @@ static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){ || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum)) || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8)) || memcmp(aMagic, aJournalMagic, 8) - || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zSuper, len, szJ-16-len)) ){ return rc; } - /* See if the checksum matches the super-journal name */ - for(u=0; ujfd) ); + if( pPager->eState==PAGER_ERROR ){ + /* If an IO error occurs in wal.c while attempting to wrap the wal file, + ** then the Wal object may be holding a write-lock but no read-lock. + ** This call ensures that the write-lock is dropped as well. We cannot + ** have sqlite3WalEndReadTransaction() drop the write-lock, as it once + ** did, because this would break "BEGIN EXCLUSIVE" handling for + ** SQLITE_ENABLE_SETLK_TIMEOUT builds. */ + (void)sqlite3WalEndWriteTransaction(pPager->pWal); + } sqlite3WalEndReadTransaction(pPager->pWal); pPager->eState = PAGER_OPEN; }else if( !pPager->exclusiveMode ){ @@ -59429,7 +61899,7 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ } pPager->journalOff = 0; }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST - || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL) + || (pPager->exclusiveMode && pPager->journalModetempFile); pPager->journalOff = 0; @@ -59829,6 +62299,40 @@ static int pager_playback_one_page( return rc; } +/* +** Check if zSuper is a valid super-journal name. There are two valid +** formats: +** +** + The 3rd and 4th last bytes of the filename are ".9", and the +** following 2 bytes are hex digits. This is a file created in 8.3 +** filenames mode. +** +** + The 3rd last byte of the filename is "9" and the filename +** contains the string "-mj" starting at the 12th last byte. +** All bytes following the "-mj" are hex digits. +** +** If the filename matches either of these patterns, return non-zero. +** Otherwise, return zero. +*/ +static int pagerIsSuperJrnlName(const char *zSuper){ + const int nSuper = sqlite3Strlen30(zSuper); + int ii; + + if( nSuper<4 ) return 0; + if( zSuper[nSuper-3]!='9' ) return 0; +#ifdef SQLITE_ENABLE_8_3_NAMES + if( sqlite3Isxdigit(zSuper[nSuper-2])==0 ) return 0; + if( sqlite3Isxdigit(zSuper[nSuper-1])==0 ) return 0; + if( zSuper[nSuper-4]=='.' ) return 1; +#endif + if( nSuper<12 ) return 0; + if( memcmp(&zSuper[nSuper-12], "-mj", 3) ) return 0; + for(ii=nSuper-9; iizJournal */ + + /* Check if this looks like a real super-journal name. If it does not, + ** return SQLITE_OK without attempting to delete it. This is to limit + ** the degree to which a crafted journal file can be used to cause + ** SQLite to delete arbitrary files. */ + if( pagerIsSuperJrnlName(zSuper)==0 ){ + return SQLITE_OK; + } /* Allocate space for both the pJournal and pSuper file descriptors. ** If successful, open the super-journal file for reading. */ - pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2); + pSuper = (sqlite3_file *)sqlite3MallocZero(2 * (i64)pVfs->szOsFile); if( !pSuper ){ rc = SQLITE_NOMEM_BKPT; pJournal = 0; @@ -59905,15 +62416,16 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ */ rc = sqlite3OsFileSize(pSuper, &nSuperJournal); if( rc!=SQLITE_OK ) goto delsuper_out; - nSuperPtr = pVfs->mxPathname+1; - zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2); + assert( nSuperJournal>=0 ); + zFree = sqlite3Malloc(4 + nSuperJournal + 2); if( !zFree ){ rc = SQLITE_NOMEM_BKPT; goto delsuper_out; + }else{ + assert( nSuperJournal<=0x7fffffff ); } zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0; zSuperJournal = &zFree[4]; - zSuperPtr = &zSuperJournal[nSuperJournal+2]; rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0); if( rc!=SQLITE_OK ) goto delsuper_out; zSuperJournal[nSuperJournal] = 0; @@ -59921,43 +62433,56 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ zJournal = zSuperJournal; while( (zJournal-zSuperJournal)zJournal)==0 ){ + bSeen = 1; + }else{ + int exists; + rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists); if( rc!=SQLITE_OK ){ goto delsuper_out; } + if( exists ){ + char *zSuperPtr = 0; - rc = readSuperJournal(pJournal, zSuperPtr, nSuperPtr); - sqlite3OsClose(pJournal); - if( rc!=SQLITE_OK ){ - goto delsuper_out; - } + /* One of the journals pointed to by the super-journal exists. + ** Open it and check if it points at the super-journal. If + ** so, return without deleting the super-journal file. + ** NB: zJournal is really a MAIN_JOURNAL. But call it a + ** SUPER_JOURNAL here so that the VFS will not send the zJournal + ** name into sqlite3_database_file_object(). + */ + int c; + int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL); + rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0); + if( rc!=SQLITE_OK ){ + goto delsuper_out; + } - c = zSuperPtr[0]!=0 && strcmp(zSuperPtr, zSuper)==0; - if( c ){ - /* We have a match. Do not delete the super-journal file. */ - goto delsuper_out; + rc = readSuperJournal(pJournal, 1+(u64)pVfs->mxPathname, &zSuperPtr); + sqlite3OsClose(pJournal); + if( rc!=SQLITE_OK ){ + assert( zSuperPtr==0 ); + goto delsuper_out; + } + + c = zSuperPtr!=0 && strcmp(zSuperPtr, zSuper)==0; + freeSuperJournal(zSuperPtr); + if( c ){ + /* We have a match. Do not delete the super-journal file. */ + goto delsuper_out; + } } } zJournal += (sqlite3Strlen30(zJournal)+1); } sqlite3OsClose(pSuper); - rc = sqlite3OsDelete(pVfs, zSuper, 0); + if( bSeen ){ + /* Only delete the super-journal if bSeen is true - indicating that + ** the super-journal contained a pointer to this database's journal + ** file. */ + rc = sqlite3OsDelete(pVfs, zSuper, 0); + } delsuper_out: sqlite3_free(zFree); @@ -60162,19 +62687,11 @@ static int pager_playback(Pager *pPager, int isHot){ ** If a super-journal file name is specified, but the file is not ** present on disk, then the journal is not hot and does not need to be ** played back. - ** - ** TODO: Technically the following is an error because it assumes that - ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that - ** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c, - ** mxPathname is 512, which is the same as the minimum allowable value - ** for pageSize. */ - zSuper = pPager->pTmpSpace; - rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); - if( rc==SQLITE_OK && zSuper[0] ){ + rc = readSuperJournal(pPager->jfd, 1+(i64)pPager->pVfs->mxPathname, &zSuper); + if( rc==SQLITE_OK && zSuper ){ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res); } - zSuper = 0; if( rc!=SQLITE_OK || !res ){ goto end_playback; } @@ -60303,30 +62820,20 @@ static int pager_playback(Pager *pPager, int isHot){ */ pPager->changeCountDone = pPager->tempFile; - if( rc==SQLITE_OK ){ - /* Leave 4 bytes of space before the super-journal filename in memory. - ** This is because it may end up being passed to sqlite3OsOpen(), in - ** which case it requires 4 0x00 bytes in memory immediately before - ** the filename. */ - zSuper = &pPager->pTmpSpace[4]; - rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); - testcase( rc!=SQLITE_OK ); - } if( rc==SQLITE_OK && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) ){ rc = sqlite3PagerSync(pPager, 0); } if( rc==SQLITE_OK ){ - rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0); + rc = pager_end_transaction(pPager, zSuper!=0, 0); testcase( rc!=SQLITE_OK ); } - if( rc==SQLITE_OK && zSuper[0] && res ){ + if( rc==SQLITE_OK && zSuper && res ){ /* If there was a super-journal and this routine will return success, ** see if it is possible to delete the super-journal. */ - assert( zSuper==&pPager->pTmpSpace[4] ); - memset(pPager->pTmpSpace, 0, 4); + assert( memcmp(&zSuper[-4], "\0\0\0\0", 4)==0 ); rc = pager_delsuper(pPager, zSuper); testcase( rc!=SQLITE_OK ); } @@ -60339,6 +62846,7 @@ static int pager_playback(Pager *pPager, int isHot){ ** back a journal created by a process with a different sector size ** value. Reset it to the correct value for this process. */ + freeSuperJournal(zSuper); setSectorSize(pPager); return rc; } @@ -60952,14 +63460,27 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags( unsigned pgFlags /* Various flags */ ){ unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK; - if( pPager->tempFile ){ + if( pPager->tempFile || level==PAGER_SYNCHRONOUS_OFF ){ pPager->noSync = 1; pPager->fullSync = 0; pPager->extraSync = 0; }else{ - pPager->noSync = level==PAGER_SYNCHRONOUS_OFF ?1:0; + pPager->noSync = 0; pPager->fullSync = level>=PAGER_SYNCHRONOUS_FULL ?1:0; - pPager->extraSync = level==PAGER_SYNCHRONOUS_EXTRA ?1:0; + + /* Set Pager.extraSync if "PRAGMA synchronous=EXTRA" is requested, or + ** if the file-system supports F2FS style atomic writes. If this flag + ** is set, SQLite syncs the directory to disk immediately after deleting + ** a journal file in "PRAGMA journal_mode=DELETE" mode. */ + if( level==PAGER_SYNCHRONOUS_EXTRA +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + || (sqlite3OsDeviceCharacteristics(pPager->fd) & SQLITE_IOCAP_BATCH_ATOMIC) +#endif + ){ + pPager->extraSync = 1; + }else{ + pPager->extraSync = 0; + } } if( pPager->noSync ){ pPager->syncFlags = 0; @@ -61519,6 +64040,8 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a); pPager->pWal = 0; } +#else + UNUSED_PARAMETER(db); #endif pager_reset(pPager); if( MEMDB ){ @@ -62080,6 +64603,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( const char *zUri = 0; /* URI args to copy */ int nUriByte = 1; /* Number of bytes of URI args at *zUri */ + /* Figure out how much space is required for each journal file-handle ** (there are two of them, the main journal and the sub-journal). */ journalFileSize = ROUND8(sqlite3JournalSize(pVfs)); @@ -62105,8 +64629,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen( */ if( zFilename && zFilename[0] ){ const char *z; - nPathname = pVfs->mxPathname+1; - zPathname = sqlite3DbMallocRaw(0, nPathname*2); + nPathname = pVfs->mxPathname + 1; + zPathname = sqlite3DbMallocRaw(0, 2*(i64)nPathname); if( zPathname==0 ){ return SQLITE_NOMEM_BKPT; } @@ -62193,14 +64717,14 @@ SQLITE_PRIVATE int sqlite3PagerOpen( ROUND8(sizeof(*pPager)) + /* Pager structure */ ROUND8(pcacheSize) + /* PCache object */ ROUND8(pVfs->szOsFile) + /* The main db file */ - journalFileSize * 2 + /* The two journal files */ + (u64)journalFileSize * 2 + /* The two journal files */ SQLITE_PTRSIZE + /* Space to hold a pointer */ 4 + /* Database prefix */ - nPathname + 1 + /* database filename */ - nUriByte + /* query parameters */ - nPathname + 8 + 1 + /* Journal filename */ + (u64)nPathname + 1 + /* database filename */ + (u64)nUriByte + /* query parameters */ + (u64)nPathname + 8 + 1 + /* Journal filename */ #ifndef SQLITE_OMIT_WAL - nPathname + 4 + 1 + /* WAL filename */ + (u64)nPathname + 4 + 1 + /* WAL filename */ #endif 3 /* Terminator */ ); @@ -64851,7 +67375,7 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint( } if( pPager->pWal ){ rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode, - (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), + (eMode<=SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), pPager->pBusyHandlerArg, pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, pnLog, pnCkpt @@ -64923,6 +67447,11 @@ static int pagerOpenWal(Pager *pPager){ pPager->fd, pPager->zWal, pPager->exclusiveMode, pPager->journalSizeLimit, &pPager->pWal ); +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( rc==SQLITE_OK ){ + sqlite3WalDb(pPager->pWal, pPager->dbWal); + } +#endif } pagerFixMaplimit(pPager); @@ -65042,6 +67571,7 @@ SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){ ** blocking locks are required. */ SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){ + pPager->dbWal = db; if( pagerUseWal(pPager) ){ sqlite3WalDb(pPager->pWal, db); } @@ -65655,6 +68185,11 @@ struct WalCkptInfo { /* ** An open write-ahead log file is represented by an instance of the ** following object. +** +** writeLock: +** This is usually set to 1 whenever the WRITER lock is held. However, +** if it is set to 2, then the WRITER lock is held but must be released +** by walHandleException() if a SEH exception is thrown. */ struct Wal { sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */ @@ -65745,9 +68280,13 @@ struct WalIterator { u32 *aPgno; /* Array of page numbers. */ int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */ int iZero; /* Frame number associated with aPgno[0] */ - } aSegment[1]; /* One for every 32KB page in the wal-index */ + } aSegment[FLEXARRAY]; /* One for every 32KB page in the wal-index */ }; +/* Size (in bytes) of a WalIterator object suitable for N or fewer segments */ +#define SZ_WALITERATOR(N) \ + (offsetof(WalIterator,aSegment)+(N)*sizeof(struct WalSegment)) + /* ** Define the parameters of the hash tables in the wal-index file. There ** is a hash-table following every HASHTABLE_NPAGE page numbers in the @@ -65906,7 +68445,7 @@ static SQLITE_NOINLINE int walIndexPageRealloc( /* Enlarge the pWal->apWiData[] array if required */ if( pWal->nWiData<=iPage ){ - sqlite3_int64 nByte = sizeof(u32*)*(iPage+1); + sqlite3_int64 nByte = sizeof(u32*)*(1+(i64)iPage); volatile u32 **apNew; apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte); if( !apNew ){ @@ -66015,10 +68554,8 @@ static void walChecksumBytes( s1 = s2 = 0; } - assert( nByte>=8 ); - assert( (nByte&0x00000007)==0 ); - assert( nByte<=65536 ); - assert( nByte%4==0 ); + /* nByte is a multiple of 8 between 8 and 65536 */ + assert( nByte>=8 && (nByte&7)==0 && nByte<=65536 ); if( !nativeCksum ){ do { @@ -66169,6 +68706,12 @@ static int walDecodeFrame( return 0; } + /* Need a valid page size + */ + if( !pWal->szPage ){ + return 0; + } + /* A frame is only valid if a checksum of the WAL header, ** all prior frames, the first 16 bytes of this frame-header, ** and the frame-data matches the checksum in the last 8 @@ -66272,7 +68815,7 @@ static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){ /* ** Compute a hash on a page number. The resulting hash value must land -** between 0 and (HASHTABLE_NSLOT-1). The walHashNext() function advances +** between 0 and (HASHTABLE_NSLOT-1). The walNextHash() function advances ** the hash to the next value in the event of a collision. */ static int walHash(u32 iPage){ @@ -66480,7 +69023,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; } - sLoc.aPgno[idx-1] = iPage; + sLoc.aPgno[(idx-1)&(HASHTABLE_NPAGE-1)] = iPage; AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT @@ -67108,8 +69651,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ /* Allocate space for the WalIterator object. */ nSegment = walFramePage(iLast) + 1; - nByte = sizeof(WalIterator) - + (nSegment-1)*sizeof(struct WalSegment) + nByte = SZ_WALITERATOR(nSegment) + iLast*sizeof(ht_slot); p = (WalIterator *)sqlite3_malloc64(nByte + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) @@ -67180,7 +69722,7 @@ static int walEnableBlockingMs(Wal *pWal, int nMs){ static int walEnableBlocking(Wal *pWal){ int res = 0; if( pWal->db ){ - int tmout = pWal->db->busyTimeout; + int tmout = pWal->db->setlkTimeout; if( tmout ){ res = walEnableBlockingMs(pWal, tmout); } @@ -67401,68 +69943,82 @@ static int walCheckpoint( && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK ){ u32 nBackfill = pInfo->nBackfill; - pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT; - - /* Sync the WAL to disk */ - rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); - - /* If the database may grow as a result of this checkpoint, hint - ** about the eventual size of the db file to the VFS layer. - */ - if( rc==SQLITE_OK ){ - i64 nReq = ((i64)mxPage * szPage); - i64 nSize; /* Current size of database file */ - sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0); - rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); - if( rc==SQLITE_OK && nSizehdr.mxFrame*szPage)pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq); + WalIndexHdr *pLive = (WalIndexHdr*)walIndexHdr(pWal); + + /* Now that read-lock slot 0 is locked, check that the wal has not been + ** wrapped since the header was read for this checkpoint. If it was, then + ** there was no work to do anyway. In this case the + ** (pInfo->nBackfillhdr.mxFrame) test above only passed because + ** pInfo->nBackfill had already been set to 0 by the writer that wrapped + ** the wal file. It would also be dangerous to proceed, as there may be + ** fewer than pWal->hdr.mxFrame valid frames in the wal file. */ + int bChg = memcmp(pLive->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)); + if( 0==bChg ){ + pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT; + + /* Sync the WAL to disk */ + rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); + + /* If the database may grow as a result of this checkpoint, hint + ** about the eventual size of the db file to the VFS layer. + */ + if( rc==SQLITE_OK ){ + i64 nReq = ((i64)mxPage * szPage); + i64 nSize; /* Current size of database file */ + sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0); + rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); + if( rc==SQLITE_OK && nSizehdr.mxFrame*szPage)pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); + } } - } - - } - /* Iterate through the contents of the WAL, copying data to the db file */ - while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ - i64 iOffset; - assert( walFramePgno(pWal, iFrame)==iDbpage ); - SEH_INJECT_FAULT; - if( AtomicLoad(&db->u1.isInterrupted) ){ - rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; - break; - } - if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){ - continue; } - iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; - /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ - rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); - if( rc!=SQLITE_OK ) break; - iOffset = (iDbpage-1)*(i64)szPage; - testcase( IS_BIG_INT(iOffset) ); - rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); - if( rc!=SQLITE_OK ) break; - } - sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0); - /* If work was actually accomplished... */ - if( rc==SQLITE_OK ){ - if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ - i64 szDb = pWal->hdr.nPage*(i64)szPage; - testcase( IS_BIG_INT(szDb) ); - rc = sqlite3OsTruncate(pWal->pDbFd, szDb); - if( rc==SQLITE_OK ){ - rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags)); + /* Iterate through the contents of the WAL, copying data to the + ** db file */ + while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ + i64 iOffset; + assert( walFramePgno(pWal, iFrame)==iDbpage ); + SEH_INJECT_FAULT; + if( AtomicLoad(&db->u1.isInterrupted) ){ + rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; + break; } + if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){ + continue; + } + iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; + /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ + rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); + if( rc!=SQLITE_OK ) break; + iOffset = (iDbpage-1)*(i64)szPage; + testcase( IS_BIG_INT(iOffset) ); + rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); + if( rc!=SQLITE_OK ) break; } + sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0); + + /* If work was actually accomplished... */ if( rc==SQLITE_OK ){ - AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT; + if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ + i64 szDb = pWal->hdr.nPage*(i64)szPage; + testcase( IS_BIG_INT(szDb) ); + rc = sqlite3OsTruncate(pWal->pDbFd, szDb); + if( rc==SQLITE_OK ){ + rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags)); + } + } + if( rc==SQLITE_OK ){ + AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT; + } } } @@ -67566,7 +70122,9 @@ static int walHandleException(Wal *pWal){ static const int S = 1; static const int E = (1<lockMask & ~( + u32 mUnlock; + if( pWal->writeLock==2 ) pWal->writeLock = 0; + mUnlock = pWal->lockMask & ~( (pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock))) | (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0) | (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0) @@ -67838,7 +70396,12 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ if( bWriteLock || SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){ - pWal->writeLock = 1; + /* If the write-lock was just obtained, set writeLock to 2 instead of + ** the usual 1. This causes walIndexPage() to behave as if the + ** write-lock were held (so that it allocates new pages as required), + ** and walHandleException() to unlock the write-lock if a SEH exception + ** is thrown. */ + if( !bWriteLock ) pWal->writeLock = 2; if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ badHdr = walIndexTryHdr(pWal, pChanged); if( badHdr ){ @@ -68003,7 +70566,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ /* Allocate a buffer to read frames into */ assert( (pWal->szPage & (pWal->szPage-1))==0 ); - assert( pWal->szPage>=512 && pWal->szPage<=65536 ); + assert( (pWal->szPage>=512 && pWal->szPage<=65536) || pWal->szPage==0 ); szFrame = pWal->szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame); if( aFrame==0 ){ @@ -68139,11 +70702,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ */ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */ - u32 mxReadMark; /* Largest aReadMark[] value */ - int mxI; /* Index of largest aReadMark[] value */ - int i; /* Loop counter */ int rc = SQLITE_OK; /* Return code */ - u32 mxFrame; /* Wal frame to lock to */ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT int nBlockTmout = 0; #endif @@ -68206,7 +70765,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ rc = walIndexReadHdr(pWal, pChanged); } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT - walDisableBlocking(pWal); if( rc==SQLITE_BUSY_TIMEOUT ){ rc = SQLITE_BUSY; *pCnt |= WAL_RETRY_BLOCKED_MASK; @@ -68221,6 +70779,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ ** WAL_RETRY this routine will be called again and will probably be ** right on the second iteration. */ + (void)walEnableBlocking(pWal); if( pWal->apWiData[0]==0 ){ /* This branch is taken when the xShmMap() method returns SQLITE_BUSY. ** We assume this is a transient condition, so return WAL_RETRY. The @@ -68237,6 +70796,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ rc = SQLITE_BUSY_RECOVERY; } } + walDisableBlocking(pWal); if( rc!=SQLITE_OK ){ return rc; } @@ -68249,141 +70809,147 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ assert( pWal->apWiData[0]!=0 ); pInfo = walCkptInfo(pWal); SEH_INJECT_FAULT; - if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame + { + u32 mxReadMark; /* Largest aReadMark[] value */ + int mxI; /* Index of largest aReadMark[] value */ + int i; /* Loop counter */ + u32 mxFrame; /* Wal frame to lock to */ + if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame #ifdef SQLITE_ENABLE_SNAPSHOT - && ((pWal->bGetSnapshot==0 && pWal->pSnapshot==0) || pWal->hdr.mxFrame==0) + && ((pWal->bGetSnapshot==0 && pWal->pSnapshot==0) || pWal->hdr.mxFrame==0) #endif - ){ - /* The WAL has been completely backfilled (or it is empty). - ** and can be safely ignored. - */ - rc = walLockShared(pWal, WAL_READ_LOCK(0)); - walShmBarrier(pWal); - if( rc==SQLITE_OK ){ - if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ - /* It is not safe to allow the reader to continue here if frames - ** may have been appended to the log before READ_LOCK(0) was obtained. - ** When holding READ_LOCK(0), the reader ignores the entire log file, - ** which implies that the database file contains a trustworthy - ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from - ** happening, this is usually correct. - ** - ** However, if frames have been appended to the log (or if the log - ** is wrapped and written for that matter) before the READ_LOCK(0) - ** is obtained, that is not necessarily true. A checkpointer may - ** have started to backfill the appended frames but crashed before - ** it finished. Leaving a corrupt image in the database file. - */ - walUnlockShared(pWal, WAL_READ_LOCK(0)); - return WAL_RETRY; + ){ + /* The WAL has been completely backfilled (or it is empty). + ** and can be safely ignored. + */ + rc = walLockShared(pWal, WAL_READ_LOCK(0)); + walShmBarrier(pWal); + if( rc==SQLITE_OK ){ + if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr,sizeof(WalIndexHdr)) ){ + /* It is not safe to allow the reader to continue here if frames + ** may have been appended to the log before READ_LOCK(0) was obtained. + ** When holding READ_LOCK(0), the reader ignores the entire log file, + ** which implies that the database file contains a trustworthy + ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from + ** happening, this is usually correct. + ** + ** However, if frames have been appended to the log (or if the log + ** is wrapped and written for that matter) before the READ_LOCK(0) + ** is obtained, that is not necessarily true. A checkpointer may + ** have started to backfill the appended frames but crashed before + ** it finished. Leaving a corrupt image in the database file. + */ + walUnlockShared(pWal, WAL_READ_LOCK(0)); + return WAL_RETRY; + } + pWal->readLock = 0; + return SQLITE_OK; + }else if( rc!=SQLITE_BUSY ){ + return rc; } - pWal->readLock = 0; - return SQLITE_OK; - }else if( rc!=SQLITE_BUSY ){ - return rc; } - } - /* If we get this far, it means that the reader will want to use - ** the WAL to get at content from recent commits. The job now is - ** to select one of the aReadMark[] entries that is closest to - ** but not exceeding pWal->hdr.mxFrame and lock that entry. - */ - mxReadMark = 0; - mxI = 0; - mxFrame = pWal->hdr.mxFrame; + /* If we get this far, it means that the reader will want to use + ** the WAL to get at content from recent commits. The job now is + ** to select one of the aReadMark[] entries that is closest to + ** but not exceeding pWal->hdr.mxFrame and lock that entry. + */ + mxReadMark = 0; + mxI = 0; + mxFrame = pWal->hdr.mxFrame; #ifdef SQLITE_ENABLE_SNAPSHOT - if( pWal->pSnapshot && pWal->pSnapshot->mxFramepSnapshot->mxFrame; - } -#endif - for(i=1; iaReadMark+i); SEH_INJECT_FAULT; - if( mxReadMark<=thisMark && thisMark<=mxFrame ){ - assert( thisMark!=READMARK_NOT_USED ); - mxReadMark = thisMark; - mxI = i; + if( pWal->pSnapshot && pWal->pSnapshot->mxFramepSnapshot->mxFrame; } - } - if( (pWal->readOnly & WAL_SHM_RDONLY)==0 - && (mxReadMarkaReadMark+i,mxFrame); - mxReadMark = mxFrame; + u32 thisMark = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT; + if( mxReadMark<=thisMark && thisMark<=mxFrame ){ + assert( thisMark!=READMARK_NOT_USED ); + mxReadMark = thisMark; mxI = i; - walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); - break; - }else if( rc!=SQLITE_BUSY ){ - return rc; } } - } - if( mxI==0 ){ - assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 ); - return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT; - } + if( (pWal->readOnly & WAL_SHM_RDONLY)==0 + && (mxReadMarkaReadMark+i,mxFrame); + mxReadMark = mxFrame; + mxI = i; + walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); + break; + }else if( rc!=SQLITE_BUSY ){ + return rc; + } + } + } + if( mxI==0 ){ + assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 ); + return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT; + } - (void)walEnableBlockingMs(pWal, nBlockTmout); - rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); - walDisableBlocking(pWal); - if( rc ){ + (void)walEnableBlockingMs(pWal, nBlockTmout); + rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); + walDisableBlocking(pWal); + if( rc ){ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT - if( rc==SQLITE_BUSY_TIMEOUT ){ - *pCnt |= WAL_RETRY_BLOCKED_MASK; - } + if( rc==SQLITE_BUSY_TIMEOUT ){ + *pCnt |= WAL_RETRY_BLOCKED_MASK; + } #else - assert( rc!=SQLITE_BUSY_TIMEOUT ); + assert( rc!=SQLITE_BUSY_TIMEOUT ); #endif - assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT ); - return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc; - } - /* Now that the read-lock has been obtained, check that neither the - ** value in the aReadMark[] array or the contents of the wal-index - ** header have changed. - ** - ** It is necessary to check that the wal-index header did not change - ** between the time it was read and when the shared-lock was obtained - ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility - ** that the log file may have been wrapped by a writer, or that frames - ** that occur later in the log than pWal->hdr.mxFrame may have been - ** copied into the database by a checkpointer. If either of these things - ** happened, then reading the database with the current value of - ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry - ** instead. - ** - ** Before checking that the live wal-index header has not changed - ** since it was read, set Wal.minFrame to the first frame in the wal - ** file that has not yet been checkpointed. This client will not need - ** to read any frames earlier than minFrame from the wal file - they - ** can be safely read directly from the database file. - ** - ** Because a ShmBarrier() call is made between taking the copy of - ** nBackfill and checking that the wal-header in shared-memory still - ** matches the one cached in pWal->hdr, it is guaranteed that the - ** checkpointer that set nBackfill was not working with a wal-index - ** header newer than that cached in pWal->hdr. If it were, that could - ** cause a problem. The checkpointer could omit to checkpoint - ** a version of page X that lies before pWal->minFrame (call that version - ** A) on the basis that there is a newer version (version B) of the same - ** page later in the wal file. But if version B happens to like past - ** frame pWal->hdr.mxFrame - then the client would incorrectly assume - ** that it can read version A from the database file. However, since - ** we can guarantee that the checkpointer that set nBackfill could not - ** see any pages past pWal->hdr.mxFrame, this problem does not come up. - */ - pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; SEH_INJECT_FAULT; - walShmBarrier(pWal); - if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark - || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) - ){ - walUnlockShared(pWal, WAL_READ_LOCK(mxI)); - return WAL_RETRY; - }else{ - assert( mxReadMark<=pWal->hdr.mxFrame ); - pWal->readLock = (i16)mxI; + assert((rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT); + return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc; + } + /* Now that the read-lock has been obtained, check that neither the + ** value in the aReadMark[] array or the contents of the wal-index + ** header have changed. + ** + ** It is necessary to check that the wal-index header did not change + ** between the time it was read and when the shared-lock was obtained + ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility + ** that the log file may have been wrapped by a writer, or that frames + ** that occur later in the log than pWal->hdr.mxFrame may have been + ** copied into the database by a checkpointer. If either of these things + ** happened, then reading the database with the current value of + ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry + ** instead. + ** + ** Before checking that the live wal-index header has not changed + ** since it was read, set Wal.minFrame to the first frame in the wal + ** file that has not yet been checkpointed. This client will not need + ** to read any frames earlier than minFrame from the wal file - they + ** can be safely read directly from the database file. + ** + ** Because a ShmBarrier() call is made between taking the copy of + ** nBackfill and checking that the wal-header in shared-memory still + ** matches the one cached in pWal->hdr, it is guaranteed that the + ** checkpointer that set nBackfill was not working with a wal-index + ** header newer than that cached in pWal->hdr. If it were, that could + ** cause a problem. The checkpointer could omit to checkpoint + ** a version of page X that lies before pWal->minFrame (call that version + ** A) on the basis that there is a newer version (version B) of the same + ** page later in the wal file. But if version B happens to like past + ** frame pWal->hdr.mxFrame - then the client would incorrectly assume + ** that it can read version A from the database file. However, since + ** we can guarantee that the checkpointer that set nBackfill could not + ** see any pages past pWal->hdr.mxFrame, this problem does not come up. + */ + pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; SEH_INJECT_FAULT; + walShmBarrier(pWal); + if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark + || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) + ){ + walUnlockShared(pWal, WAL_READ_LOCK(mxI)); + return WAL_RETRY; + }else{ + assert( mxReadMark<=pWal->hdr.mxFrame ); + pWal->readLock = (i16)mxI; + } } return rc; } @@ -68621,8 +71187,11 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ ** read-lock. */ SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){ - sqlite3WalEndWriteTransaction(pWal); +#ifndef SQLITE_ENABLE_SETLK_TIMEOUT + assert( pWal->writeLock==0 || pWal->readLock<0 ); +#endif if( pWal->readLock>=0 ){ + (void)sqlite3WalEndWriteTransaction(pWal); walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock)); pWal->readLock = -1; } @@ -68702,7 +71271,10 @@ static int walFindFrame( SEH_INJECT_FAULT; while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){ u32 iFrame = iH + sLoc.iZero; - if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){ + if( iFrame<=iLast + && iFrame>=pWal->minFrame + && sLoc.aPgno[(iH-1)&(HASHTABLE_NPAGE-1)]==pgno + ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } @@ -68815,7 +71387,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){ ** read-transaction was even opened, making this call a no-op. ** Return early. */ if( pWal->writeLock ){ - assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) ); + assert( !memcmp(&pWal->hdr,(void*)pWal->apWiData[0],sizeof(WalIndexHdr)) ); return SQLITE_OK; } #endif @@ -68915,6 +71487,7 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal); } SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; ) + pWal->iReCksum = 0; } return rc; } @@ -68962,6 +71535,9 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){ walCleanupHash(pWal); } SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; ) + if( pWal->iReCksum>pWal->hdr.mxFrame ){ + pWal->iReCksum = 0; + } } return rc; @@ -69427,7 +72003,8 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked ** in the SQLITE_CHECKPOINT_PASSIVE mode. */ - assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); + assert( SQLITE_CHECKPOINT_NOOPSQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); if( pWal->readOnly ) return SQLITE_READONLY; WALTRACE(("WAL%p: checkpoint begins\n", pWal)); @@ -69444,31 +72021,35 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured, ** it will not be invoked in this case. */ - rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); - testcase( rc==SQLITE_BUSY ); - testcase( rc!=SQLITE_OK && xBusy2!=0 ); - if( rc==SQLITE_OK ){ - pWal->ckptLock = 1; + if( eMode!=SQLITE_CHECKPOINT_NOOP ){ + rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); + testcase( rc==SQLITE_BUSY ); + testcase( rc!=SQLITE_OK && xBusy2!=0 ); + if( rc==SQLITE_OK ){ + pWal->ckptLock = 1; - /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and - ** TRUNCATE modes also obtain the exclusive "writer" lock on the database - ** file. - ** - ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained - ** immediately, and a busy-handler is configured, it is invoked and the - ** writer lock retried until either the busy-handler returns 0 or the - ** lock is successfully obtained. - */ - if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ - rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1); - if( rc==SQLITE_OK ){ - pWal->writeLock = 1; - }else if( rc==SQLITE_BUSY ){ - eMode2 = SQLITE_CHECKPOINT_PASSIVE; - xBusy2 = 0; - rc = SQLITE_OK; + /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART + ** and TRUNCATE modes also obtain the exclusive "writer" lock on the + ** database file. + ** + ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained + ** immediately, and a busy-handler is configured, it is invoked and the + ** writer lock retried until either the busy-handler returns 0 or the + ** lock is successfully obtained. + */ + if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ + rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1); + if( rc==SQLITE_OK ){ + pWal->writeLock = 1; + }else if( rc==SQLITE_BUSY ){ + eMode2 = SQLITE_CHECKPOINT_PASSIVE; + xBusy2 = 0; + rc = SQLITE_OK; + } } } + }else{ + rc = SQLITE_OK; } @@ -69482,7 +72063,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( ** immediately and do a partial checkpoint if it cannot obtain it. */ walDisableBlocking(pWal); rc = walIndexReadHdr(pWal, &isChanged); - if( eMode2!=SQLITE_CHECKPOINT_PASSIVE ) (void)walEnableBlocking(pWal); + if( eMode2>SQLITE_CHECKPOINT_PASSIVE ) (void)walEnableBlocking(pWal); if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){ sqlite3OsUnfetch(pWal->pDbFd, 0, 0); } @@ -69490,9 +72071,10 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( /* Copy data from the log to the database file. */ if( rc==SQLITE_OK ){ + sqlite3FaultSim(660); if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ rc = SQLITE_CORRUPT_BKPT; - }else{ + }else if( eMode2!=SQLITE_CHECKPOINT_NOOP ){ rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags,zBuf); } @@ -69520,7 +72102,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( sqlite3WalDb(pWal, 0); /* Release the locks. */ - sqlite3WalEndWriteTransaction(pWal); + (void)sqlite3WalEndWriteTransaction(pWal); if( pWal->ckptLock ){ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); pWal->ckptLock = 0; @@ -70264,6 +72846,12 @@ struct CellInfo { */ #define BTCURSOR_MAX_DEPTH 20 +/* +** Maximum amount of storage local to a database page, regardless of +** page size. +*/ +#define BT_MAX_LOCAL 65501 /* 65536 - 35 */ + /* ** A cursor is a pointer to a particular entry within a particular ** b-tree within a database file. @@ -70476,6 +73064,9 @@ struct IntegrityCk { u32 *heap; /* Min-heap used for analyzing cell coverage */ sqlite3 *db; /* Database connection running the check */ i64 nRow; /* Number of rows visited in current tree */ +#ifdef SQLITE_DEBUG + u32 mxHeap; /* Maximum number of entries in the Min-heap */ +#endif }; /* @@ -70672,7 +73263,7 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){ */ static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){ int i; - int skipOk = 1; + u8 skipOk = 1; Btree *p; assert( sqlite3_mutex_held(db->mutex) ); for(i=0; inDb; i++){ @@ -71528,7 +74119,7 @@ static int saveCursorKey(BtCursor *pCur){ ** below. */ void *pKey; pCur->nKey = sqlite3BtreePayloadSize(pCur); - pKey = sqlite3Malloc( pCur->nKey + 9 + 8 ); + pKey = sqlite3Malloc( ((i64)pCur->nKey) + 9 + 8 ); if( pKey ){ rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ @@ -71671,7 +74262,7 @@ static int btreeMoveto( assert( nKey==(i64)(int)nKey ); pIdxKey = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; - sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); + sqlite3VdbeRecordUnpack((int)nKey, pKey, pIdxKey); if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ rc = SQLITE_CORRUPT_BKPT; }else{ @@ -71818,7 +74409,7 @@ SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){ */ SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){ assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 ); - pCur->hints = x; + pCur->hints = (u8)x; } @@ -72012,14 +74603,15 @@ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow( static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){ int maxLocal; /* Maximum amount of payload held locally */ maxLocal = pPage->maxLocal; + assert( nPayload>=0 ); if( nPayload<=maxLocal ){ - return nPayload; + return (int)nPayload; }else{ int minLocal; /* Minimum amount of payload held locally */ int surplus; /* Overflow payload available for local storage */ minLocal = pPage->minLocal; - surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize-4); - return ( surplus <= maxLocal ) ? surplus : minLocal; + surplus = (int)(minLocal +(nPayload - minLocal)%(pPage->pBt->usableSize-4)); + return (surplus <= maxLocal) ? surplus : minLocal; } } @@ -72060,7 +74652,7 @@ static void btreeParseCellPtr( CellInfo *pInfo /* Fill in this structure */ ){ u8 *pIter; /* For scanning through pCell */ - u32 nPayload; /* Number of bytes of cell payload */ + u64 nPayload; /* Number of bytes of cell payload */ u64 iKey; /* Extracted Key value */ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); @@ -72082,6 +74674,7 @@ static void btreeParseCellPtr( do{ nPayload = (nPayload<<7) | (*++pIter & 0x7f); }while( (*pIter)>=0x80 && pIternKey = *(i64*)&iKey; - pInfo->nPayload = nPayload; + pInfo->nPayload = (u32)nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==(u32)pPage->maxLocal+1 ); + assert( pPage->maxLocal <= BT_MAX_LOCAL ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ - pInfo->nSize = nPayload + (u16)(pIter - pCell); + pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell); if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; }else{ @@ -72166,11 +74760,13 @@ static void btreeParseCellPtrIndex( pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==(u32)pPage->maxLocal+1 ); + assert( nPayload>=0 ); + assert( pPage->maxLocal <= BT_MAX_LOCAL ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ - pInfo->nSize = nPayload + (u16)(pIter - pCell); + pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell); if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; }else{ @@ -72709,24 +75305,24 @@ static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ ** at the end of the page. So do additional corruption checks inside this ** routine and return SQLITE_CORRUPT if any problems are found. */ -static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ - u16 iPtr; /* Address of ptr to next freeblock */ - u16 iFreeBlk; /* Address of the next freeblock */ +static int freeSpace(MemPage *pPage, int iStart, int iSize){ + int iPtr; /* Address of ptr to next freeblock */ + int iFreeBlk; /* Address of the next freeblock */ u8 hdr; /* Page header size. 0 or 100 */ - u8 nFrag = 0; /* Reduction in fragmentation */ - u16 iOrigSize = iSize; /* Original value of iSize */ - u16 x; /* Offset to cell content area */ - u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ + int nFrag = 0; /* Reduction in fragmentation */ + int iOrigSize = iSize; /* Original value of iSize */ + int x; /* Offset to cell content area */ + int iEnd = iStart + iSize; /* First byte past the iStart buffer */ unsigned char *data = pPage->aData; /* Page content */ u8 *pTmp; /* Temporary ptr into data[] */ assert( pPage->pBt!=0 ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( CORRUPT_DB || iStart>=pPage->hdrOffset+6+pPage->childPtrSize ); - assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize ); + assert( CORRUPT_DB || iEnd <= (int)pPage->pBt->usableSize ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( iSize>=4 ); /* Minimum cell size is 4 */ - assert( CORRUPT_DB || iStart<=pPage->pBt->usableSize-4 ); + assert( CORRUPT_DB || iStart<=(int)pPage->pBt->usableSize-4 ); /* The list of freeblocks must be in ascending order. Find the ** spot on the list where iStart should be inserted. @@ -72743,7 +75339,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ } iPtr = iFreeBlk; } - if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ + if( iFreeBlk>(int)pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ return SQLITE_CORRUPT_PAGE(pPage); } assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB ); @@ -72758,7 +75354,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ nFrag = iFreeBlk - iEnd; if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage); iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); - if( iEnd > pPage->pBt->usableSize ){ + if( iEnd > (int)pPage->pBt->usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } iSize = iEnd - iStart; @@ -72779,7 +75375,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ } } if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); - data[hdr+7] -= nFrag; + data[hdr+7] -= (u8)nFrag; } pTmp = &data[hdr+5]; x = get2byte(pTmp); @@ -72800,7 +75396,8 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ /* Insert the new freeblock into the freelist */ put2byte(&data[iPtr], iStart); put2byte(&data[iStart], iFreeBlk); - put2byte(&data[iStart+2], iSize); + assert( iSize>=0 && iSize<=0xffff ); + put2byte(&data[iStart+2], (u16)iSize); } pPage->nFree += iOrigSize; return SQLITE_OK; @@ -72931,8 +75528,12 @@ static int btreeComputeFreeSpace(MemPage *pPage){ } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); + if( size<4 ){ + /* Minimum freeblock size is 4 */ + return SQLITE_CORRUPT_PAGE(pPage); + } nFree = nFree + size; - if( next<=pc+size+3 ) break; + if( next0 ){ @@ -73026,7 +75627,7 @@ static int btreeInitPage(MemPage *pPage){ assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); pPage->nOverflow = 0; - pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize; + pPage->cellOffset = (u16)(pPage->hdrOffset + 8 + pPage->childPtrSize); pPage->aCellIdx = data + pPage->childPtrSize + 8; pPage->aDataEnd = pPage->aData + pBt->pageSize; pPage->aDataOfst = pPage->aData + pPage->childPtrSize; @@ -73060,8 +75661,8 @@ static int btreeInitPage(MemPage *pPage){ static void zeroPage(MemPage *pPage, int flags){ unsigned char *data = pPage->aData; BtShared *pBt = pPage->pBt; - u8 hdr = pPage->hdrOffset; - u16 first; + int hdr = pPage->hdrOffset; + int first; assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno || CORRUPT_DB ); assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); @@ -73078,7 +75679,7 @@ static void zeroPage(MemPage *pPage, int flags){ put2byte(&data[hdr+5], pBt->usableSize); pPage->nFree = (u16)(pBt->usableSize - first); decodeFlags(pPage, flags); - pPage->cellOffset = first; + pPage->cellOffset = (u16)first; pPage->aDataEnd = &data[pBt->pageSize]; pPage->aCellIdx = &data[first]; pPage->aDataOfst = &data[pPage->childPtrSize]; @@ -73649,6 +76250,7 @@ static int removeFromSharingList(BtShared *pBt){ sqlite3_mutex_leave(pMainMtx); return removed; #else + UNUSED_PARAMETER( pBt ); return 1; #endif } @@ -73864,8 +76466,12 @@ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, BtShared *pBt = p->pBt; assert( nReserve>=0 && nReserve<=255 ); sqlite3BtreeEnter(p); - pBt->nReserveWanted = nReserve; + pBt->nReserveWanted = (u8)nReserve; x = pBt->pageSize - pBt->usableSize; + if( x==nReserve && (pageSize==0 || (u32)pageSize==pBt->pageSize) ){ + sqlite3BtreeLeave(p); + return SQLITE_OK; + } if( nReservebtsFlags & BTS_PAGESIZE_FIXED ){ sqlite3BtreeLeave(p); @@ -73970,7 +76576,7 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) ); if( newFlag>=0 ){ p->pBt->btsFlags &= ~BTS_FAST_SECURE; - p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag; + p->pBt->btsFlags |= (u16)(BTS_SECURE_DELETE*newFlag); } b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE; sqlite3BtreeLeave(p); @@ -74461,6 +77067,30 @@ static SQLITE_NOINLINE int btreeBeginTrans( } #endif +#ifdef SQLITE_EXPERIMENTAL_PRAGMA_20251114 + /* If both a read and write transaction will be opened by this call, + ** then issue a file-control as if the following pragma command had + ** been evaluated: + ** + ** PRAGMA experimental_pragma_20251114 = 1|2 + ** + ** where the RHS is "1" if wrflag is 1 (RESERVED lock), or "2" if wrflag + ** is 2 (EXCLUSIVE lock). Ignore any result or error returned by the VFS. + ** + ** WARNING: This code will likely remain part of SQLite only temporarily - + ** it exists to allow users to experiment with certain types of blocking + ** locks in custom VFS implementations. It MAY BE REMOVED AT ANY TIME. */ + if( pBt->pPage1==0 && wrflag ){ + sqlite3_file *fd = sqlite3PagerFile(pPager); + char *aFcntl[3] = {0,0,0}; + aFcntl[1] = "experimental_pragma_20251114"; + assert( wrflag==1 || wrflag==2 ); + aFcntl[2] = (wrflag==1 ? "1" : "2"); + sqlite3OsFileControlHint(fd, SQLITE_FCNTL_PRAGMA, (void*)aFcntl); + sqlite3_free(aFcntl[0]); + } +#endif + /* Call lockBtree() until either pBt->pPage1 is populated or ** lockBtree() returns something other than SQLITE_OK. lockBtree() ** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after @@ -74490,6 +77120,13 @@ static SQLITE_NOINLINE int btreeBeginTrans( (void)sqlite3PagerWalWriteLock(pPager, 0); unlockBtreeIfUnused(pBt); } +#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) + if( rc==SQLITE_BUSY_TIMEOUT ){ + /* If a blocking lock timed out, break out of the loop here so that + ** the busy-handler is not invoked. */ + break; + } +#endif }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && btreeInvokeBusyHandler(pBt) ); sqlite3PagerWalDb(pPager, 0); @@ -75901,7 +78538,7 @@ static int accessPayload( getCellInfo(pCur); aPayload = pCur->info.pPayload; - assert( offset+amt <= pCur->info.nPayload ); + assert( (u64)offset+(u64)amt <= (u64)pCur->info.nPayload ); assert( aPayload > pPage->aData ); if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){ @@ -75942,7 +78579,9 @@ static int accessPayload( ** means "not yet known" (the cache is lazily populated). */ if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){ - int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; + i64 nOvfl = pCur->info.nPayload; + testcase( nOvfl - pCur->info.nLocal + ovflSize - 1 > 0xffffffffU ); + nOvfl = (nOvfl - pCur->info.nLocal + ovflSize-1)/ovflSize; if( pCur->aOverflow==0 || nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow) ){ @@ -76047,6 +78686,12 @@ static int accessPayload( (eOp==0 ? PAGER_GET_READONLY : 0) ); if( rc==SQLITE_OK ){ + if( eOp!=0 + && (sqlite3PagerPageRefcount(pDbPage)!=1 + || NEVER(((MemPage*)sqlite3PagerGetExtra(pDbPage))->isInit)) ){ + sqlite3PagerUnref(pDbPage); + return SQLITE_CORRUPT_PAGE(pPage); + } aPayload = sqlite3PagerGetData(pDbPage); nextPage = get4byte(aPayload); rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage); @@ -76448,6 +79093,30 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ return rc; } +/* Set *pRes to 1 (true) if the BTree pointed to by cursor pCur contains zero +** rows of content. Set *pRes to 0 (false) if the table contains content. +** Return SQLITE_OK on success or some error code (ex: SQLITE_NOMEM) if +** something goes wrong. +*/ +SQLITE_PRIVATE int sqlite3BtreeIsEmpty(BtCursor *pCur, int *pRes){ + int rc; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + if( NEVER(pCur->eState==CURSOR_VALID) ){ + *pRes = 0; + return SQLITE_OK; + } + rc = moveToRoot(pCur); + if( rc==SQLITE_EMPTY ){ + *pRes = 1; + rc = SQLITE_OK; + }else{ + *pRes = 0; + } + return rc; +} + #ifdef SQLITE_DEBUG /* The cursors is CURSOR_VALID and has BTCF_AtLast set. Verify that ** this flags are true for a consistent database. @@ -76667,8 +79336,8 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( } /* -** Compare the "idx"-th cell on the page the cursor pCur is currently -** pointing to to pIdxKey using xRecordCompare. Return negative or +** Compare the "idx"-th cell on the page pPage against the key +** pointing to by pIdxKey using xRecordCompare. Return negative or ** zero if the cell is less than or equal pIdxKey. Return positive ** if unknown. ** @@ -76683,12 +79352,11 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( ** a positive value as that will cause the optimization to be skipped. */ static int indexCellCompare( - BtCursor *pCur, + MemPage *pPage, int idx, UnpackedRecord *pIdxKey, RecordCompare xRecordCompare ){ - MemPage *pPage = pCur->pPage; int c; int nCell; /* Size of the pCell cell in bytes */ u8 *pCell = findCellPastPtr(pPage, idx); @@ -76698,14 +79366,14 @@ static int indexCellCompare( /* This branch runs if the record-size field of the cell is a ** single byte varint and the record fits entirely on the main ** b-tree page. */ - testcase( pCell+nCell+1==pPage->aDataEnd ); + if( pCell + nCell >= pPage->aDataEnd ) return 99; c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ - testcase( pCell+nCell+2==pPage->aDataEnd ); + if( pCell + nCell >= pPage->aDataEnd ) return 99; c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* If the record extends into overflow pages, do not attempt @@ -76797,14 +79465,14 @@ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( ){ int c; if( pCur->ix==pCur->pPage->nCell-1 - && (c = indexCellCompare(pCur, pCur->ix, pIdxKey, xRecordCompare))<=0 + && (c = indexCellCompare(pCur->pPage,pCur->ix,pIdxKey,xRecordCompare))<=0 && pIdxKey->errCode==SQLITE_OK ){ *pRes = c; return SQLITE_OK; /* Cursor already pointing at the correct spot */ } if( pCur->iPage>0 - && indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0 + && indexCellCompare(pCur->pPage, 0, pIdxKey, xRecordCompare)<=0 && pIdxKey->errCode==SQLITE_OK ){ pCur->curFlags &= ~(BTCF_ValidOvfl|BTCF_AtLast); @@ -76867,14 +79535,17 @@ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( /* This branch runs if the record-size field of the cell is a ** single byte varint and the record fits entirely on the main ** b-tree page. */ - testcase( pCell+nCell+1==pPage->aDataEnd ); + if( pCell + nCell >= pPage->aDataEnd ){ + rc = SQLITE_CORRUPT_PAGE(pPage); + goto moveto_index_finish; + } c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal + && pCell + nCell < pPage->aDataEnd ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ - testcase( pCell+nCell+2==pPage->aDataEnd ); c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* The record flows over onto one or more overflow pages. In @@ -76899,7 +79570,7 @@ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( rc = SQLITE_CORRUPT_PAGE(pPage); goto moveto_index_finish; } - pCellKey = sqlite3Malloc( nCell+nOverrun ); + pCellKey = sqlite3Malloc( (u64)nCell+(u64)nOverrun ); if( pCellKey==0 ){ rc = SQLITE_NOMEM_BKPT; goto moveto_index_finish; @@ -77021,7 +79692,7 @@ SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){ n = pCur->pPage->nCell; for(i=0; iiPage; i++){ - n *= pCur->apPage[i]->nCell; + n *= pCur->apPage[i]->nCell+1; } return n; } @@ -78418,7 +81089,8 @@ static int rebuildPage( } /* The pPg->nFree field is now set incorrectly. The caller will fix it. */ - pPg->nCell = nCell; + assert( nCell < 10922 ); + pPg->nCell = (u16)nCell; pPg->nOverflow = 0; put2byte(&aData[hdr+1], 0); @@ -78665,9 +81337,13 @@ static int editPage( if( pageInsertArray( pPg, pBegin, &pData, pCellptr, iNew+nCell, nNew-nCell, pCArray - ) ) goto editpage_fail; + ) + ){ + goto editpage_fail; + } - pPg->nCell = nNew; + assert( nNew < 10922 ); + pPg->nCell = (u16)nNew; pPg->nOverflow = 0; put2byte(&aData[hdr+3], pPg->nCell); @@ -78976,7 +81652,7 @@ static int balance_nonroot( int pageFlags; /* Value of pPage->aData[0] */ int iSpace1 = 0; /* First unused byte of aSpace1[] */ int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */ - int szScratch; /* Size of scratch memory requested */ + u64 szScratch; /* Size of scratch memory requested */ MemPage *apOld[NB]; /* pPage and up to two siblings */ MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */ u8 *pRight; /* Location in parent of right-sibling pointer */ @@ -79473,7 +82149,12 @@ static int balance_nonroot( ** of the right-most new sibling page is set to the value that was ** originally in the same field of the right-most old sibling page. */ if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){ - MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1]; + MemPage *pOld; + if( nNew>nOld ){ + pOld = apNew[nOld-1]; + }else{ + pOld = apOld[nOld-1]; + } memcpy(&apNew[nNew-1]->aData[8], &pOld->aData[8], 4); } @@ -80261,7 +82942,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( if( pCur->info.nKey==pX->nKey ){ BtreePayload x2; x2.pData = pX->pKey; - x2.nData = pX->nKey; + x2.nData = (int)pX->nKey; assert( pX->nKey<=0x7fffffff ); x2.nZero = 0; return btreeOverwriteCell(pCur, &x2); } @@ -80442,7 +83123,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 getCellInfo(pSrc); if( pSrc->info.nPayload<0x80 ){ - *(aOut++) = pSrc->info.nPayload; + *(aOut++) = (u8)pSrc->info.nPayload; }else{ aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload); } @@ -80455,7 +83136,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 nRem = pSrc->info.nPayload; if( nIn==nRem && nInpPage->maxLocal ){ memcpy(aOut, aIn, nIn); - pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace); + pBt->nPreformatSize = nIn + (int)(aOut - pBt->pTmpSpace); return SQLITE_OK; }else{ int rc = SQLITE_OK; @@ -80467,7 +83148,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 u32 nOut; /* Size of output buffer aOut[] */ nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload); - pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace); + pBt->nPreformatSize = (int)nOut + (int)(aOut - pBt->pTmpSpace); if( nOutinfo.nPayload ){ pPgnoOut = &aOut[nOut]; pBt->nPreformatSize += 4; @@ -80506,7 +83187,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 }while( rc==SQLITE_OK && nOut>0 ); if( rc==SQLITE_OK && nRem>0 && ALWAYS(pPgnoOut) ){ - Pgno pgnoNew; + Pgno pgnoNew = 0; /* Prevent harmless static-analyzer warning */ MemPage *pNew = 0; rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); put4byte(pPgnoOut, pgnoNew); @@ -81729,6 +84410,7 @@ static int checkTreePage( } }else{ /* Populate the coverage-checking heap for leaf pages */ + assert( heap[0] < pCheck->mxHeap ); btreeHeapInsert(heap, (pc<<16)|(pc+info.nSize-1)); } } @@ -81748,6 +84430,7 @@ static int checkTreePage( u32 size; pc = get2byteAligned(&data[cellStart+i*2]); size = pPage->xCellSize(pPage, &data[pc]); + assert( heap[0] < pCheck->mxHeap ); btreeHeapInsert(heap, (pc<<16)|(pc+size-1)); } } @@ -81764,6 +84447,7 @@ static int checkTreePage( assert( (u32)i<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ size = get2byte(&data[i+2]); assert( (u32)(i+size)<=usableSize ); /* due to btreeComputeFreeSpace() */ + assert( heap[0] < pCheck->mxHeap ); btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1)); /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a ** big-endian integer which is the offset in the b-tree page of the next @@ -81898,6 +84582,9 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( goto integrity_ck_cleanup; } sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); +#ifdef SQLITE_DEBUG + sCheck.mxHeap = pBt->pageSize/4 - 1; +#endif if( sCheck.heap==0 ){ checkOom(&sCheck); goto integrity_ck_cleanup; @@ -82088,6 +84775,7 @@ SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){ */ SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ BtShared *pBt = p->pBt; + assert( nBytes==0 || nBytes==sizeof(Schema) ); sqlite3BtreeEnter(p); if( !pBt->pSchema && nBytes ){ pBt->pSchema = sqlite3DbMallocZero(0, nBytes); @@ -82104,6 +84792,7 @@ SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void */ SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *p){ int rc; + UNUSED_PARAMETER(p); /* only used in DEBUG builds */ assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK); @@ -82313,6 +85002,7 @@ SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){ */ struct sqlite3_backup { sqlite3* pDestDb; /* Destination database handle */ + char *zDestDb; Btree *pDest; /* Destination b-tree file */ u32 iDestSchema; /* Original schema cookie in destination */ int bDestLocked; /* True once a write-transaction is open on pDest */ @@ -82402,10 +85092,8 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ ** Attempt to set the page size of the destination to match the page size ** of the source. */ -static int setDestPgsz(sqlite3_backup *p){ - int rc; - rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0); - return rc; +static int setDestPgsz(Btree *pDest, Btree *pSrc){ + return sqlite3BtreeSetPageSize(pDest, sqlite3BtreeGetPageSize(pSrc), 0, 0); } /* @@ -82468,27 +85156,37 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init( ); p = 0; }else { + int nDest = sqlite3Strlen30(zDestDb); + /* Allocate space for a new sqlite3_backup object... ** EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a ** call to sqlite3_backup_init() and is destroyed by a call to ** sqlite3_backup_finish(). */ - p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup)); + p = (sqlite3_backup*)sqlite3MallocZero(sizeof(sqlite3_backup)+nDest+1); if( !p ){ sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT); + }else{ + p->zDestDb = (char*)&p[1]; + memcpy(p->zDestDb, zDestDb, nDest); } } /* If the allocation succeeded, populate the new object. */ if( p ){ + /* Do not store the pointer to the destination b-tree at this point. + ** This is because there is nothing preventing it from being detached + ** or otherwise freed before the first call to sqlite3_backup_step() + ** on this object. The source b-tree does not have this problem, as + ** incrementing Btree.nBackup (see below) effectively locks the object. */ + Btree *pDest = findBtree(pDestDb, pDestDb, zDestDb); p->pSrc = findBtree(pDestDb, pSrcDb, zSrcDb); - p->pDest = findBtree(pDestDb, pDestDb, zDestDb); p->pDestDb = pDestDb; p->pSrcDb = pSrcDb; p->iNext = 1; p->isAttached = 0; - if( 0==p->pSrc || 0==p->pDest - || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK + if( 0==p->pSrc || 0==pDest + || checkReadTransaction(pDestDb, pDest)!=SQLITE_OK ){ /* One (or both) of the named databases did not exist or an OOM ** error was hit. Or there is a transaction open on the destination @@ -82612,7 +85310,7 @@ static void attachBackupObject(sqlite3_backup *p){ */ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ int rc; - int destMode; /* Destination journal mode */ + int destMode = 0; /* Destination journal mode */ int pgszSrc = 0; /* Source page size */ int pgszDest = 0; /* Destination page size */ @@ -82628,7 +85326,8 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ rc = p->rc; if( !isFatalError(rc) ){ Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */ - Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */ + Btree * pDest = 0; /* Dest btree */ + Pager * pDestPager = 0; /* Dest pager */ int ii; /* Iterator variable */ int nSrcPage = -1; /* Size of source db in pages */ int bCloseTrans = 0; /* True if src db requires unlocking */ @@ -82642,6 +85341,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ rc = SQLITE_OK; } + /* If there is no open read-transaction on the source database, open ** one now. If a transaction is opened here, then it will be closed ** before this function exits. @@ -82651,34 +85351,48 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ bCloseTrans = 1; } + /* Locate the destination btree and pager. */ + if( (pDest = p->pDest)==0 ){ + pDest = findBtree(p->pDestDb, p->pDestDb, p->zDestDb); + } + if( pDest==0 ){ + rc = SQLITE_ERROR; + }else{ + pDestPager = sqlite3BtreePager(pDest); + } + /* If the destination database has not yet been locked (i.e. if this ** is the first call to backup_step() for the current backup operation), ** try to set its page size to the same as the source database. This ** is especially important on ZipVFS systems, as in that case it is ** not possible to create a database file that uses one page size by ** writing to it with another. */ - if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){ + if( p->bDestLocked==0 && rc==SQLITE_OK + && setDestPgsz(pDest, p->pSrc)==SQLITE_NOMEM + ){ rc = SQLITE_NOMEM; } /* Lock the destination database, if it is not locked already. */ if( SQLITE_OK==rc && p->bDestLocked==0 - && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2, + && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(pDest, 2, (int*)&p->iDestSchema)) ){ p->bDestLocked = 1; + p->pDest = pDest; } /* Do not allow backup if the destination database is in WAL mode ** and the page sizes are different between source and destination */ - pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); - pgszDest = sqlite3BtreeGetPageSize(p->pDest); - destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest)); - if( SQLITE_OK==rc - && (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager)) - && pgszSrc!=pgszDest - ){ - rc = SQLITE_READONLY; + if( rc==SQLITE_OK ){ + pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); + pgszDest = sqlite3BtreeGetPageSize(p->pDest); + destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest)); + if( (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager)) + && pgszSrc!=pgszDest + ){ + rc = SQLITE_READONLY; + } } /* Now that there is a read-lock on the source database, query the @@ -82896,7 +85610,9 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){ } /* If a transaction is still open on the Btree, roll it back. */ - sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); + if( p->pDest ){ + sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); + } /* Set the error code of the destination database handle. */ rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; @@ -83176,21 +85892,27 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ StrAccum acc; assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) ); assert( sz>22 ); - if( p->flags & MEM_Int ){ -#if GCC_VERSION>=7000000 - /* Work-around for GCC bug - ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */ + if( p->flags & (MEM_Int|MEM_IntReal) ){ +#if GCC_VERSION>=7000000 && GCC_VERSION<15000000 && defined(__i386__) + /* Work-around for GCC bug or bugs: + ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 + ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114659 + ** The problem appears to be fixed in GCC 15 */ i64 x; - assert( (p->flags&MEM_Int)*2==sizeof(x) ); - memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2); + assert( (MEM_Str&~p->flags)*4==sizeof(x) ); + memcpy(&x, (char*)&p->u, (MEM_Str&~p->flags)*4); p->n = sqlite3Int64ToText(x, zBuf); #else p->n = sqlite3Int64ToText(p->u.i, zBuf); #endif + if( p->flags & MEM_IntReal ){ + memcpy(zBuf+p->n,".0", 3); + p->n += 2; + } }else{ sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0); - sqlite3_str_appendf(&acc, "%!.15g", - (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r); + sqlite3_str_appendf(&acc, "%!.*g", + (p->db ? p->db->nFpDigit : 17), p->u.r); assert( acc.zText==zBuf && acc.mxAlloc<=0 ); zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */ p->n = acc.nChar; @@ -83210,7 +85932,7 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ ** corresponding string value, then it is important that the string be ** derived from the numeric value, not the other way around, to ensure ** that the index and table are consistent. See ticket -** https://www.sqlite.org/src/info/343634942dd54ab (2018-01-31) for +** https://sqlite.org/src/info/343634942dd54ab (2018-01-31) for ** an example. ** ** This routine looks at pMem to verify that if it has both a numeric @@ -83239,6 +85961,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){ assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 ); } if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1; + if( p->db==0 ){ + return 1; /* db->nFpDigit required to validate p->z[] */ + } memcpy(&tmp, p, sizeof(tmp)); vdbeMemRenderNum(sizeof(zBuf), zBuf, &tmp); z = p->z; @@ -83389,32 +86114,36 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ ** ** This is an optimization. Correct operation continues even if ** this routine is a no-op. +** +** Return true if the strig is zero-terminated after this routine is +** called and false if it is not. */ -SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ +SQLITE_PRIVATE int sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ if( (pMem->flags & (MEM_Str|MEM_Term|MEM_Ephem|MEM_Static))!=MEM_Str ){ /* pMem must be a string, and it cannot be an ephemeral or static string */ - return; + return 0; } - if( pMem->enc!=SQLITE_UTF8 ) return; - if( NEVER(pMem->z==0) ) return; + if( pMem->enc!=SQLITE_UTF8 ) return 0; + assert( pMem->z!=0 ); if( pMem->flags & MEM_Dyn ){ if( pMem->xDel==sqlite3_free && sqlite3_msize(pMem->z) >= (u64)(pMem->n+1) ){ pMem->z[pMem->n] = 0; pMem->flags |= MEM_Term; - return; + return 1; } if( pMem->xDel==sqlite3RCStrUnref ){ /* Blindly assume that all RCStr objects are zero-terminated */ pMem->flags |= MEM_Term; - return; + return 1; } }else if( pMem->szMalloc >= pMem->n+1 ){ pMem->z[pMem->n] = 0; pMem->flags |= MEM_Term; - return; + return 1; } + return 0; } /* @@ -83712,18 +86441,117 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem *pMem){ } } +/* +** This routine implements the uncommon and slower path for +** sqlite3MemRealValueRC() that has to deal with input strings +** that are not UTF8 or that are not zero-terminated. It is +** broken out into a separate no-inline routine so that the +** main sqlite3MemRealValueRC() routine can avoid unnecessary +** stack pushes. +** +** A text->float translation of pMem->z is written into *pValue. +** +** Result code invariants: +** +** rc==0 => ERROR: Input string not well-formed, or OOM +** rc<0 => Some prefix of the input is well-formed +** rc>0 => All of the input is well-formed +** (rc&2)==0 => The number is expressed as an integer, with no +** decimal point or eNNN suffix. +*/ +static SQLITE_NOINLINE int sqlite3MemRealValueRCSlowPath( + Mem *pMem, + double *pValue +){ + int rc = SQLITE_OK; + *pValue = 0.0; + if( pMem->enc==SQLITE_UTF8 ){ + char *zCopy = sqlite3DbStrNDup(pMem->db, pMem->z, pMem->n); + if( zCopy ){ + rc = sqlite3AtoF(zCopy, pValue); + sqlite3DbFree(pMem->db, zCopy); + } + return rc; + }else{ + int n, i, j; + char *zCopy; + const char *z; + + n = pMem->n & ~1; + zCopy = sqlite3DbMallocRaw(pMem->db, n/2 + 2); + if( zCopy ){ + z = pMem->z; + if( pMem->enc==SQLITE_UTF16LE ){ + for(i=j=0; idb, zCopy); + } + return rc; + } +} + +/* +** Invoke sqlite3AtoF() on the text value of pMem. Write the +** translation of the text input into *pValue. +** +** The caller must ensure that pMem->db!=0 and that pMem is in +** mode MEM_Str or MEM_Blob. +** +** Result code invariants: +** +** rc==0 => ERROR: Input string not well-formed, or OOM +** rc<0 => Some prefix of the input is well-formed +** rc>0 => All of the input is well-formed +** (rc&2)==0 => The number is expressed as an integer, with no +** decimal point or eNNN suffix. +*/ +SQLITE_PRIVATE int sqlite3MemRealValueRC(Mem *pMem, double *pValue){ + testcase( pMem->db==0 ); + assert( pMem->flags & (MEM_Str|MEM_Blob) ); + if( pMem->z==0 ){ + *pValue = 0.0; + return 0; + }else if( pMem->enc==SQLITE_UTF8 + && ((pMem->flags & MEM_Term)!=0 || sqlite3VdbeMemZeroTerminateIfAble(pMem)) + ){ + return sqlite3AtoF(pMem->z, pValue); + }else if( pMem->n==0 ){ + *pValue = 0.0; + return 0; + }else{ + return sqlite3MemRealValueRCSlowPath(pMem, pValue); + } +} + +/* +** This routine acts as a bridge from sqlite3VdbeRealValue() to +** sqlite3VdbeRealValueRC, allowing sqlite3VdbeRealValue() to avoid +** stuffing values onto the stack. +*/ +static SQLITE_NOINLINE double sqlite3MemRealValueNoRC(Mem *pMem){ + double r; + (void)sqlite3MemRealValueRC(pMem, &r); + return r; +} + /* ** Return the best representation of pMem that we can get into a ** double. If pMem is already a double or an integer, return its ** value. If it is a string or blob, try to convert it to a double. ** If it is a NULL, return 0.0. */ -static SQLITE_NOINLINE double memRealValue(Mem *pMem){ - /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ - double val = (double)0; - sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); - return val; -} SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); @@ -83734,7 +86562,7 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ testcase( pMem->flags & MEM_IntReal ); return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ - return memRealValue(pMem); + return sqlite3MemRealValueNoRC(pMem); }else{ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ return (double)0; @@ -83858,8 +86686,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ sqlite3_int64 ix; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); - if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1) + rc = sqlite3MemRealValueRC(pMem, &pMem->u.r); + if( ((rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<2) || sqlite3RealSameAsInt(pMem->u.r, (ix = sqlite3RealToI64(pMem->u.r))) ){ pMem->u.i = ix; @@ -84115,27 +86943,30 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ int i; Mem *pX; - for(i=1, pX=pVdbe->aMem+1; inMem; i++, pX++){ - if( pX->pScopyFrom==pMem ){ - u16 mFlags; - if( pVdbe->db->flags & SQLITE_VdbeTrace ){ - sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n", - (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem)); - } - /* If pX is marked as a shallow copy of pMem, then try to verify that - ** no significant changes have been made to pX since the OP_SCopy. - ** A significant change would indicated a missed call to this - ** function for pX. Minor changes, such as adding or removing a - ** dual type, are allowed, as long as the underlying value is the - ** same. */ - mFlags = pMem->flags & pX->flags & pX->mScopyFlags; - assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i ); - - /* pMem is the register that is changing. But also mark pX as - ** undefined so that we can quickly detect the shallow-copy error */ - pX->flags = MEM_Undefined; - pX->pScopyFrom = 0; - } + if( pMem->bScopy ){ + for(i=1, pX=pVdbe->aMem+1; inMem; i++, pX++){ + if( pX->pScopyFrom==pMem ){ + u16 mFlags; + if( pVdbe->db->flags & SQLITE_VdbeTrace ){ + sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n", + (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem)); + } + /* If pX is marked as a shallow copy of pMem, then try to verify that + ** no significant changes have been made to pX since the OP_SCopy. + ** A significant change would indicated a missed call to this + ** function for pX. Minor changes, such as adding or removing a + ** dual type, are allowed, as long as the underlying value is the + ** same. */ + mFlags = pMem->flags & pX->flags & pX->mScopyFlags; + assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i ); + + /* pMem is the register that is changing. But also mark pX as + ** undefined so that we can quickly detect the shallow-copy error */ + pX->flags = MEM_Undefined; + pX->pScopyFrom = 0; + } + } + pMem->bScopy = 0; } pMem->pScopyFrom = 0; } @@ -84292,6 +87123,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){ return SQLITE_NOMEM_BKPT; } + assert( pMem->z!=0 ); memcpy(pMem->z, z, nAlloc); }else{ sqlite3VdbeMemRelease(pMem); @@ -84319,6 +87151,84 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( return SQLITE_OK; } +/* Like sqlite3VdbeMemSetStr() except: +** +** enc is always SQLITE_UTF8 +** pMem->db is always non-NULL +*/ +SQLITE_PRIVATE int sqlite3VdbeMemSetText( + Mem *pMem, /* Memory cell to set to string value */ + const char *z, /* String pointer */ + i64 n, /* Bytes in string, or negative */ + void (*xDel)(void*) /* Destructor function */ +){ + i64 nByte = n; /* New value for pMem->n */ + u16 flags; + + assert( pMem!=0 ); + assert( pMem->db!=0 ); + assert( sqlite3_mutex_held(pMem->db->mutex) ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); + + /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ + if( !z ){ + sqlite3VdbeMemSetNull(pMem); + return SQLITE_OK; + } + + if( nByte<0 ){ + nByte = strlen(z); + flags = MEM_Str|MEM_Term; + }else{ + flags = MEM_Str; + } + if( nByte>(i64)pMem->db->aLimit[SQLITE_LIMIT_LENGTH] ){ + if( xDel && xDel!=SQLITE_TRANSIENT ){ + if( xDel==SQLITE_DYNAMIC ){ + sqlite3DbFree(pMem->db, (void*)z); + }else{ + xDel((void*)z); + } + } + sqlite3VdbeMemSetNull(pMem); + return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); + } + + /* The following block sets the new values of Mem.z and Mem.xDel. It + ** also sets a flag in local variable "flags" to indicate the memory + ** management (one of MEM_Dyn or MEM_Static). + */ + if( xDel==SQLITE_TRANSIENT ){ + i64 nAlloc = nByte + 1; + testcase( nAlloc==31 ); + testcase( nAlloc==32 ); + if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){ + return SQLITE_NOMEM_BKPT; + } + assert( pMem->z!=0 ); + memcpy(pMem->z, z, nByte); + pMem->z[nByte] = 0; + }else{ + sqlite3VdbeMemRelease(pMem); + pMem->z = (char *)z; + if( xDel==SQLITE_DYNAMIC ){ + pMem->zMalloc = pMem->z; + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); + pMem->xDel = 0; + }else if( xDel==SQLITE_STATIC ){ + pMem->xDel = xDel; + flags |= MEM_Static; + }else{ + pMem->xDel = xDel; + flags |= MEM_Dyn; + } + } + pMem->flags = flags; + pMem->n = (int)(nByte & 0x7fffffff); + pMem->enc = SQLITE_UTF8; + return SQLITE_OK; +} + /* ** Move data out of a btree key or data field and into a Mem structure. ** The data is payload from the entry that pCur is currently pointing @@ -84342,7 +87252,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( ){ int rc; pMem->flags = MEM_Null; - if( sqlite3BtreeMaxRecordSize(pCur)=SQLITE_MAX_ALLOCATION_SIZE ){ + return SQLITE_NOMEM_BKPT; + } + if( (u64)amt + (u64)offset > (u64)sqlite3BtreeMaxRecordSize(pCur) ){ return SQLITE_CORRUPT_BKPT; } if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){ @@ -84506,7 +87421,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ if( pRec==0 ){ Index *pIdx = p->pIdx; /* Index being probed */ - int nByte; /* Bytes of space to allocate */ + i64 nByte; /* Bytes of space to allocate */ int i; /* Counter variable */ int nCol = pIdx->nColumn; /* Number of index columns including rowid */ @@ -84572,7 +87487,7 @@ static int valueFromFunction( ){ sqlite3_context ctx; /* Context object for function invocation */ sqlite3_value **apVal = 0; /* Function arguments */ - int nVal = 0; /* Size of apVal[] array */ + int nVal = 0; /* Number of function arguments */ FuncDef *pFunc = 0; /* Function definition */ sqlite3_value *pVal = 0; /* New value */ int rc = SQLITE_OK; /* Return code */ @@ -84742,7 +87657,7 @@ static int valueFromExpr( if( affinity==SQLITE_AFF_BLOB ){ if( op==TK_FLOAT ){ assert( pVal && pVal->z && pVal->flags==(MEM_Str|MEM_Term) ); - sqlite3AtoF(pVal->z, &pVal->u.r, pVal->n, SQLITE_UTF8); + sqlite3AtoF(pVal->z, &pVal->u.r); pVal->flags = MEM_Real; }else if( op==TK_INTEGER ){ /* This case is required by -9223372036854775808 and other strings @@ -85010,6 +87925,11 @@ SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr( ** ** If *ppVal is initially NULL then the caller is responsible for ** ensuring that the value written into *ppVal is eventually freed. +** +** If the buffer does not contain a well-formed record, this routine may +** read several bytes past the end of the buffer. Callers must therefore +** ensure that any buffer which may contain a corrupt record is padded +** with at least 8 bytes of addressable memory. */ SQLITE_PRIVATE int sqlite3Stat4Column( sqlite3 *db, /* Database handle */ @@ -85570,12 +88490,10 @@ SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall( int eCallCtx /* Calling context */ ){ Vdbe *v = pParse->pVdbe; - int nByte; int addr; sqlite3_context *pCtx; assert( v ); - nByte = sizeof(*pCtx) + (nArg-1)*sizeof(sqlite3_value*); - pCtx = sqlite3DbMallocRawNN(pParse->db, nByte); + pCtx = sqlite3DbMallocRawNN(pParse->db, SZ_CONTEXT(nArg)); if( pCtx==0 ){ assert( pParse->db->mallocFailed ); freeEphemeralFunction(pParse->db, (FuncDef*)pFunc); @@ -85851,7 +88769,7 @@ static Op *opIterNext(VdbeOpIter *p){ } if( pRet->p4type==P4_SUBPROGRAM ){ - int nByte = (p->nSub+1)*sizeof(SubProgram*); + i64 nByte = (1+(u64)p->nSub)*sizeof(SubProgram*); int j; for(j=0; jnSub; j++){ if( p->apSub[j]==pRet->p4.pProgram ) break; @@ -85981,8 +88899,8 @@ SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){ ** (1) For each jump instruction with a negative P2 value (a label) ** resolve the P2 value to an actual address. ** -** (2) Compute the maximum number of arguments used by any SQL function -** and store that value in *pMaxFuncArgs. +** (2) Compute the maximum number of arguments used by the xUpdate/xFilter +** methods of any virtual table and store that value in *pMaxVtabArgs. ** ** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately ** indicate what the prepared statement actually does. @@ -85995,8 +88913,8 @@ SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){ ** script numbers the opcodes correctly. Changes to this routine must be ** coordinated with changes to mkopcodeh.tcl. */ -static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ - int nMaxArgs = *pMaxFuncArgs; +static void resolveP2Values(Vdbe *p, int *pMaxVtabArgs){ + int nMaxVtabArgs = *pMaxVtabArgs; Op *pOp; Parse *pParse = p->pParse; int *aLabel = pParse->aLabel; @@ -86041,15 +88959,19 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ } #ifndef SQLITE_OMIT_VIRTUALTABLE case OP_VUpdate: { - if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; + if( pOp->p2>nMaxVtabArgs ) nMaxVtabArgs = pOp->p2; break; } case OP_VFilter: { int n; + /* The instruction immediately prior to VFilter will be an + ** OP_Integer that sets the "argc" value for the VFilter. See + ** the code where OP_VFilter is generated at tag-20250207a. */ assert( (pOp - p->aOp) >= 3 ); assert( pOp[-1].opcode==OP_Integer ); + assert( pOp[-1].p2==pOp->p3+1 ); n = pOp[-1].p1; - if( n>nMaxArgs ) nMaxArgs = n; + if( n>nMaxVtabArgs ) nMaxVtabArgs = n; /* Fall through into the default case */ /* no break */ deliberate_fall_through } @@ -86090,7 +89012,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ pParse->aLabel = 0; } pParse->nLabel = 0; - *pMaxFuncArgs = nMaxArgs; + *pMaxVtabArgs = nMaxVtabArgs; assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); } @@ -86319,7 +89241,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus( const char *zName /* Name of table or index being scanned */ ){ if( IS_STMT_SCANSTATUS(p->db) ){ - sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); + i64 nByte = (1+(i64)p->nScan) * sizeof(ScanStatus); ScanStatus *aNew; aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); if( aNew ){ @@ -86429,6 +89351,9 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){ */ SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){ VdbeOp *pOp = sqlite3VdbeGetLastOp(p); +#ifdef SQLITE_DEBUG + while( pOp->opcode==OP_ReleaseReg ) pOp--; +#endif if( pOp->p3==iDest && pOp->opcode==OP_Column ){ pOp->p5 |= OPFLAG_TYPEOFARG; } @@ -87123,6 +90048,10 @@ SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){ zP4 = pOp->p4.pTab->zName; break; } + case P4_INDEX: { + zP4 = pOp->p4.pIdx->zName; + break; + } case P4_SUBRTNSIG: { SubrtnSig *pSig = pOp->p4.pSubrtnSig; sqlite3_str_appendf(&x, "subrtnsig:%d,%s", pSig->selId, pSig->zAff); @@ -87269,6 +90198,7 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){ ** will be initialized before use. */ static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){ + assert( db!=0 ); if( N>0 ){ do{ p->flags = flags; @@ -87276,6 +90206,7 @@ static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){ p->szMalloc = 0; #ifdef SQLITE_DEBUG p->pScopyFrom = 0; + p->bScopy = 0; #endif p++; }while( (--N)>0 ); @@ -87294,6 +90225,7 @@ static void releaseMemArray(Mem *p, int N){ if( p && N ){ Mem *pEnd = &p[N]; sqlite3 *db = p->db; + assert( db!=0 ); if( db->pnBytesFreed ){ do{ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); @@ -87765,7 +90697,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( int nVar; /* Number of parameters */ int nMem; /* Number of VM memory registers */ int nCursor; /* Number of cursors required */ - int nArg; /* Number of arguments in subprograms */ + int nArg; /* Max number args to xFilter or xUpdate */ int n; /* Loop counter */ struct ReusableSpace x; /* Reusable bulk memory */ @@ -87774,6 +90706,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( assert( pParse!=0 ); assert( p->eVdbeState==VDBE_INIT_STATE ); assert( pParse==p->pParse ); + assert( pParse->db==p->db ); p->pVList = pParse->pVList; pParse->pVList = 0; db = p->db; @@ -87836,6 +90769,9 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*)); } } +#ifdef SQLITE_DEBUG + p->napArg = nArg; +#endif if( db->mallocFailed ){ p->nVar = 0; @@ -88014,7 +90950,7 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName( } assert( p->aColName!=0 ); pColName = &(p->aColName[idx+var*p->nResAlloc]); - rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, xDel); + rc = sqlite3VdbeMemSetText(pColName, zName, -1, xDel); assert( rc!=0 || !zName || (pColName->flags&MEM_Term)!=0 ); return rc; } @@ -88107,10 +91043,12 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt)) || nTrans<=1 ){ - for(i=0; rc==SQLITE_OK && inDb; i++){ - Btree *pBt = db->aDb[i].pBt; - if( pBt ){ - rc = sqlite3BtreeCommitPhaseOne(pBt, 0); + if( needXcommit ){ + for(i=0; rc==SQLITE_OK && inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( sqlite3BtreeTxnState(pBt)>=SQLITE_TXN_WRITE ){ + rc = sqlite3BtreeCommitPhaseOne(pBt, 0); + } } } @@ -88121,7 +91059,9 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ */ for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; - if( pBt ){ + int txn = sqlite3BtreeTxnState(pBt); + if( txn!=SQLITE_TXN_NONE ){ + assert( needXcommit || txn==SQLITE_TXN_READ ); rc = sqlite3BtreeCommitPhaseTwo(pBt, 0); } } @@ -88376,28 +91316,31 @@ SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ /* -** This function is called when a transaction opened by the database +** These functions are called when a transaction opened by the database ** handle associated with the VM passed as an argument is about to be -** committed. If there are outstanding deferred foreign key constraint -** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK. +** committed. If there are outstanding foreign key constraint violations +** return an error code. Otherwise, SQLITE_OK. ** ** If there are outstanding FK violations and this function returns -** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY -** and write an error message to it. Then return SQLITE_ERROR. +** non-zero, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY +** and write an error message to it. */ #ifndef SQLITE_OMIT_FOREIGN_KEY -SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){ +static SQLITE_NOINLINE int vdbeFkError(Vdbe *p){ + p->rc = SQLITE_CONSTRAINT_FOREIGNKEY; + p->errorAction = OE_Abort; + sqlite3VdbeError(p, "FOREIGN KEY constraint failed"); + if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ) return SQLITE_ERROR; + return SQLITE_CONSTRAINT_FOREIGNKEY; +} +SQLITE_PRIVATE int sqlite3VdbeCheckFkImmediate(Vdbe *p){ + if( p->nFkConstraint==0 ) return SQLITE_OK; + return vdbeFkError(p); +} +SQLITE_PRIVATE int sqlite3VdbeCheckFkDeferred(Vdbe *p){ sqlite3 *db = p->db; - if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0) - || (!deferred && p->nFkConstraint>0) - ){ - p->rc = SQLITE_CONSTRAINT_FOREIGNKEY; - p->errorAction = OE_Abort; - sqlite3VdbeError(p, "FOREIGN KEY constraint failed"); - if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ) return SQLITE_ERROR; - return SQLITE_CONSTRAINT_FOREIGNKEY; - } - return SQLITE_OK; + if( (db->nDeferredCons+db->nDeferredImmCons)==0 ) return SQLITE_OK; + return vdbeFkError(p); } #endif @@ -88491,7 +91434,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ /* Check for immediate foreign key violations. */ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ - (void)sqlite3VdbeCheckFk(p, 0); + (void)sqlite3VdbeCheckFkImmediate(p); } /* If the auto-commit flag is set and this is the only active writer @@ -88505,7 +91448,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ && db->nVdbeWrite==(p->readOnly==0) ){ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ - rc = sqlite3VdbeCheckFk(p, 1); + rc = sqlite3VdbeCheckFkDeferred(p); if( rc!=SQLITE_OK ){ if( NEVER(p->readOnly) ){ sqlite3VdbeLeave(p); @@ -89315,29 +92258,22 @@ SQLITE_PRIVATE void sqlite3VdbeSerialGet( return; } /* -** This routine is used to allocate sufficient space for an UnpackedRecord -** structure large enough to be used with sqlite3VdbeRecordUnpack() if -** the first argument is a pointer to KeyInfo structure pKeyInfo. -** -** The space is either allocated using sqlite3DbMallocRaw() or from within -** the unaligned buffer passed via the second and third arguments (presumably -** stack space). If the former, then *ppFree is set to a pointer that should -** be eventually freed by the caller using sqlite3DbFree(). Or, if the -** allocation comes from the pSpace/szSpace buffer, *ppFree is set to NULL -** before returning. +** Allocate sufficient space for an UnpackedRecord structure large enough +** to hold a decoded index record for pKeyInfo. ** -** If an OOM error occurs, NULL is returned. +** The space is allocated using sqlite3DbMallocRaw(). If an OOM error +** occurs, NULL is returned. */ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( KeyInfo *pKeyInfo /* Description of the record */ ){ UnpackedRecord *p; /* Unpacked record to return */ - int nByte; /* Number of bytes required for *p */ + u64 nByte; /* Number of bytes required for *p */ + assert( sizeof(UnpackedRecord) + sizeof(Mem)*65536 < 0x7fffffff ); nByte = ROUND8P(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1); p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); if( !p ) return 0; p->aMem = (Mem*)&((char*)p)[ROUND8P(sizeof(UnpackedRecord))]; - assert( pKeyInfo->aSortFlags!=0 ); p->pKeyInfo = pKeyInfo; p->nField = pKeyInfo->nKeyField + 1; return p; @@ -89349,7 +92285,6 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( ** contents of the decoded record. */ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( - KeyInfo *pKeyInfo, /* Information about the record format */ int nKey, /* Size of the binary record */ const void *pKey, /* The binary record */ UnpackedRecord *p /* Populate this structure before returning. */ @@ -89360,6 +92295,7 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( u16 u; /* Unsigned loop counter */ u32 szHdr; Mem *pMem = p->aMem; + KeyInfo *pKeyInfo = p->pKeyInfo; p->default_rc = 0; assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -89377,16 +92313,18 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( pMem->z = 0; sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); d += sqlite3VdbeSerialTypeLen(serial_type); - pMem++; if( (++u)>=p->nField ) break; + pMem++; } if( d>(u32)nKey && u ){ assert( CORRUPT_DB ); /* In a corrupt record entry, the last pMem might have been set up using ** uninitialized memory. Overwrite its value with NULL, to prevent ** warnings from MSAN. */ - sqlite3VdbeMemSetNull(pMem-1); + sqlite3VdbeMemSetNull(pMem-(unField)); } + testcase( u == pKeyInfo->nKeyField + 1 ); + testcase( u < pKeyInfo->nKeyField + 1 ); assert( u<=pKeyInfo->nKeyField + 1 ); p->nField = u; } @@ -89554,6 +92492,32 @@ static void vdbeAssertFieldCountWithinLimits( ** or positive value if *pMem1 is less than, equal to or greater than ** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);". */ +static SQLITE_NOINLINE int vdbeCompareMemStringWithEncodingChange( + const Mem *pMem1, + const Mem *pMem2, + const CollSeq *pColl, + u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */ +){ + int rc; + const void *v1, *v2; + Mem c1; + Mem c2; + sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null); + sqlite3VdbeMemInit(&c2, pMem1->db, MEM_Null); + sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); + sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); + v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); + v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); + if( (v1==0 || v2==0) ){ + if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT; + rc = 0; + }else{ + rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2); + } + sqlite3VdbeMemReleaseMalloc(&c1); + sqlite3VdbeMemReleaseMalloc(&c2); + return rc; +} static int vdbeCompareMemString( const Mem *pMem1, const Mem *pMem2, @@ -89565,25 +92529,7 @@ static int vdbeCompareMemString( ** comparison function directly */ return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z); }else{ - int rc; - const void *v1, *v2; - Mem c1; - Mem c2; - sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null); - sqlite3VdbeMemInit(&c2, pMem1->db, MEM_Null); - sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); - sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); - v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); - v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); - if( (v1==0 || v2==0) ){ - if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT; - rc = 0; - }else{ - rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2); - } - sqlite3VdbeMemReleaseMalloc(&c1); - sqlite3VdbeMemReleaseMalloc(&c2); - return rc; + return vdbeCompareMemStringWithEncodingChange(pMem1,pMem2,pColl,prcErr); } } @@ -90246,6 +93192,7 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ ** The easiest way to enforce this limit is to consider only records with ** 13 fields or less. If the first field is an integer, the maximum legal ** header size is (12*5 + 1 + 1) bytes. */ + assert( p->pKeyInfo->aSortFlags!=0 ); if( p->pKeyInfo->nAllField<=13 ){ int flags = p->aMem[0].flags; if( p->pKeyInfo->aSortFlags[0] ){ @@ -90495,6 +93442,224 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ } } +/* +** Helper function for vdbeIsMatchingIndexKey(). Return true if column +** iCol should be ignored when comparing a record with a record from +** an index on disk. The field should be ignored if: +** +** * the corresponding bit in mask is set, and +** * either: +** - bIntegrity is false, or +** - the two Mem values are both real values that differ by +** BTREE_ULPDISTORTION or fewer ULPs. +*/ +static int vdbeSkipField( + Bitmask mask, /* Mask of indexed expression fields */ + int iCol, /* Column of index being considered */ + Mem *pMem1, /* Expected index value */ + Mem *pMem2, /* Actual indexed value */ + int bIntegrity /* True if running PRAGMA integrity_check */ +){ +#define BTREE_ULPDISTORTION 2 + if( iCol>=BMS || (mask & MASKBIT(iCol))==0 ) return 0; + if( bIntegrity==0 ) return 1; + if( (pMem1->flags & MEM_Real) && (pMem2->flags & MEM_Real) ){ + u64 m1, m2; + memcpy(&m1,&pMem1->u.r,8); + memcpy(&m2,&pMem2->u.r,8); + if( (m1pKeyInfo->enc; + mem.db = p->pKeyInfo->db; + nRec = sqlite3BtreePayloadSize(pCur); + if( nRec>0x7fffffff ){ + return SQLITE_CORRUPT_BKPT; + } + + /* Allocate 5 extra bytes at the end of the buffer. This allows the + ** getVarint32() call below to read slightly past the end of the buffer + ** if the record is corrupt. */ + aRec = sqlite3MallocZero(nRec+5); + if( aRec==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + rc = sqlite3BtreePayload(pCur, 0, nRec, aRec); + } + + if( rc==SQLITE_OK ){ + u32 szHdr = 0; /* Size of record header in bytes */ + u32 idxHdr = 0; /* Current index in header */ + + idxHdr = getVarint32(aRec, szHdr); + if( szHdr>98307 ){ + rc = SQLITE_CORRUPT; + }else{ + int res = 0; /* Result of this function call */ + u32 idxRec = szHdr; /* Index of next field in record body */ + int ii = 0; /* Iterator variable */ + + int nCol = p->pKeyInfo->nAllField; + for(ii=0; ii=szHdr ){ + rc = SQLITE_CORRUPT_BKPT; + break; + } + idxHdr += getVarint32(&aRec[idxHdr], iSerial); + nSerial = sqlite3VdbeSerialTypeLen(iSerial); + if( (idxRec+nSerial)>nRec ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + sqlite3VdbeSerialGet(&aRec[idxRec], iSerial, &mem); + if( vdbeSkipField(mask, ii, &p->aMem[ii], &mem, bInt)==0 ){ + res = sqlite3MemCompare(&mem, &p->aMem[ii], p->pKeyInfo->aColl[ii]); + if( res!=0 ) break; + } + } + idxRec += sqlite3VdbeSerialTypeLen(iSerial); + } + + *piRes = res; + } + } + + sqlite3_free(aRec); + return rc; +} + +/* +** This is called when the record in (*p) should be found in the index +** opened by cursor pCur, but was not. This may happen as part of a DELETE +** operation or an integrity check. +** +** One reason that an exact match was not found may be the EIIB bug - that +** a text-to-float conversion may have caused a real value in record (*p) +** to be slightly different from its counterpart on disk. This function +** attempts to find the right index record. If it does find the right +** record, it leaves *pCur pointing to it and sets (*pRes) to 0 before +** returning. Otherwise, (*pRes) is set to non-zero and an SQLite error +** code returned. +** +** The algorithm used to find the correct record is: +** +** * Scan up to BTREE_FDK_RANGE entries either side of the current entry. +** If parameter bIntegrity is false, then all fields that are indexed +** expressions or virtual table columns are omitted from the comparison. +** If bIntegrity is true, then small differences in real values in +** such fields are overlooked, but they are not omitted from the comparison +** altogether. +** +** * If the above fails to find an entry and bIntegrity is false, search +** the entire index. +*/ +SQLITE_PRIVATE int sqlite3VdbeFindIndexKey( + BtCursor *pCur, + Index *pIdx, + UnpackedRecord *p, + int *pRes, + int bIntegrity +){ +#define BTREE_FDK_RANGE 10 + int nStep = 0; + int res = 1; + int rc = SQLITE_OK; + int ii = 0; + + /* Calculate a mask based on the first 64 columns of the index. The mask + ** bit is set if the corresponding index field is either an expression + ** or a virtual column of the table. */ + Bitmask mask = 0; + for(ii=0; iinColumn, BMS); ii++){ + int iCol = pIdx->aiColumn[ii]; + if( (iCol==XN_EXPR) + || (iCol>=0 && (pIdx->pTable->aCol[iCol].colFlags & COLFLAG_VIRTUAL)) + ){ + mask |= MASKBIT(ii); + } + } + + /* If the mask is 0 at this point, then the index contains no expressions + ** or virtual columns. So do not search for a match - return so that the + ** caller may declare the db corrupt immediately. Or, if mask is non-zero, + ** proceed. */ + if( mask!=0 ){ + + /* Move the cursor back BTREE_FDK_RANGE entries. If this hits an EOF, + ** position the cursor at the first entry in the index and set nStep + ** to -1 so that the first loop below scans the entire index. Otherwise, + ** set nStep to BTREE_FDK_RANGE*2 so that the first loop below scans + ** just that many entries. */ + for(ii=0; sqlite3BtreeEof(pCur)==0 && ii=0), or the entire index if (nStep<0). */ + while( sqlite3BtreeCursorIsValidNN(pCur) ){ + for(ii=0; rc==SQLITE_OK && (iizName; - static const u8 fakeSortOrder = 0; #ifdef SQLITE_DEBUG int nRealCol; if( pTab->tabFlags & TF_WithoutRowid ){ @@ -90639,10 +93804,11 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( preupdate.pCsr = pCsr; preupdate.op = op; preupdate.iNewReg = iReg; - preupdate.keyinfo.db = db; - preupdate.keyinfo.enc = ENC(db); - preupdate.keyinfo.nKeyField = pTab->nCol; - preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder; + preupdate.pKeyinfo = (KeyInfo*)&preupdate.uKey; + preupdate.pKeyinfo->db = db; + preupdate.pKeyinfo->enc = ENC(db); + preupdate.pKeyinfo->nKeyField = pTab->nCol; + preupdate.pKeyinfo->aSortFlags = 0; /* Indicate .aColl, .nAllField uninit */ preupdate.iKey1 = iKey1; preupdate.iKey2 = iKey2; preupdate.pTab = pTab; @@ -90652,8 +93818,9 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2); db->pPreUpdate = 0; sqlite3DbFree(db, preupdate.aRecord); - vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked); - vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked); + vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pUnpacked); + vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pNewUnpacked); + sqlite3VdbeMemRelease(&preupdate.oldipk); if( preupdate.aNew ){ int i; for(i=0; inField; i++){ @@ -90671,6 +93838,17 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ +#ifdef SQLITE_ENABLE_PERCENTILE +/* +** Return the name of an SQL function associated with the sqlite3_context. +*/ +SQLITE_PRIVATE const char *sqlite3VdbeFuncName(const sqlite3_context *pCtx){ + assert( pCtx!=0 ); + assert( pCtx->pFunc!=0 ); + return pCtx->pFunc->zName; +} +#endif /* SQLITE_ENABLE_PERCENTILE */ + /************** End of vdbeaux.c *********************************************/ /************** Begin file vdbeapi.c *****************************************/ /* @@ -90702,8 +93880,14 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( ** added or changed. */ SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){ - Vdbe *p = (Vdbe*)pStmt; - return p==0 || p->expired; + int iRet = 1; + if( pStmt ){ + Vdbe *p = (Vdbe*)pStmt; + sqlite3_mutex_enter(p->db->mutex); + iRet = p->expired; + sqlite3_mutex_leave(p->db->mutex); + } + return iRet; } #endif @@ -90738,7 +93922,6 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ sqlite3_int64 iNow; sqlite3_int64 iElapse; assert( p->startTime>0 ); - assert( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 ); assert( db->init.busy==0 ); assert( p->zSql!=0 ); sqlite3OsCurrentTimeInt64(db->pVfs, &iNow); @@ -91068,7 +94251,23 @@ static void setResultStrOrError( void (*xDel)(void*) /* Destructor function */ ){ Mem *pOut = pCtx->pOut; - int rc = sqlite3VdbeMemSetStr(pOut, z, n, enc, xDel); + int rc; + if( enc==SQLITE_UTF8 ){ + rc = sqlite3VdbeMemSetText(pOut, z, n, xDel); + }else if( enc==SQLITE_UTF8_ZT ){ + /* It is usually considered improper to assert() on an input. However, + ** the following assert() is checking for inputs that are documented + ** to result in undefined behavior. */ + assert( z==0 + || n<0 + || n>pOut->db->aLimit[SQLITE_LIMIT_LENGTH] + || z[n]==0 + ); + rc = sqlite3VdbeMemSetText(pOut, z, n, xDel); + pOut->flags |= MEM_Term; + }else{ + rc = sqlite3VdbeMemSetStr(pOut, z, n, enc, xDel); + } if( rc ){ if( rc==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(pCtx); @@ -91261,7 +94460,7 @@ SQLITE_API void sqlite3_result_text64( #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); - if( enc!=SQLITE_UTF8 ){ + if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF8_ZT ){ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; n &= ~(u64)1; } @@ -91412,6 +94611,8 @@ static int doWalCallbacks(sqlite3 *db){ } } } +#else + UNUSED_PARAMETER(db); #endif return rc; } @@ -91458,7 +94659,7 @@ static int sqlite3Step(Vdbe *p){ } assert( db->nVdbeWrite>0 || db->autoCommit==0 - || (db->nDeferredCons==0 && db->nDeferredImmCons==0) + || ((db->nDeferredCons + db->nDeferredImmCons)==0) ); #ifndef SQLITE_OMIT_TRACE @@ -91719,7 +94920,7 @@ static int valueFromValueList( Mem sMem; /* Raw content of current row */ memset(&sMem, 0, sizeof(sMem)); sz = sqlite3BtreePayloadSize(pRhs->pCsr); - rc = sqlite3VdbeMemFromBtreeZeroOffset(pRhs->pCsr,(int)sz,&sMem); + rc = sqlite3VdbeMemFromBtreeZeroOffset(pRhs->pCsr,sz,&sMem); if( rc==SQLITE_OK ){ u8 *zBuf = (u8*)sMem.z; u32 iSerial; @@ -91969,6 +95170,7 @@ static const Mem *columnNullValue(void){ #ifdef SQLITE_DEBUG /* .pScopyFrom = */ (Mem*)0, /* .mScopyFlags= */ 0, + /* .bScopy = */ 0, #endif }; return &nullMem; @@ -92010,7 +95212,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){ ** sqlite3_column_int64() ** sqlite3_column_text() ** sqlite3_column_text16() -** sqlite3_column_real() +** sqlite3_column_double() ** sqlite3_column_bytes() ** sqlite3_column_bytes16() ** sqlite3_column_blob() @@ -92367,7 +95569,23 @@ static int bindText( assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ if( zData!=0 ){ pVar = &p->aVar[i-1]; - rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); + if( encoding==SQLITE_UTF8 ){ + rc = sqlite3VdbeMemSetText(pVar, zData, nData, xDel); + }else if( encoding==SQLITE_UTF8_ZT ){ + /* It is usually consider improper to assert() on an input. + ** However, the following assert() is checking for inputs + ** that are documented to result in undefined behavior. */ + assert( zData==0 + || nData<0 + || nData>pVar->db->aLimit[SQLITE_LIMIT_LENGTH] + || ((u8*)zData)[nData]==0 + ); + rc = sqlite3VdbeMemSetText(pVar, zData, nData, xDel); + pVar->flags |= MEM_Term; + }else{ + rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); + if( encoding==0 ) pVar->enc = ENC(p->db); + } if( rc==SQLITE_OK && encoding!=0 ){ rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); } @@ -92481,9 +95699,9 @@ SQLITE_API int sqlite3_bind_text64( unsigned char enc ){ assert( xDel!=SQLITE_DYNAMIC ); - if( enc!=SQLITE_UTF8 ){ + if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF8_ZT ){ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; - nData &= ~(u16)1; + nData &= ~(u64)1; } return bindText(pStmt, i, zData, nData, xDel, enc); } @@ -92838,7 +96056,7 @@ static UnpackedRecord *vdbeUnpackRecord( pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); if( pRet ){ memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1)); - sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet); + sqlite3VdbeRecordUnpack(nKey, pKey, pRet); } return pRet; } @@ -92851,6 +96069,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa PreUpdate *p; Mem *pMem; int rc = SQLITE_OK; + int iStore = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( db==0 || ppValue==0 ){ @@ -92865,67 +96084,78 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa goto preupdate_old_out; } if( p->pPk ){ - iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); + iStore = sqlite3TableColumnToIndex(p->pPk, iIdx); + }else if( iIdx >= p->pTab->nCol ){ + rc = SQLITE_MISUSE_BKPT; + goto preupdate_old_out; + }else{ + iStore = sqlite3TableColumnToStorage(p->pTab, iIdx); } - if( iIdx>=p->pCsr->nField || iIdx<0 ){ + if( iStore>=p->pCsr->nField || iStore<0 ){ rc = SQLITE_RANGE; goto preupdate_old_out; } - /* If the old.* record has not yet been loaded into memory, do so now. */ - if( p->pUnpacked==0 ){ - u32 nRec; - u8 *aRec; + if( iIdx==p->pTab->iPKey ){ + *ppValue = pMem = &p->oldipk; + sqlite3VdbeMemSetInt64(pMem, p->iKey1); + }else{ + + /* If the old.* record has not yet been loaded into memory, do so now. */ + if( p->pUnpacked==0 ){ + u32 nRec; + u8 *aRec; - assert( p->pCsr->eCurType==CURTYPE_BTREE ); - nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); - aRec = sqlite3DbMallocRaw(db, nRec); - if( !aRec ) goto preupdate_old_out; - rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); - if( rc==SQLITE_OK ){ - p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); - if( !p->pUnpacked ) rc = SQLITE_NOMEM; - } - if( rc!=SQLITE_OK ){ - sqlite3DbFree(db, aRec); - goto preupdate_old_out; + assert( p->pCsr->eCurType==CURTYPE_BTREE ); + nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); + aRec = sqlite3DbMallocRaw(db, nRec); + if( !aRec ) goto preupdate_old_out; + rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec); + if( rc==SQLITE_OK ){ + p->pUnpacked = vdbeUnpackRecord(p->pKeyinfo, nRec, aRec); + if( !p->pUnpacked ) rc = SQLITE_NOMEM; + } + if( rc!=SQLITE_OK ){ + sqlite3DbFree(db, aRec); + goto preupdate_old_out; + } + p->aRecord = aRec; } - p->aRecord = aRec; - } - pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; - if( iIdx==p->pTab->iPKey ){ - sqlite3VdbeMemSetInt64(pMem, p->iKey1); - }else if( iIdx>=p->pUnpacked->nField ){ - /* This occurs when the table has been extended using ALTER TABLE - ** ADD COLUMN. The value to return is the default value of the column. */ - Column *pCol = &p->pTab->aCol[iIdx]; - if( pCol->iDflt>0 ){ - if( p->apDflt==0 ){ - int nByte = sizeof(sqlite3_value*)*p->pTab->nCol; - p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte); - if( p->apDflt==0 ) goto preupdate_old_out; - } - if( p->apDflt[iIdx]==0 ){ - sqlite3_value *pVal = 0; - Expr *pDflt; - assert( p->pTab!=0 && IsOrdinaryTable(p->pTab) ); - pDflt = p->pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; - rc = sqlite3ValueFromExpr(db, pDflt, ENC(db), pCol->affinity, &pVal); - if( rc==SQLITE_OK && pVal==0 ){ - rc = SQLITE_CORRUPT_BKPT; + pMem = *ppValue = &p->pUnpacked->aMem[iStore]; + if( iStore>=p->pUnpacked->nField ){ + /* This occurs when the table has been extended using ALTER TABLE + ** ADD COLUMN. The value to return is the default value of the column. */ + Column *pCol = &p->pTab->aCol[iIdx]; + if( pCol->iDflt>0 ){ + if( p->apDflt==0 ){ + int nByte; + assert( sizeof(sqlite3_value*)*UMXV(p->pTab->nCol) < 0x7fffffff ); + nByte = sizeof(sqlite3_value*)*p->pTab->nCol; + p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte); + if( p->apDflt==0 ) goto preupdate_old_out; + } + if( p->apDflt[iIdx]==0 ){ + sqlite3_value *pVal = 0; + Expr *pDflt; + assert( p->pTab!=0 && IsOrdinaryTable(p->pTab) ); + pDflt = p->pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; + rc = sqlite3ValueFromExpr(db, pDflt, ENC(db), pCol->affinity, &pVal); + if( rc==SQLITE_OK && pVal==0 ){ + rc = SQLITE_CORRUPT_BKPT; + } + p->apDflt[iIdx] = pVal; } - p->apDflt[iIdx] = pVal; + *ppValue = p->apDflt[iIdx]; + }else{ + *ppValue = (sqlite3_value *)columnNullValue(); + } + }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ + if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_IntReal ); + sqlite3VdbeMemRealify(pMem); } - *ppValue = p->apDflt[iIdx]; - }else{ - *ppValue = (sqlite3_value *)columnNullValue(); - } - }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ - if( pMem->flags & (MEM_Int|MEM_IntReal) ){ - testcase( pMem->flags & MEM_Int ); - testcase( pMem->flags & MEM_IntReal ); - sqlite3VdbeMemRealify(pMem); } } @@ -92947,7 +96177,7 @@ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ #else p = db->pPreUpdate; #endif - return (p ? p->keyinfo.nKeyField : 0); + return (p ? p->pKeyinfo->nKeyField : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -92999,6 +96229,7 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa PreUpdate *p; int rc = SQLITE_OK; Mem *pMem; + int iStore = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( db==0 || ppValue==0 ){ @@ -93011,9 +96242,14 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa goto preupdate_new_out; } if( p->pPk && p->op!=SQLITE_UPDATE ){ - iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); + iStore = sqlite3TableColumnToIndex(p->pPk, iIdx); + }else if( iIdx >= p->pTab->nCol ){ + return SQLITE_MISUSE_BKPT; + }else{ + iStore = sqlite3TableColumnToStorage(p->pTab, iIdx); } - if( iIdx>=p->pCsr->nField || iIdx<0 ){ + + if( iStore>=p->pCsr->nField || iStore<0 ){ rc = SQLITE_RANGE; goto preupdate_new_out; } @@ -93026,40 +96262,41 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa Mem *pData = &p->v->aMem[p->iNewReg]; rc = ExpandBlob(pData); if( rc!=SQLITE_OK ) goto preupdate_new_out; - pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z); + pUnpack = vdbeUnpackRecord(p->pKeyinfo, pData->n, pData->z); if( !pUnpack ){ rc = SQLITE_NOMEM; goto preupdate_new_out; } p->pNewUnpacked = pUnpack; } - pMem = &pUnpack->aMem[iIdx]; + pMem = &pUnpack->aMem[iStore]; if( iIdx==p->pTab->iPKey ){ sqlite3VdbeMemSetInt64(pMem, p->iKey2); - }else if( iIdx>=pUnpack->nField ){ + }else if( iStore>=pUnpack->nField ){ pMem = (sqlite3_value *)columnNullValue(); } }else{ - /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required + /* For an UPDATE, memory cell (p->iNewReg+1+iStore) contains the required ** value. Make a copy of the cell contents and return a pointer to it. ** It is not safe to return a pointer to the memory cell itself as the ** caller may modify the value text encoding. */ assert( p->op==SQLITE_UPDATE ); if( !p->aNew ){ - p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField); + assert( sizeof(Mem)*UMXV(p->pCsr->nField) < 0x7fffffff ); + p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem)*p->pCsr->nField); if( !p->aNew ){ rc = SQLITE_NOMEM; goto preupdate_new_out; } } - assert( iIdx>=0 && iIdxpCsr->nField ); - pMem = &p->aNew[iIdx]; + assert( iStore>=0 && iStorepCsr->nField ); + pMem = &p->aNew[iStore]; if( pMem->flags==0 ){ if( iIdx==p->pTab->iPKey ){ sqlite3VdbeMemSetInt64(pMem, p->iKey2); }else{ - rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]); + rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iStore]); if( rc!=SQLITE_OK ) goto preupdate_new_out; } } @@ -93283,10 +96520,10 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ ** a host parameter. If the text contains no host parameters, return ** the total number of bytes in the text. */ -static int findNextHostParameter(const char *zSql, int *pnToken){ +static i64 findNextHostParameter(const char *zSql, i64 *pnToken){ int tokenType; - int nTotal = 0; - int n; + i64 nTotal = 0; + i64 n; *pnToken = 0; while( zSql[0] ){ @@ -93333,8 +96570,8 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( sqlite3 *db; /* The database connection */ int idx = 0; /* Index of a host parameter */ int nextIndex = 1; /* Index of next ? host parameter */ - int n; /* Length of a token prefix */ - int nToken; /* Length of the parameter token */ + i64 n; /* Length of a token prefix */ + i64 nToken; /* Length of the parameter token */ int i; /* Loop counter */ Mem *pVar; /* Value of a host parameter */ StrAccum out; /* Accumulate the output here */ @@ -93499,17 +96736,19 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( #ifndef SQLITE_HWTIME_H #define SQLITE_HWTIME_H -/* -** The following routine only works on Pentium-class (or newer) processors. -** It uses the RDTSC opcode to read the cycle count value out of the -** processor and returns that value. This can be used for high-res -** profiling. -*/ -#if !defined(__STRICT_ANSI__) && \ - (defined(__GNUC__) || defined(_MSC_VER)) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) +#if defined(_MSC_VER) && defined(_WIN32) - #if defined(__GNUC__) +/* #include "windows.h" */ + #include + + __inline sqlite3_uint64 sqlite3Hwtime(void){ + LARGE_INTEGER tm; + QueryPerformanceCounter(&tm); + return (sqlite3_uint64)tm.QuadPart; + } + +#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && \ + (defined(i386) || defined(__i386__) || defined(_M_IX86)) __inline__ sqlite_uint64 sqlite3Hwtime(void){ unsigned int lo, hi; @@ -93517,17 +96756,6 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( return (sqlite_uint64)hi << 32 | lo; } - #elif defined(_MSC_VER) - - __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - #elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) __inline__ sqlite_uint64 sqlite3Hwtime(void){ @@ -93536,6 +96764,14 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( return (sqlite_uint64)hi << 32 | lo; } +#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__aarch64__) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + sqlite3_uint64 cnt; + __asm__ __volatile__ ("mrs %0, cntvct_el0" : "=r" (cnt)); + return cnt; + } + #elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) __inline__ sqlite_uint64 sqlite3Hwtime(void){ @@ -93817,11 +97053,11 @@ static VdbeCursor *allocateCursor( */ Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem; - int nByte; + i64 nByte; VdbeCursor *pCx = 0; - nByte = - ROUND8P(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + - (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0); + nByte = SZ_VDBECURSOR(nField); + assert( ROUND8(nByte)==nByte ); + if( eCurType==CURTYPE_BTREE ) nByte += sqlite3BtreeCursorSize(); assert( iCur>=0 && iCurnCursor ); if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/ @@ -93845,7 +97081,7 @@ static VdbeCursor *allocateCursor( pMem->szMalloc = 0; return 0; } - pMem->szMalloc = nByte; + pMem->szMalloc = (int)nByte; } p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc; @@ -93854,8 +97090,8 @@ static VdbeCursor *allocateCursor( pCx->nField = nField; pCx->aOffset = &pCx->aType[nField]; if( eCurType==CURTYPE_BTREE ){ - pCx->uc.pCursor = (BtCursor*) - &pMem->z[ROUND8P(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; + assert( ROUND8(SZ_VDBECURSOR(nField))==SZ_VDBECURSOR(nField) ); + pCx->uc.pCursor = (BtCursor*)&pMem->z[SZ_VDBECURSOR(nField)]; sqlite3BtreeCursorZero(pCx->uc.pCursor); } return pCx; @@ -93894,12 +97130,11 @@ static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){ */ static void applyNumericAffinity(Mem *pRec, int bTryForInt){ double rValue; - u8 enc = pRec->enc; int rc; assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str ); - rc = sqlite3AtoF(pRec->z, &rValue, pRec->n, enc); + rc = sqlite3MemRealValueRC(pRec, &rValue); if( rc<=0 ) return; - if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){ + if( (rc&2)==0 && alsoAnInt(pRec, rValue, &pRec->u.i) ){ pRec->flags |= MEM_Int; }else{ pRec->u.r = rValue; @@ -93979,7 +97214,10 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){ int eType = sqlite3_value_type(pVal); if( eType==SQLITE_TEXT ){ Mem *pMem = (Mem*)pVal; + assert( pMem->db!=0 ); + sqlite3_mutex_enter(pMem->db->mutex); applyNumericAffinity(pMem, 0); + sqlite3_mutex_leave(pMem->db->mutex); eType = sqlite3_value_type(pVal); } return eType; @@ -94012,15 +97250,15 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ pMem->u.i = 0; return MEM_Int; } - rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + rc = sqlite3MemRealValueRC(pMem, &pMem->u.r); if( rc<=0 ){ - if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){ + if( (rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){ pMem->u.i = ix; return MEM_Int; }else{ return MEM_Real; } - }else if( rc==1 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){ + }else if( (rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){ pMem->u.i = ix; return MEM_Int; } @@ -94148,6 +97386,7 @@ static void registerTrace(int iReg, Mem *p){ printf("R[%d] = ", iReg); memTracePrint(p); if( p->pScopyFrom ){ + assert( p->pScopyFrom->bScopy ); printf(" <== R[%d]", (int)(p->pScopyFrom - &p[-iReg])); } printf("\n"); @@ -94257,7 +97496,7 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){ static SQLITE_NOINLINE int vdbeColumnFromOverflow( VdbeCursor *pC, /* The BTree cursor from which we are reading */ int iCol, /* The column to read */ - int t, /* The serial-type code for the column value */ + u32 t, /* The serial-type code for the column value */ i64 iOffset, /* Offset to the start of the content value */ u32 cacheStatus, /* Current Vdbe.cacheCtr value */ u32 colCacheCtr, /* Current value of the column cache counter */ @@ -94332,6 +97571,36 @@ static SQLITE_NOINLINE int vdbeColumnFromOverflow( return rc; } +/* +** Send a "statement aborts" message to the error log. +*/ +static SQLITE_NOINLINE void sqlite3VdbeLogAbort( + Vdbe *p, /* The statement that is running at the time of failure */ + int rc, /* Error code */ + Op *pOp, /* Opcode that filed */ + Op *aOp /* All opcodes */ +){ + const char *zSql = p->zSql; /* Original SQL text */ + const char *zPrefix = ""; /* Prefix added to SQL text */ + int pc; /* Opcode address */ + char zXtra[100]; /* Buffer space to store zPrefix */ + + if( p->pFrame ){ + assert( aOp[0].opcode==OP_Init ); + if( aOp[0].p4.z!=0 ){ + assert( aOp[0].p4.z[0]=='-' + && aOp[0].p4.z[1]=='-' + && aOp[0].p4.z[2]==' ' ); + sqlite3_snprintf(sizeof(zXtra), zXtra,"/* %s */ ",aOp[0].p4.z+3); + zPrefix = zXtra; + }else{ + zPrefix = "/* unknown trigger */ "; + } + } + pc = (int)(pOp - aOp); + sqlite3_log(rc, "statement aborts at %d: %s; [%s%s]", + pc, p->zErrMsg, zPrefix, zSql); +} /* ** Return the symbolic name for the data type of a pMem @@ -94857,8 +98126,7 @@ case OP_Halt: { }else{ sqlite3VdbeError(p, "%s", pOp->p4.z); } - pcx = (int)(pOp - aOp); - sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg); + sqlite3VdbeLogAbort(p, pOp->p1, pOp, aOp); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); @@ -95131,6 +98399,7 @@ case OP_Move: { { int i; for(i=1; inMem; i++){ if( aMem[i].pScopyFrom==pIn1 ){ + assert( aMem[i].bScopy ); aMem[i].pScopyFrom = pOut; } } @@ -95203,6 +98472,7 @@ case OP_SCopy: { /* out2 */ #ifdef SQLITE_DEBUG pOut->pScopyFrom = pIn1; pOut->mScopyFlags = pIn1->flags; + pIn1->bScopy = 1; #endif break; } @@ -95235,7 +98505,7 @@ case OP_IntCopy: { /* out2 */ ** RETURNING clause. */ case OP_FkCheck: { - if( (rc = sqlite3VdbeCheckFk(p,0))!=SQLITE_OK ){ + if( (rc = sqlite3VdbeCheckFkImmediate(p))!=SQLITE_OK ){ goto abort_due_to_error; } break; @@ -95327,10 +98597,14 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ if( sqlite3VdbeMemExpandBlob(pIn2) ) goto no_mem; flags2 = pIn2->flags & ~MEM_Str; } - nByte = pIn1->n + pIn2->n; + nByte = pIn1->n; + nByte += pIn2->n; if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } +#if SQLITE_MAX_LENGTH>2147483645 + if( nByte>2147483645 ){ goto too_big; } +#endif if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){ goto no_mem; } @@ -96014,6 +99288,7 @@ case OP_Compare: { pKeyInfo = pOp->p4.pKeyInfo; assert( n>0 ); assert( pKeyInfo!=0 ); + assert( pKeyInfo->aSortFlags!=0 ); p1 = pOp->p1; p2 = pOp->p2; #ifdef SQLITE_DEBUG @@ -96182,7 +99457,7 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ break; } -/* Opcode: Once P1 P2 * * * +/* Opcode: Once P1 P2 P3 * * ** ** Fall through to the next instruction the first time this opcode is ** encountered on each invocation of the byte-code program. Jump to P2 @@ -96198,6 +99473,12 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ ** whether or not the jump should be taken. The bitmask is necessary ** because the self-altering code trick does not work for recursive ** triggers. +** +** The P3 operand is not used directly by this opcode. However P3 is +** used by the code generator as follows: If this opcode is the start +** of a subroutine and that subroutine uses a Bloom filter, then P3 will +** be the register that holds that Bloom filter. See tag-202407032019 +** in the source code for implementation details. */ case OP_Once: { /* jump */ u32 iAddr; /* Address of this instruction */ @@ -96770,6 +100051,15 @@ case OP_Column: { /* ncycle */ ** Take the affinities from the Table object in P4. If any value ** cannot be coerced into the correct type, then raise an error. ** +** If P3==0, then omit checking of VIRTUAL columns. +** +** If P3==1, then omit checking of all generated column, both VIRTUAL +** and STORED. +** +** If P3>=2, then only check column number P3-2 in the table (which will +** be a VIRTUAL column) against the value in reg[P1]. In this case, +** P2 will be 1. +** ** This opcode is similar to OP_Affinity except that this opcode ** forces the register type to the Table column type. This is used ** to implement "strict affinity". @@ -96783,8 +100073,8 @@ case OP_Column: { /* ncycle */ ** **
          **
        • P2 should be the number of non-virtual columns in the -** table of P4. -**
        • Table P4 should be a STRICT table. +** table of P4 unless P3>1, in which case P2 will be 1. +**
        • Table P4 is a STRICT table. **
        ** ** If any precondition is false, an assertion fault occurs. @@ -96793,16 +100083,28 @@ case OP_TypeCheck: { Table *pTab; Column *aCol; int i; + int nCol; assert( pOp->p4type==P4_TABLE ); pTab = pOp->p4.pTab; assert( pTab->tabFlags & TF_Strict ); - assert( pTab->nNVCol==pOp->p2 ); + assert( pOp->p3>=0 && pOp->p3nCol+2 ); aCol = pTab->aCol; pIn1 = &aMem[pOp->p1]; - for(i=0; inCol; i++){ - if( aCol[i].colFlags & COLFLAG_GENERATED ){ - if( aCol[i].colFlags & COLFLAG_VIRTUAL ) continue; + if( pOp->p3<2 ){ + assert( pTab->nNVCol==pOp->p2 ); + i = 0; + nCol = pTab->nCol; + }else{ + i = pOp->p3-2; + nCol = i+1; + assert( inCol ); + assert( aCol[i].colFlags & COLFLAG_VIRTUAL ); + assert( pOp->p2==1 ); + } + for(; ip3<2 ){ + if( (aCol[i].colFlags & COLFLAG_VIRTUAL)!=0 ) continue; if( pOp->p3 ){ pIn1++; continue; } } assert( pIn1 < &aMem[pOp->p1+pOp->p2] ); @@ -97124,7 +100426,7 @@ case OP_MakeRecord: { len = (u32)pRec->n; serial_type = (len*2) + 12 + ((pRec->flags & MEM_Str)!=0); if( pRec->flags & MEM_Zero ){ - serial_type += pRec->u.nZero*2; + serial_type += (u32)pRec->u.nZero*2; if( nData ){ if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem; len += pRec->u.nZero; @@ -97243,6 +100545,7 @@ case OP_MakeRecord: { zHdr += sqlite3PutVarint(zHdr, serial_type); if( pRec->n ){ assert( pRec->z!=0 ); + assert( pRec->z!=(const char*)sqlite3CtypeMap ); memcpy(zPayload, pRec->z, pRec->n); zPayload += pRec->n; } @@ -97390,7 +100693,7 @@ case OP_Savepoint: { */ int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint; if( isTransaction && p1==SAVEPOINT_RELEASE ){ - if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ + if( (rc = sqlite3VdbeCheckFkDeferred(p))!=SQLITE_OK ){ goto vdbe_return; } db->autoCommit = 1; @@ -97508,7 +100811,7 @@ case OP_AutoCommit: { "SQL statements in progress"); rc = SQLITE_BUSY; goto abort_due_to_error; - }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ + }else if( (rc = sqlite3VdbeCheckFkDeferred(p))!=SQLITE_OK ){ goto vdbe_return; }else{ db->autoCommit = (u8)desiredAutoCommit; @@ -98079,9 +101382,11 @@ case OP_OpenEphemeral: { /* ncycle */ } } pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); + assert( p->apCsr[pOp->p1]==pCx ); if( rc ){ assert( !sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) ); sqlite3BtreeClose(pCx->ub.pBtx); + p->apCsr[pOp->p1] = 0; /* Not required; helps with static analysis */ }else{ assert( sqlite3BtreeClosesWithCursor(pCx->ub.pBtx, pCx->uc.pCursor) ); } @@ -98878,7 +102183,7 @@ case OP_Found: { /* jump, in3, ncycle */ if( rc ) goto no_mem; pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo); if( pIdxKey==0 ) goto no_mem; - sqlite3VdbeRecordUnpack(pC->pKeyInfo, r.aMem->n, r.aMem->z, pIdxKey); + sqlite3VdbeRecordUnpack(r.aMem->n, r.aMem->z, pIdxKey); pIdxKey->default_rc = 0; rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &pC->seekResult); sqlite3DbFreeNN(db, pIdxKey); @@ -99592,7 +102897,7 @@ case OP_RowData: { /* The OP_RowData opcodes always follow OP_NotExists or ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions ** that might invalidate the cursor. - ** If this where not the case, on of the following assert()s + ** If this were not the case, one of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). @@ -99876,6 +103181,32 @@ case OP_Rewind: { /* jump0, ncycle */ break; } +/* Opcode: IfEmpty P1 P2 * * * +** Synopsis: if( empty(P1) ) goto P2 +** +** Check to see if the b-tree table that cursor P1 references is empty +** and jump to P2 if it is. +*/ +case OP_IfEmpty: { /* jump */ + VdbeCursor *pC; + BtCursor *pCrsr; + int res; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( pOp->p2>=0 && pOp->p2nOp ); + + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + pCrsr = pC->uc.pCursor; + assert( pCrsr ); + rc = sqlite3BtreeIsEmpty(pCrsr, &res); + if( rc ) goto abort_due_to_error; + VdbeBranchTaken(res!=0,2); + if( res ) goto jump_to_p2; + break; +} + /* Opcode: Next P1 P2 P3 * P5 ** ** Advance cursor P1 so that it points to the next key/data pair in its @@ -100068,20 +103399,17 @@ case OP_SorterInsert: { /* in2 */ break; } -/* Opcode: IdxDelete P1 P2 P3 * P5 +/* Opcode: IdxDelete P1 P2 P3 P4 * ** Synopsis: key=r[P2@P3] ** ** The content of P3 registers starting at register P2 form ** an unpacked index key. This opcode removes that entry from the ** index opened by cursor P1. ** -** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error -** if no matching index entry is found. This happens when running -** an UPDATE or DELETE statement and the index entry to be updated -** or deleted is not found. For some uses of IdxDelete -** (example: the EXCEPT operator) it does not matter that no matching -** entry is found. For those cases, P5 is zero. Also, do not raise -** this (self-correcting and non-critical) error if in writable_schema mode. +** P4 is a pointer to an Index structure. +** +** Raise an SQLITE_CORRUPT_INDEX error if no matching index entry is found +** and not in writable_schema mode. */ case OP_IdxDelete: { VdbeCursor *pC; @@ -100104,13 +103432,22 @@ case OP_IdxDelete: { r.aMem = &aMem[pOp->p2]; rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res); if( rc ) goto abort_due_to_error; - if( res==0 ){ - rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); - if( rc ) goto abort_due_to_error; - }else if( pOp->p5 && !sqlite3WritableSchema(db) ){ - rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption"); - goto abort_due_to_error; + if( res!=0 ){ + rc = sqlite3VdbeFindIndexKey(pCrsr, pOp->p4.pIdx, &r, &res, 0); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + if( res!=0 ){ + if( !sqlite3WritableSchema(db) ){ + rc = sqlite3ReportError( + SQLITE_CORRUPT_INDEX, __LINE__, "index corruption"); + goto abort_due_to_error; + } + pC->cacheStatus = CACHE_STALE; + pC->seekResult = 0; + break; + } } + rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); + if( rc ) goto abort_due_to_error; assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; pC->seekResult = 0; @@ -100737,6 +104074,58 @@ case OP_IntegrityCk: { sqlite3VdbeChangeEncoding(pIn1, encoding); goto check_for_interrupt; } + +/* Opcode: IFindKey P1 P2 P3 P4 * +** +** This instruction always follows an OP_Found with the same P1, P2 and P3 +** values as this instruction and a non-zero P4 value. The P4 value to +** this opcode is of type P4_INDEX and contains a pointer to the Index +** object of for the index being searched. +** +** This opcode uses sqlite3VdbeFindIndexKey() to search around the current +** cursor location for an index key that exactly matches all fields that +** are not indexed expressions or references to VIRTUAL generated columns, +** and either exactly match or are real numbers that are within 2 ULPs of +** each other if the don't match. +** +** To put it another way, this opcode looks for nearby index entries that +** are very close to the search key, but which might have small differences +** in floating-point values that come via an expression. +** +** If no nearby alternative entry is found in cursor P1, then jump to P2. +** But if a close match is found, fall through. +** +** This opcode is used by PRAGMA integrity_check to help distinguish +** between truely corrupt indexes and expression indexes that are holding +** floating-point values that are off by one or two ULPs. +*/ +case OP_IFindKey: { /* jump, in3 */ + VdbeCursor *pC; + int res; + UnpackedRecord r; + + assert( pOp[-1].opcode==OP_Found ); + assert( pOp[-1].p1==pOp->p1 ); + assert( pOp[-1].p3==pOp->p3 ); + pC = p->apCsr[pOp->p1]; + assert( pOp->p4type==P4_INDEX ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->uc.pCursor!=0 ); + assert( pC->isTable==0 ); + + memset(&r, 0, sizeof(r)); + r.aMem = &aMem[pOp->p3]; + r.nField = pOp->p4.pIdx->nColumn; + r.pKeyInfo = pC->pKeyInfo; + + rc = sqlite3VdbeFindIndexKey(pC->uc.pCursor, pOp->p4.pIdx, &r, &res, 1); + if( rc || res!=0 ){ + rc = SQLITE_OK; + goto jump_to_p2; + } + pC->nullRow = 0; + break; +}; #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* Opcode: RowSetAdd P1 P2 * * * @@ -100861,7 +104250,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */ */ case OP_Program: { /* jump0 */ int nMem; /* Number of memory registers for sub-program */ - int nByte; /* Bytes of runtime space required for sub-program */ + i64 nByte; /* Bytes of runtime space required for sub-program */ Mem *pRt; /* Register to allocate runtime space */ Mem *pMem; /* Used to iterate through memory cells */ Mem *pEnd; /* Last memory cell in new array */ @@ -100912,7 +104301,7 @@ case OP_Program: { /* jump0 */ nByte = ROUND8(sizeof(VdbeFrame)) + nMem * sizeof(Mem) + pProgram->nCsr * sizeof(VdbeCursor*) - + (pProgram->nOp + 7)/8; + + (7 + (i64)pProgram->nOp)/8; pFrame = sqlite3DbMallocZero(db, nByte); if( !pFrame ){ goto no_mem; @@ -100920,7 +104309,7 @@ case OP_Program: { /* jump0 */ sqlite3VdbeMemRelease(pRt); pRt->flags = MEM_Blob|MEM_Dyn; pRt->z = (char*)pFrame; - pRt->n = nByte; + pRt->n = (int)nByte; pRt->xDel = sqlite3VdbeFrameMemDel; pFrame->v = p; @@ -101019,12 +104408,14 @@ case OP_Param: { /* out2 */ ** statement counter is incremented (immediate foreign key constraints). */ case OP_FkCounter: { - if( db->flags & SQLITE_DeferFKs ){ - db->nDeferredImmCons += pOp->p2; - }else if( pOp->p1 ){ + if( pOp->p1 ){ db->nDeferredCons += pOp->p2; }else{ - p->nFkConstraint += pOp->p2; + if( db->flags & SQLITE_DeferFKs ){ + db->nDeferredImmCons += pOp->p2; + }else{ + p->nFkConstraint += pOp->p2; + } } break; } @@ -101239,7 +104630,7 @@ case OP_AggStep: { ** ** Note: We could avoid this by using a regular memory cell from aMem[] for ** the accumulator, instead of allocating one here. */ - nAlloc = ROUND8P( sizeof(pCtx[0]) + (n-1)*sizeof(sqlite3_value*) ); + nAlloc = ROUND8P( SZ_CONTEXT(n) ); pCtx = sqlite3DbMallocRawNN(db, nAlloc + sizeof(Mem)); if( pCtx==0 ) goto no_mem; pCtx->pOut = (Mem*)((u8*)pCtx + nAlloc); @@ -101410,6 +104801,7 @@ case OP_Checkpoint: { || pOp->p2==SQLITE_CHECKPOINT_FULL || pOp->p2==SQLITE_CHECKPOINT_RESTART || pOp->p2==SQLITE_CHECKPOINT_TRUNCATE + || pOp->p2==SQLITE_CHECKPOINT_NOOP ); rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]); if( rc ){ @@ -101745,7 +105137,14 @@ case OP_VOpen: { /* ncycle */ const sqlite3_module *pModule; assert( p->bIsReader ); - pCur = 0; + pCur = p->apCsr[pOp->p1]; + if( pCur!=0 + && ALWAYS( pCur->eCurType==CURTYPE_VTAB ) + && ALWAYS( pCur->uc.pVCur->pVtab==pOp->p4.pVtab->pVtab ) + ){ + /* This opcode is a no-op if the cursor is already open */ + break; + } pVCur = 0; pVtab = pOp->p4.pVtab->pVtab; if( pVtab==0 || NEVER(pVtab->pModule==0) ){ @@ -101899,6 +105298,7 @@ case OP_VFilter: { /* jump, ncycle */ /* Invoke the xFilter method */ apArg = p->apArg; + assert( nArg<=p->napArg ); for(i = 0; ivtabOnConflict; apArg = p->apArg; pX = &aMem[pOp->p3]; + assert( nArg<=p->napArg ); for(i=0; irc = rc; sqlite3SystemError(db, rc); testcase( sqlite3GlobalConfig.xLog!=0 ); - sqlite3_log(rc, "statement aborts at %d: [%s] %s", - (int)(pOp - aOp), p->zSql, p->zErrMsg); + sqlite3VdbeLogAbort(p, rc, pOp, aOp); if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p); if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){ @@ -102895,6 +106295,7 @@ SQLITE_API int sqlite3_blob_open( char *zErr = 0; Table *pTab; Incrblob *pBlob = 0; + int iDb; Parse sParse; #ifdef SQLITE_ENABLE_API_ARMOR @@ -102940,7 +106341,10 @@ SQLITE_API int sqlite3_blob_open( sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable); } #endif - if( !pTab ){ + if( pTab==0 + || ((iDb = sqlite3SchemaToIndex(db, pTab->pSchema))==1 && + sqlite3OpenTempDatabase(&sParse)) + ){ if( sParse.zErrMsg ){ sqlite3DbFree(db, zErr); zErr = sParse.zErrMsg; @@ -102951,15 +106355,11 @@ SQLITE_API int sqlite3_blob_open( goto blob_open_out; } pBlob->pTab = pTab; - pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; + pBlob->zDb = db->aDb[iDb].zDbSName; /* Now search pTab for the exact column. */ - for(iCol=0; iColnCol; iCol++) { - if( sqlite3StrICmp(pTab->aCol[iCol].zCnName, zColumn)==0 ){ - break; - } - } - if( iCol==pTab->nCol ){ + iCol = sqlite3ColumnIndex(pTab, zColumn); + if( iCol<0 ){ sqlite3DbFree(db, zErr); zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn); rc = SQLITE_ERROR; @@ -103039,7 +106439,6 @@ SQLITE_API int sqlite3_blob_open( {OP_Halt, 0, 0, 0}, /* 5 */ }; Vdbe *v = (Vdbe *)pBlob->pStmt; - int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); VdbeOp *aOp; sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag, @@ -103148,7 +106547,7 @@ static int blobReadWrite( int iOffset, int (*xCall)(BtCursor*, u32, u32, void*) ){ - int rc; + int rc = SQLITE_OK; Incrblob *p = (Incrblob *)pBlob; Vdbe *v; sqlite3 *db; @@ -103188,17 +106587,32 @@ static int blobReadWrite( ** using the incremental-blob API, this works. For the sessions module ** anyhow. */ - sqlite3_int64 iKey; - iKey = sqlite3BtreeIntegerKey(p->pCsr); - assert( v->apCsr[0]!=0 ); - assert( v->apCsr[0]->eCurType==CURTYPE_BTREE ); - sqlite3VdbePreUpdateHook( - v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1, p->iCol - ); + if( sqlite3BtreeCursorIsValidNN(p->pCsr)==0 ){ + /* If the cursor is not currently valid, try to reseek it. This + ** always either fails or finds the correct row - the cursor will + ** have been marked permanently CURSOR_INVALID if the open row has + ** been deleted. */ + int bDiff = 0; + rc = sqlite3BtreeCursorRestore(p->pCsr, &bDiff); + assert( bDiff==0 || sqlite3BtreeCursorIsValidNN(p->pCsr)==0 ); + } + if( sqlite3BtreeCursorIsValidNN(p->pCsr) ){ + sqlite3_int64 iKey; + iKey = sqlite3BtreeIntegerKey(p->pCsr); + assert( v->apCsr[0]!=0 ); + assert( v->apCsr[0]->eCurType==CURTYPE_BTREE ); + sqlite3VdbePreUpdateHook( + v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1, p->iCol + ); + } + } + if( rc==SQLITE_OK ){ + rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); } +#else + rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); #endif - rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); sqlite3BtreeLeaveCursor(p->pCsr); if( rc==SQLITE_ABORT ){ sqlite3VdbeFinalize(v); @@ -103587,6 +107001,7 @@ struct SortSubtask { SorterCompare xCompare; /* Compare function to use */ SorterFile file; /* Temp file for level-0 PMAs */ SorterFile file2; /* Space for other PMAs */ + u64 nSpill; /* Total bytes written by this task */ }; @@ -103617,9 +107032,12 @@ struct VdbeSorter { u8 iPrev; /* Previous thread used to flush PMA */ u8 nTask; /* Size of aTask[] array */ u8 typeMask; - SortSubtask aTask[1]; /* One or more subtasks */ + SortSubtask aTask[FLEXARRAY]; /* One or more subtasks */ }; +/* Size (in bytes) of a VdbeSorter object that works with N or fewer subtasks */ +#define SZ_VDBESORTER(N) (offsetof(VdbeSorter,aTask)+(N)*sizeof(SortSubtask)) + #define SORTER_TYPE_INTEGER 0x01 #define SORTER_TYPE_TEXT 0x02 @@ -103704,6 +107122,7 @@ struct PmaWriter { int iBufEnd; /* Last byte of buffer to write */ i64 iWriteOff; /* Offset of start of buffer in file */ sqlite3_file *pFd; /* File handle to write to */ + u64 nPmaSpill; /* Total number of bytes written */ }; /* @@ -104048,7 +107467,7 @@ static int vdbeSorterCompareTail( ){ UnpackedRecord *r2 = pTask->pUnpacked; if( *pbKey2Cached==0 ){ - sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); + sqlite3VdbeRecordUnpack(nKey2, pKey2, r2); *pbKey2Cached = 1; } return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, r2, 1); @@ -104075,7 +107494,7 @@ static int vdbeSorterCompare( ){ UnpackedRecord *r2 = pTask->pUnpacked; if( !*pbKey2Cached ){ - sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); + sqlite3VdbeRecordUnpack(nKey2, pKey2, r2); *pbKey2Cached = 1; } return sqlite3VdbeRecordCompare(nKey1, pKey1, r2); @@ -104115,6 +107534,7 @@ static int vdbeSorterCompareText( ); } }else{ + assert( pTask->pSorter->pKeyInfo->aSortFlags!=0 ); assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) ); if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){ res = res * -1; @@ -104178,6 +107598,7 @@ static int vdbeSorterCompareInt( } } + assert( pTask->pSorter->pKeyInfo->aSortFlags!=0 ); if( res==0 ){ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( @@ -104221,7 +107642,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( VdbeSorter *pSorter; /* The new sorter */ KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */ int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */ - int sz; /* Size of pSorter in bytes */ + i64 sz; /* Size of pSorter in bytes */ int rc = SQLITE_OK; #if SQLITE_MAX_WORKER_THREADS==0 # define nWorker 0 @@ -104249,8 +107670,11 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( assert( pCsr->pKeyInfo ); assert( !pCsr->isEphemeral ); assert( pCsr->eCurType==CURTYPE_SORTER ); - szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*); - sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); + assert( sizeof(KeyInfo) + UMXV(pCsr->pKeyInfo->nKeyField)*sizeof(CollSeq*) + < 0x7fffffff ); + assert( pCsr->pKeyInfo->nKeyField<=pCsr->pKeyInfo->nAllField ); + szKeyInfo = SZ_KEYINFO(pCsr->pKeyInfo->nAllField); + sz = SZ_VDBESORTER(nWorker+1); pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); pCsr->uc.pSorter = pSorter; @@ -104263,7 +107687,12 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( pKeyInfo->db = 0; if( nField && nWorker==0 ){ pKeyInfo->nKeyField = nField; + assert( nField<=pCsr->pKeyInfo->nAllField ); } + /* It is OK that pKeyInfo reuses the aSortFlags field from pCsr->pKeyInfo, + ** since the pCsr->pKeyInfo->aSortFlags[] array is invariant and lives + ** longer that pSorter. */ + assert( pKeyInfo->aSortFlags==pCsr->pKeyInfo->aSortFlags ); sqlite3BtreeEnter(pBt); pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(pBt); sqlite3BtreeLeave(pBt); @@ -104462,7 +107891,7 @@ static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){ */ static MergeEngine *vdbeMergeEngineNew(int nReader){ int N = 2; /* Smallest power of two >= nReader */ - int nByte; /* Total bytes of space to allocate */ + i64 nByte; /* Total bytes of space to allocate */ MergeEngine *pNew; /* Pointer to allocated object to return */ assert( nReader<=SORTER_MAX_MERGE_COUNT ); @@ -104552,6 +107981,12 @@ SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ assert( pCsr->eCurType==CURTYPE_SORTER ); pSorter = pCsr->uc.pSorter; if( pSorter ){ + /* Increment db->nSpill by the total number of bytes of data written + ** to temp files by this sort operation. */ + int ii; + for(ii=0; iinTask; ii++){ + db->nSpill += pSorter->aTask[ii].nSpill; + } sqlite3VdbeSorterReset(db, pSorter); sqlite3_free(pSorter->list.aMemory); sqlite3DbFree(db, pSorter); @@ -104714,6 +108149,10 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ p->u.pNext = 0; for(i=0; aSlot[i]; i++){ p = vdbeSorterMerge(pTask, p, aSlot[i]); + /* ,--Each aSlot[] holds twice as much as the previous. So we cannot use + ** | up all 64 aSlots[] with only a 64-bit address space. + ** v */ + assert( iaBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, p->iWriteOff + p->iBufStart ); + p->nPmaSpill += (p->iBufEnd - p->iBufStart); p->iBufStart = p->iBufEnd = 0; p->iWriteOff += p->nBuffer; } @@ -104789,17 +108229,20 @@ static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){ ** required. Otherwise, return an SQLite error code. ** ** Before returning, set *piEof to the offset immediately following the -** last byte written to the file. +** last byte written to the file. Also, increment (*pnSpill) by the total +** number of bytes written to the file. */ -static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){ +static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof, u64 *pnSpill){ int rc; if( p->eFWErr==0 && ALWAYS(p->aBuffer) && p->iBufEnd>p->iBufStart ){ p->eFWErr = sqlite3OsWrite(p->pFd, &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, p->iWriteOff + p->iBufStart ); + p->nPmaSpill += (p->iBufEnd - p->iBufStart); } *piEof = (p->iWriteOff + p->iBufEnd); + *pnSpill += p->nPmaSpill; sqlite3_free(p->aBuffer); rc = p->eFWErr; memset(p, 0, sizeof(PmaWriter)); @@ -104879,7 +108322,7 @@ static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){ if( pList->aMemory==0 ) sqlite3_free(p); } pList->pList = p; - rc = vdbePmaWriterFinish(&writer, &pTask->file.iEof); + rc = vdbePmaWriterFinish(&writer, &pTask->file.iEof, &pTask->nSpill); } vdbeSorterWorkDebug(pTask, "exit"); @@ -105193,7 +108636,7 @@ static int vdbeIncrPopulate(IncrMerger *pIncr){ rc = vdbeMergeEngineStep(pIncr->pMerger, &dummy); } - rc2 = vdbePmaWriterFinish(&writer, &pOut->iEof); + rc2 = vdbePmaWriterFinish(&writer, &pOut->iEof, &pTask->nSpill); if( rc==SQLITE_OK ) rc = rc2; vdbeSorterPopulateDebug(pTask, "exit"); return rc; @@ -106039,7 +109482,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare( assert( r2->nField==nKeyCol ); pKey = vdbeSorterRowkey(pSorter, &nKey); - sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, r2); + sqlite3VdbeRecordUnpack(nKey, pKey, r2); for(i=0; iaMem[i].flags & MEM_Null ){ *pRes = -1; @@ -107505,7 +110948,6 @@ static int lookupName( Schema *pSchema = 0; /* Schema of the expression */ int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */ Table *pTab = 0; /* Table holding the row */ - Column *pCol; /* A column of pTab */ ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */ const char *zCol = pRight->u.zToken; @@ -107556,7 +110998,6 @@ static int lookupName( if( pSrcList ){ for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ - u8 hCol; pTab = pItem->pSTab; assert( pTab!=0 && pTab->zName!=0 ); assert( pTab->nCol>0 || pParse->nErr ); @@ -107586,10 +111027,13 @@ static int lookupName( if( cnt>0 ){ if( pItem->fg.isUsing==0 || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0 + || pMatch==pItem ){ /* Two or more tables have the same column name which is - ** not joined by USING. This is an error. Signal as much - ** by clearing pFJMatch and letting cnt go above 1. */ + ** not joined by USING. Or, a single table has two columns + ** that match a USING term (if pMatch==pItem). These are both + ** "ambiguous column name" errors. Signal as much by clearing + ** pFJMatch and letting cnt go above 1. */ sqlite3ExprListDelete(db, pFJMatch); pFJMatch = 0; }else @@ -107644,43 +111088,38 @@ static int lookupName( sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab); } } - hCol = sqlite3StrIHash(zCol); - for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ - if( pCol->hName==hCol - && sqlite3StrICmp(pCol->zCnName, zCol)==0 - ){ - if( cnt>0 ){ - if( pItem->fg.isUsing==0 - || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0 - ){ - /* Two or more tables have the same column name which is - ** not joined by USING. This is an error. Signal as much - ** by clearing pFJMatch and letting cnt go above 1. */ - sqlite3ExprListDelete(db, pFJMatch); - pFJMatch = 0; - }else - if( (pItem->fg.jointype & JT_RIGHT)==0 ){ - /* An INNER or LEFT JOIN. Use the left-most table */ - continue; - }else - if( (pItem->fg.jointype & JT_LEFT)==0 ){ - /* A RIGHT JOIN. Use the right-most table */ - cnt = 0; - sqlite3ExprListDelete(db, pFJMatch); - pFJMatch = 0; - }else{ - /* For a FULL JOIN, we must construct a coalesce() func */ - extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); - } - } - cnt++; - pMatch = pItem; - /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ - pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; - if( pItem->fg.isNestedFrom ){ - sqlite3SrcItemColumnUsed(pItem, j); + j = sqlite3ColumnIndex(pTab, zCol); + if( j>=0 ){ + if( cnt>0 ){ + if( pItem->fg.isUsing==0 + || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0 + ){ + /* Two or more tables have the same column name which is + ** not joined by USING. This is an error. Signal as much + ** by clearing pFJMatch and letting cnt go above 1. */ + sqlite3ExprListDelete(db, pFJMatch); + pFJMatch = 0; + }else + if( (pItem->fg.jointype & JT_RIGHT)==0 ){ + /* An INNER or LEFT JOIN. Use the left-most table */ + continue; + }else + if( (pItem->fg.jointype & JT_LEFT)==0 ){ + /* A RIGHT JOIN. Use the right-most table */ + cnt = 0; + sqlite3ExprListDelete(db, pFJMatch); + pFJMatch = 0; + }else{ + /* For a FULL JOIN, we must construct a coalesce() func */ + extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn); } - break; + } + cnt++; + pMatch = pItem; + /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ + pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; + if( pItem->fg.isNestedFrom ){ + sqlite3SrcItemColumnUsed(pItem, j); } } if( 0==cnt && VisibleRowid(pTab) ){ @@ -107770,23 +111209,18 @@ static int lookupName( if( pTab ){ int iCol; - u8 hCol = sqlite3StrIHash(zCol); pSchema = pTab->pSchema; cntTab++; - for(iCol=0, pCol=pTab->aCol; iColnCol; iCol++, pCol++){ - if( pCol->hName==hCol - && sqlite3StrICmp(pCol->zCnName, zCol)==0 - ){ - if( iCol==pTab->iPKey ){ - iCol = -1; - } - break; + iCol = sqlite3ColumnIndex(pTab, zCol); + if( iCol>=0 ){ + if( pTab->iPKey==iCol ) iCol = -1; + }else{ + if( sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){ + iCol = -1; + }else{ + iCol = pTab->nCol; } } - if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){ - /* IMP: R-51414-32910 */ - iCol = -1; - } if( iColnCol ){ cnt++; pMatch = 0; @@ -107994,6 +111428,7 @@ static int lookupName( pExpr->op = TK_FUNCTION; pExpr->u.zToken = "coalesce"; pExpr->x.pList = pFJMatch; + pExpr->affExpr = SQLITE_AFF_DEFER; cnt = 1; goto lookupname_end; }else{ @@ -108149,19 +111584,48 @@ static void notValidImpl( /* ** Expression p should encode a floating point value between 1.0 and 0.0. -** Return 1024 times this value. Or return -1 if p is not a floating point -** value between 1.0 and 0.0. +** Return 134,217,728 (2^27) times this value. Or return -1 if p is not +** a floating point value between 1.0 and 0.0. */ static int exprProbability(Expr *p){ double r = -1.0; if( p->op!=TK_FLOAT ) return -1; assert( !ExprHasProperty(p, EP_IntValue) ); - sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8); + sqlite3AtoF(p->u.zToken, &r); assert( r>=0.0 ); if( r>1.0 ) return -1; return (int)(r*134217728.0); } +/* +** Set the EP_SubtArg property on every expression inside of +** pList. If any subexpression is actually a subquery, then +** also set the EP_SubtArg property on the first result-set +** column of that subquery. +*/ +static SQLITE_NOINLINE void resolveSetExprSubtypeArg(ExprList *pList){ + int nn, ii; + nn = pList ? pList->nExpr : 0; + for(ii=0; iia[ii].pExpr; + while( 1 /*exit-by-break*/ ){ + ExprSetProperty(pExpr, EP_SubtArg); + if( pExpr->op==TK_SELECT ){ + assert( ExprUseXSelect(pExpr) ); + assert( pExpr->x.pSelect!=0 ); + resolveSetExprSubtypeArg(pExpr->x.pSelect->pEList); + break; + } + if( pExpr->op==TK_UPLUS ){ + pExpr = pExpr->pLeft; + assert( pExpr!=0 ); + }else{ + break; + } + } + } +} + /* ** This routine is callback for sqlite3WalkExpr(). ** @@ -108406,10 +111870,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ if( (pDef->funcFlags & SQLITE_SUBTYPE) || ExprHasProperty(pExpr, EP_SubtArg) ){ - int ii; - for(ii=0; iia[ii].pExpr, EP_SubtArg); - } + resolveSetExprSubtypeArg(pList); } if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ @@ -108425,13 +111886,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ ** sqlite_version() that might change over time cannot be used ** in an index or generated column. Curiously, they can be used ** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all - ** all this. */ + ** allow this. */ sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr|NC_PartIdx|NC_GenCol, 0, pExpr); }else{ assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */ pExpr->op2 = pNC->ncFlags & NC_SelfRef; - if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); } if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && pParse->nested==0 @@ -108447,6 +111907,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 && !IN_RENAME_OBJECT ){ + if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); sqlite3ExprFunctionUsable(pParse, pExpr, pDef); } } @@ -108581,11 +112042,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ return WRC_Prune; } #ifndef SQLITE_OMIT_SUBQUERY + case TK_EXISTS: case TK_SELECT: - case TK_EXISTS: testcase( pExpr->op==TK_EXISTS ); #endif case TK_IN: { testcase( pExpr->op==TK_IN ); + testcase( pExpr->op==TK_EXISTS ); + testcase( pExpr->op==TK_SELECT ); if( ExprUseXSelect(pExpr) ){ int nRef = pNC->nRef; testcase( pNC->ncFlags & NC_IsCheck ); @@ -108593,6 +112056,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ testcase( pNC->ncFlags & NC_IdxExpr ); testcase( pNC->ncFlags & NC_GenCol ); assert( pExpr->x.pSelect ); + if( pExpr->op==TK_EXISTS ) pParse->bHasExists = 1; if( pNC->ncFlags & NC_SelfRef ){ notValidImpl(pParse, pNC, "subqueries", pExpr, pExpr); }else{ @@ -108873,10 +112337,8 @@ static int resolveCompoundOrderBy( /* Convert the ORDER BY term into an integer column number iCol, ** taking care to preserve the COLLATE clause if it exists. */ if( !IN_RENAME_OBJECT ){ - Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); + Expr *pNew = sqlite3ExprInt32(db, iCol); if( pNew==0 ) return 1; - pNew->flags |= EP_IntValue; - pNew->u.iValue = iCol; if( pItem->pExpr==pE ){ pItem->pExpr = pNew; }else{ @@ -109230,10 +112692,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ } #endif - /* The ORDER BY and GROUP BY clauses may not refer to terms in - ** outer queries - */ - sNC.pNext = 0; sNC.ncFlags |= NC_AllowAgg|NC_AllowWin; /* If this is a converted compound query, move the ORDER BY clause from @@ -109296,6 +112754,14 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ return WRC_Abort; } + /* If the SELECT statement contains ON clauses that were moved into + ** the WHERE clause, go through and verify that none of the terms + ** in the ON clauses reference tables to the right of the ON clause. */ + if( (p->selFlags & SF_OnToWhere) ){ + sqlite3SelectCheckOnClauses(pParse, p); + if( pParse->nErr ) return WRC_Abort; + } + /* Advance to the next term of the compound */ p = p->pPrior; @@ -109500,20 +112966,25 @@ SQLITE_PRIVATE int sqlite3ResolveSelfReference( Expr *pExpr, /* Expression to resolve. May be NULL. */ ExprList *pList /* Expression list to resolve. May be NULL. */ ){ - SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ + SrcList *pSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ int rc; + union { + SrcList sSrc; + u8 srcSpace[SZ_SRCLIST_1]; /* Memory space for the fake SrcList */ + } uSrc; assert( type==0 || pTab!=0 ); assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr || type==NC_GenCol || pTab==0 ); memset(&sNC, 0, sizeof(sNC)); - memset(&sSrc, 0, sizeof(sSrc)); + memset(&uSrc, 0, sizeof(uSrc)); + pSrc = &uSrc.sSrc; if( pTab ){ - sSrc.nSrc = 1; - sSrc.a[0].zName = pTab->zName; - sSrc.a[0].pSTab = pTab; - sSrc.a[0].iCursor = -1; + pSrc->nSrc = 1; + pSrc->a[0].zName = pTab->zName; + pSrc->a[0].pSTab = pTab; + pSrc->a[0].iCursor = -1; if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){ /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP ** schema elements */ @@ -109521,7 +112992,7 @@ SQLITE_PRIVATE int sqlite3ResolveSelfReference( } } sNC.pParse = pParse; - sNC.pSrcList = &sSrc; + sNC.pSrcList = pSrc; sNC.ncFlags = type | NC_IsDDL; if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc; if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList); @@ -109605,7 +113076,9 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){ pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr ); } - if( op==TK_VECTOR ){ + if( op==TK_VECTOR + || (op==TK_FUNCTION && pExpr->affExpr==SQLITE_AFF_DEFER) + ){ assert( ExprUseXList(pExpr) ); return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr); } @@ -109798,7 +113271,9 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){ p = p->pLeft; continue; } - if( op==TK_VECTOR ){ + if( op==TK_VECTOR + || (op==TK_FUNCTION && p->affExpr==SQLITE_AFF_DEFER) + ){ assert( ExprUseXList(p) ); p = p->x.pList->a[0].pExpr; continue; @@ -110011,7 +113486,7 @@ static int codeCompare( p5 = binaryCompareP5(pLeft, pRight, jumpIfNull); addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1, (void*)p4, P4_COLLSEQ); - sqlite3VdbeChangeP5(pParse->pVdbe, (u8)p5); + sqlite3VdbeChangeP5(pParse->pVdbe, (u16)p5); return addr; } @@ -110463,34 +113938,22 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( int dequote /* True to dequote */ ){ Expr *pNew; - int nExtra = 0; - int iValue = 0; + int nExtra = pToken ? pToken->n+1 : 0; assert( db!=0 ); - if( pToken ){ - if( op!=TK_INTEGER || pToken->z==0 - || sqlite3GetInt32(pToken->z, &iValue)==0 ){ - nExtra = pToken->n+1; /* tag-20240227-a */ - assert( iValue>=0 ); - } - } pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra); if( pNew ){ memset(pNew, 0, sizeof(Expr)); pNew->op = (u8)op; pNew->iAgg = -1; - if( pToken ){ - if( nExtra==0 ){ - pNew->flags |= EP_IntValue|EP_Leaf|(iValue?EP_IsTrue:EP_IsFalse); - pNew->u.iValue = iValue; - }else{ - pNew->u.zToken = (char*)&pNew[1]; - assert( pToken->z!=0 || pToken->n==0 ); - if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n); - pNew->u.zToken[pToken->n] = 0; - if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){ - sqlite3DequoteExpr(pNew); - } + if( nExtra ){ + assert( pToken!=0 ); + pNew->u.zToken = (char*)&pNew[1]; + assert( pToken->z!=0 || pToken->n==0 ); + if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n); + pNew->u.zToken[pToken->n] = 0; + if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){ + sqlite3DequoteExpr(pNew); } } #if SQLITE_MAX_EXPR_DEPTH>0 @@ -110515,6 +113978,24 @@ SQLITE_PRIVATE Expr *sqlite3Expr( return sqlite3ExprAlloc(db, op, &x, 0); } +/* +** Allocate an expression for a 32-bit signed integer literal. +*/ +SQLITE_PRIVATE Expr *sqlite3ExprInt32(sqlite3 *db, int iVal){ + Expr *pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)); + if( pNew ){ + memset(pNew, 0, sizeof(Expr)); + pNew->op = TK_INTEGER; + pNew->iAgg = -1; + pNew->flags = EP_IntValue|EP_Leaf|(iVal?EP_IsTrue:EP_IsFalse); + pNew->u.iValue = iVal; +#if SQLITE_MAX_EXPR_DEPTH>0 + pNew->nHeight = 1; +#endif + } + return pNew; +} + /* ** Attach subtrees pLeft and pRight to the Expr node pRoot. ** @@ -110672,12 +114153,12 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ return pLeft; }else{ u32 f = pLeft->flags | pRight->flags; - if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse))==EP_IsFalse + if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse|EP_HasFunc))==EP_IsFalse && !IN_RENAME_OBJECT ){ sqlite3ExprDeferredDelete(pParse, pLeft); sqlite3ExprDeferredDelete(pParse, pRight); - return sqlite3Expr(db, TK_INTEGER, "0"); + return sqlite3ExprInt32(db, 0); }else{ return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); } @@ -110767,6 +114248,11 @@ SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy( sqlite3ExprListDelete(db, pOrderBy); return; } + if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ + sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause"); + sqlite3ExprListDelete(db, pOrderBy); + return; + } pOB = sqlite3ExprAlloc(db, TK_ORDER, 0, 0); if( pOB==0 ){ @@ -110797,7 +114283,9 @@ SQLITE_PRIVATE void sqlite3ExprFunctionUsable( ){ assert( !IN_RENAME_OBJECT ); assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 ); - if( ExprHasProperty(pExpr, EP_FromDDL) ){ + if( ExprHasProperty(pExpr, EP_FromDDL) + || pParse->prepFlags & SQLITE_PREPARE_FROM_DDL + ){ if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0 || (pParse->db->flags & SQLITE_TrustedSchema)==0 ){ @@ -111270,7 +114758,7 @@ static Expr *exprDup( SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){ With *pRet = 0; if( p ){ - sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); + sqlite3_int64 nByte = SZ_WITH(p->nCte); pRet = sqlite3DbMallocZero(db, nByte); if( pRet ){ int i; @@ -111381,7 +114869,6 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int } pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName); pItem->fg = pOldItem->fg; - pItem->fg.done = 0; pItem->u = pOldItem->u; } return pNew; @@ -111398,11 +114885,9 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){ SrcList *pNew; int i; - int nByte; assert( db!=0 ); if( p==0 ) return 0; - nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0); - pNew = sqlite3DbMallocRawNN(db, nByte ); + pNew = sqlite3DbMallocRawNN(db, SZ_SRCLIST(p->nSrc) ); if( pNew==0 ) return 0; pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; inSrc; i++){ @@ -111464,16 +114949,13 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){ int i; assert( db!=0 ); if( p==0 ) return 0; - assert( p->eU4!=EU4_EXPR ); - pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) ); + pNew = sqlite3DbMallocRawNN(db, SZ_IDLIST(p->nId)); if( pNew==0 ) return 0; pNew->nId = p->nId; - pNew->eU4 = p->eU4; for(i=0; inId; i++){ struct IdList_item *pNewItem = &pNew->a[i]; const struct IdList_item *pOldItem = &p->a[i]; pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); - pNewItem->u4 = pOldItem->u4; } return pNew; } @@ -111499,9 +114981,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int fla pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); pNew->iLimit = 0; pNew->iOffset = 0; - pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; - pNew->addrOpenEphm[0] = -1; - pNew->addrOpenEphm[1] = -1; + pNew->selFlags = p->selFlags; pNew->nSelectRow = p->nSelectRow; pNew->pWith = sqlite3WithDup(db, p->pWith); #ifndef SQLITE_OMIT_WINDOWFUNC @@ -111551,7 +115031,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew( struct ExprList_item *pItem; ExprList *pList; - pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)+sizeof(pList->a[0])*4 ); + pList = sqlite3DbMallocRawNN(db, SZ_EXPRLIST(4)); if( pList==0 ){ sqlite3ExprDelete(db, pExpr); return 0; @@ -111571,8 +115051,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendGrow( struct ExprList_item *pItem; ExprList *pNew; pList->nAlloc *= 2; - pNew = sqlite3DbRealloc(db, pList, - sizeof(*pList)+(pList->nAlloc-1)*sizeof(pList->a[0])); + pNew = sqlite3DbRealloc(db, pList, SZ_EXPRLIST(pList->nAlloc)); if( pNew==0 ){ sqlite3ExprListDelete(db, pList); sqlite3ExprDelete(db, pExpr); @@ -111908,6 +115387,85 @@ SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){ return pExpr; } +/* +** Return true if it might be advantageous to compute the right operand +** of expression pExpr first, before the left operand. +** +** Normally the left operand is computed before the right operand. But if +** the left operand contains a subquery and the right does not, then it +** might be more efficient to compute the right operand first. +*/ +static int exprEvalRhsFirst(Expr *pExpr){ + if( ExprHasProperty(pExpr->pLeft, EP_Subquery) + && !ExprHasProperty(pExpr->pRight, EP_Subquery) + ){ + return 1; + }else{ + return 0; + } +} + +/* +** Compute the two operands of a binary operator. +** +** If either operand contains a subquery, then the code strives to +** compute the operand containing the subquery second. If the other +** operand evalutes to NULL, then a jump is made. The address of the +** IsNull operand that does this jump is returned. The caller can use +** this to optimize the computation so as to avoid doing the potentially +** expensive subquery. +** +** If no optimization opportunities exist, return 0. +*/ +static int exprComputeOperands( + Parse *pParse, /* Parsing context */ + Expr *pExpr, /* The comparison expression */ + int *pR1, /* OUT: Register holding the left operand */ + int *pR2, /* OUT: Register holding the right operand */ + int *pFree1, /* OUT: Temp register to free if not zero */ + int *pFree2 /* OUT: Another temp register to free if not zero */ +){ + int addrIsNull; + int r1, r2; + Vdbe *v = pParse->pVdbe; + + assert( v!=0 ); + /* + ** If the left operand contains a (possibly expensive) subquery and the + ** right operand does not and the right operation might be NULL, + ** then compute the right operand first and do an IsNull jump if the + ** right operand evalutes to NULL. + */ + if( exprEvalRhsFirst(pExpr) && sqlite3ExprCanBeNull(pExpr->pRight) ){ + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, pFree2); + addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, r2); + VdbeComment((v, "skip left operand")); + VdbeCoverage(v); + }else{ + r2 = 0; /* Silence a false-positive uninit-var warning in MSVC */ + addrIsNull = 0; + } + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, pFree1); + if( addrIsNull==0 ){ + /* + ** If the right operand contains a subquery and the left operand does not + ** and the left operand might be NULL, then do an IsNull check + ** check on the left operand before computing the right operand. + */ + if( ExprHasProperty(pExpr->pRight, EP_Subquery) + && sqlite3ExprCanBeNull(pExpr->pLeft) + ){ + addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, r1); + VdbeComment((v, "skip right operand")); + VdbeCoverage(v); + } + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, pFree2); + } + *pR1 = r1; + *pR2 = r2; + return addrIsNull; +} + /* ** pExpr is a TK_FUNCTION node. Try to determine whether or not the ** function is a constant function. A function is constant if all of @@ -112075,7 +115633,7 @@ static int exprIsConst(Parse *pParse, Expr *p, int initFlag){ /* ** Walk an expression tree. Return non-zero if the expression is constant -** and 0 if it involves variables or function calls. +** or return zero if the expression involves variables or function calls. ** ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is @@ -112178,7 +115736,7 @@ static int sqlite3ExprIsTableConstant(Expr *p, int iCur, int bAllowSubq){ ** (4a) pExpr must come from an ON clause.. ** (4b) and specifically the ON clause associated with the LEFT JOIN. ** -** (5) If pSrc is not the right operand of a LEFT JOIN or the left +** (5) If pSrc is the right operand of a LEFT JOIN or the left ** operand of a RIGHT JOIN, then pExpr must be from the WHERE ** clause, not an ON clause. ** @@ -112501,13 +116059,7 @@ SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab){ int ii; assert( VisibleRowid(pTab) ); for(ii=0; iinCol; iCol++){ - if( sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break; - } - if( iCol==pTab->nCol ){ - return azOpt[ii]; - } + if( sqlite3ColumnIndex(pTab, azOpt[ii])<0 ) return azOpt[ii]; } return 0; } @@ -112817,6 +116369,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( if( aiMap ) aiMap[i] = j; } + assert( nExpr>0 && nExprnQueryLoop; int rMayHaveNull = 0; + int bloomOk = (inFlags & IN_INDEX_MEMBERSHIP)!=0; eType = IN_INDEX_EPH; if( inFlags & IN_INDEX_LOOP ){ pParse->nQueryLoop = 0; @@ -112877,7 +116431,13 @@ SQLITE_PRIVATE int sqlite3FindInIndex( *prRhsHasNull = rMayHaveNull = ++pParse->nMem; } assert( pX->op==TK_IN ); - sqlite3CodeRhsOfIN(pParse, pX, iTab); + if( !bloomOk + && ExprUseXSelect(pX) + && (pX->x.pSelect->selFlags & SF_ClonedRhsIn)!=0 + ){ + bloomOk = 1; + } + sqlite3CodeRhsOfIN(pParse, pX, iTab, bloomOk); if( rMayHaveNull ){ sqlite3SetHasNullFlag(v, iTab, rMayHaveNull); } @@ -112910,7 +116470,7 @@ static char *exprINAffinity(Parse *pParse, const Expr *pExpr){ char *zRet; assert( pExpr->op==TK_IN ); - zRet = sqlite3DbMallocRaw(pParse->db, nVal+1); + zRet = sqlite3DbMallocRaw(pParse->db, 1+(i64)nVal); if( zRet ){ int i; for(i=0; iopcode==OP_BeginSubrtn ); pSig = pOp->p4.pSubrtnSig; assert( pSig!=0 ); + if( !pSig->bComplete ) continue; if( pNewSig->selId!=pSig->selId ) continue; if( strcmp(pNewSig->zAff,pSig->zAff)!=0 ) continue; pExpr->y.sub.iAddr = pSig->iAddr; @@ -113034,7 +116595,8 @@ static int findCompatibleInRhsSubrtn( SQLITE_PRIVATE void sqlite3CodeRhsOfIN( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The IN operator */ - int iTab /* Use this cursor number */ + int iTab, /* Use this cursor number */ + int allowBloom /* True to allow the use of a Bloom filter */ ){ int addrOnce = 0; /* Address of the OP_Once instruction at top */ int addr; /* Address of OP_OpenEphemeral instruction */ @@ -113042,6 +116604,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( KeyInfo *pKeyInfo = 0; /* Key information */ int nVal; /* Size of vector pLeft */ Vdbe *v; /* The prepared statement under construction */ + SubrtnSig *pSig = 0; /* Signature for this subroutine */ v = pParse->pVdbe; assert( v!=0 ); @@ -113062,7 +116625,6 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( ** Compute a signature for the RHS of the IN operator to facility ** finding and reusing prior instances of the same IN operator. */ - SubrtnSig *pSig = 0; assert( !ExprUseXSelect(pExpr) || pExpr->x.pSelect!=0 ); if( ExprUseXSelect(pExpr) && (pExpr->x.pSelect->selFlags & SF_All)==0 ){ pSig = sqlite3DbMallocRawNN(pParse->db, sizeof(pSig[0])); @@ -113105,6 +116667,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( pExpr->y.sub.iAddr = sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1; if( pSig ){ + pSig->bComplete = 0; pSig->iAddr = pExpr->y.sub.iAddr; pSig->regReturn = pExpr->y.sub.regReturn; pSig->iTable = iTab; @@ -113155,7 +116718,10 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( sqlite3SelectDestInit(&dest, SRT_Set, iTab); dest.zAffSdst = exprINAffinity(pParse, pExpr); pSelect->iLimit = 0; - if( addrOnce && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){ + if( addrOnce + && allowBloom + && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) + ){ int regBloom = ++pParse->nMem; addrBloom = sqlite3VdbeAddOp2(v, OP_Blob, 10000, regBloom); VdbeComment((v, "Bloom filter")); @@ -113168,11 +116734,12 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( sqlite3SelectDelete(pParse->db, pCopy); sqlite3DbFree(pParse->db, dest.zAffSdst); if( addrBloom ){ + /* Remember that location of the Bloom filter in the P3 operand + ** of the OP_Once that began this subroutine. tag-202407032019 */ sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; if( dest.iSDParm2==0 ){ - sqlite3VdbeChangeToNoop(v, addrBloom); - }else{ - sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; + /* If the Bloom filter won't actually be used, keep it small */ + sqlite3VdbeGetOp(v, addrBloom)->p1 = 10; } } if( rc ){ @@ -113240,6 +116807,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } + if( pSig ) pSig->bComplete = 1; if( pKeyInfo ){ sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); } @@ -113343,9 +116911,22 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ pParse->nMem += nReg; if( pExpr->op==TK_SELECT ){ dest.eDest = SRT_Mem; - dest.iSdst = dest.iSDParm; + if( (pSel->selFlags&SF_Distinct) && pSel->pLimit && pSel->pLimit->pRight ){ + /* If there is both a DISTINCT and an OFFSET clause, then allocate + ** a separate dest.iSdst array for sqlite3Select() and other + ** routines to populate. In this case results will be copied over + ** into the dest.iSDParm array only after OFFSET processing. This + ** ensures that in the case where OFFSET excludes all rows, the + ** dest.iSDParm array is not left populated with the contents of the + ** last row visited - it should be all NULLs if all rows were + ** excluded by OFFSET. */ + dest.iSdst = pParse->nMem+1; + pParse->nMem += nReg; + }else{ + dest.iSdst = dest.iSDParm; + } dest.nSdst = nReg; - sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1); + sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, pParse->nMem); VdbeComment((v, "Init subquery result")); }else{ dest.eDest = SRT_Exists; @@ -113353,20 +116934,26 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ VdbeComment((v, "Init EXISTS result")); } if( pSel->pLimit ){ - /* The subquery already has a limit. If the pre-existing limit is X - ** then make the new limit X<>0 so that the new limit is either 1 or 0 */ - sqlite3 *db = pParse->db; - pLimit = sqlite3Expr(db, TK_INTEGER, "0"); - if( pLimit ){ - pLimit->affExpr = SQLITE_AFF_NUMERIC; - pLimit = sqlite3PExpr(pParse, TK_NE, - sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit); + /* The subquery already has a limit. If the pre-existing limit X is + ** not already integer value 1 or 0, then make the new limit X<>0 so that + ** the new limit is either 1 or 0 */ + Expr *pLeft = pSel->pLimit->pLeft; + if( ExprHasProperty(pLeft, EP_IntValue)==0 + || (pLeft->u.iValue!=1 && pLeft->u.iValue!=0) + ){ + sqlite3 *db = pParse->db; + pLimit = sqlite3ExprInt32(db, 0); + if( pLimit ){ + pLimit->affExpr = SQLITE_AFF_NUMERIC; + pLimit = sqlite3PExpr(pParse, TK_NE, + sqlite3ExprDup(db, pLeft, 0), pLimit); + } + sqlite3ExprDeferredDelete(pParse, pLeft); + pSel->pLimit->pLeft = pLimit; } - sqlite3ExprDeferredDelete(pParse, pSel->pLimit->pLeft); - pSel->pLimit->pLeft = pLimit; }else{ /* If there is no pre-existing limit add a limit of 1 */ - pLimit = sqlite3Expr(pParse->db, TK_INTEGER, "1"); + pLimit = sqlite3ExprInt32(pParse->db, 1); pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0); } pSel->iLimit = 0; @@ -113451,7 +117038,6 @@ static void sqlite3ExprCodeIN( int rRhsHasNull = 0; /* Register that is true if RHS contains NULL values */ int eType; /* Type of the RHS */ int rLhs; /* Register(s) holding the LHS values */ - int rLhsOrig; /* LHS values prior to reordering by aiMap[] */ Vdbe *v; /* Statement under construction */ int *aiMap = 0; /* Map from vector field to index column */ char *zAff = 0; /* Affinity string for comparisons */ @@ -113514,19 +117100,8 @@ static void sqlite3ExprCodeIN( ** by code generated below. */ assert( pParse->okConstFactor==okConstFactor ); pParse->okConstFactor = 0; - rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy); + rLhs = exprCodeVector(pParse, pLeft, &iDummy); pParse->okConstFactor = okConstFactor; - for(i=0; ix.pList; pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); @@ -113582,6 +117158,26 @@ static void sqlite3ExprCodeIN( goto sqlite3ExprCodeIN_finished; } + if( eType!=IN_INDEX_ROWID ){ + /* If this IN operator will use an index, then the order of columns in the + ** vector might be different from the order in the index. In that case, + ** we need to reorder the LHS values to be in index order. Run Affinity + ** before reordering the columns, so that the affinity is correct. + */ + sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); + for(i=0; ipLeft, i); if( pParse->nErr ) goto sqlite3ExprCodeIN_oom_error; if( sqlite3ExprCanBeNull(p) ){ - sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2); + sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+aiMap[i], destStep2); VdbeCoverage(v); } } @@ -113608,18 +117204,19 @@ static void sqlite3ExprCodeIN( /* In this case, the RHS is the ROWID of table b-tree and so we also ** know that the RHS is non-NULL. Hence, we combine steps 3 and 4 ** into a single opcode. */ + assert( nVector==1 ); sqlite3VdbeAddOp3(v, OP_SeekRowid, iTab, destIfFalse, rLhs); VdbeCoverage(v); addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */ }else{ - sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); if( destIfFalse==destIfNull ){ /* Combine Step 3 and Step 5 into a single opcode */ if( ExprHasProperty(pExpr, EP_Subrtn) ){ const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr); assert( pOp->opcode==OP_Once || pParse->nErr ); - if( pOp->opcode==OP_Once && pOp->p3>0 ){ - assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ); + if( pOp->p3>0 ){ /* tag-202407032019 */ + assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) + || pParse->nErr ); sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse, rLhs, nVector); VdbeCoverage(v); } @@ -113668,9 +117265,18 @@ static void sqlite3ExprCodeIN( CollSeq *pColl; int r3 = sqlite3GetTempReg(pParse); p = sqlite3VectorFieldSubexpr(pLeft, i); - pColl = sqlite3ExprCollSeq(pParse, p); - sqlite3VdbeAddOp3(v, OP_Column, iTab, i, r3); - sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3, + if( ExprUseXSelect(pExpr) ){ + Expr *pRhs = pExpr->x.pSelect->pEList->a[i].pExpr; + pColl = sqlite3BinaryCompareCollSeq(pParse, p, pRhs); + }else{ + /* If the RHS of the IN(...) expression are scalar expressions, do + ** not consider their collation sequences. The documentation says + ** "The collating sequence used for expressions of the form "x IN (y, z, + ** ...)" is the collating sequence of x.". */ + pColl = sqlite3ExprCollSeq(pParse, p); + } + sqlite3VdbeAddOp3(v, OP_Column, iTab, aiMap[i], r3); + sqlite3VdbeAddOp4(v, OP_Ne, rLhs+aiMap[i], destNotNull, r3, (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, r3); @@ -113690,7 +117296,6 @@ static void sqlite3ExprCodeIN( sqlite3VdbeJumpHere(v, addrTruthOp); sqlite3ExprCodeIN_finished: - if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs); VdbeComment((v, "end IN expr")); sqlite3ExprCodeIN_oom_error: sqlite3DbFree(pParse->db, aiMap); @@ -113710,7 +117315,7 @@ static void sqlite3ExprCodeIN( static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){ if( ALWAYS(z!=0) ){ double value; - sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); + sqlite3AtoF(z, &value); assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */ if( negateFlag ) value = -value; sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL); @@ -113805,7 +117410,12 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn( iAddr = 0; } sqlite3ExprCodeCopy(pParse, sqlite3ColumnExpr(pTab,pCol), regOut); - if( pCol->affinity>=SQLITE_AFF_TEXT ){ + if( (pCol->colFlags & COLFLAG_VIRTUAL)!=0 + && (pTab->tabFlags & TF_Strict)!=0 + ){ + int p3 = 2+(int)(pCol - pTab->aCol); + sqlite3VdbeAddOp4(v, OP_TypeCheck, regOut, 1, p3, (char*)pTab, P4_TABLE); + }else if( pCol->affinity>=SQLITE_AFF_TEXT ){ sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1); } if( iAddr ) sqlite3VdbeJumpHere(v, iAddr); @@ -114087,26 +117697,37 @@ static int exprCodeInlineFunction( } /* -** Expression Node callback for sqlite3ExprCanReturnSubtype(). +** Expression Node callback for sqlite3ExprCanReturnSubtype(). If +** pExpr is able to return a subtype, set pWalker->eCode and abort +** the search. If pExpr can never return a subtype, prune search. +** +** The only expressions that can return a subtype are: ** -** Only a function call is able to return a subtype. So if the node -** is not a function call, return WRC_Prune immediately. +** 1. A function +** 2. The no-op "+" operator +** 3. A CASE...END expression +** 4. A CAST() expression +** 5. A "expr COLLATE colseq" expression. ** -** A function call is able to return a subtype if it has the -** SQLITE_RESULT_SUBTYPE property. +** For any other kind of expression, prune the search. ** -** Assume that every function is able to pass-through a subtype from -** one of its argument (using sqlite3_result_value()). Most functions -** are not this way, but we don't have a mechanism to distinguish those -** that are from those that are not, so assume they all work this way. -** That means that if one of its arguments is another function and that -** other function is able to return a subtype, then this function is -** able to return a subtype. +** For case 1, the expression can yield a subtype if the function has +** the SQLITE_RESULT_SUBTYPE property. Functions can also return +** a subtype (via sqlite3_result_value()) if any of the arguments can +** return a subtype. +** +** In all cases 1 through 5, the expression might also return a subtype +** if any operand can return a subtype. */ static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){ int n; FuncDef *pDef; sqlite3 *db; + if( pExpr->op==TK_CASE || pExpr->op==TK_UPLUS + || pExpr->op==TK_COLLATE || pExpr->op==TK_CAST + ){ + return WRC_Continue; + } if( pExpr->op!=TK_FUNCTION ){ return WRC_Prune; } @@ -114116,7 +117737,7 @@ static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){ pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ pWalker->eCode = 1; - return WRC_Prune; + return WRC_Abort; } return WRC_Continue; } @@ -114210,7 +117831,7 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup( /* -** Expresion pExpr is guaranteed to be a TK_COLUMN or equivalent. This +** Expression pExpr is guaranteed to be a TK_COLUMN or equivalent. This ** function checks the Parse.pIdxPartExpr list to see if this column ** can be replaced with a constant value. If so, it generates code to ** put the constant value in a register (ideally, but not necessarily, @@ -114243,6 +117864,80 @@ static int exprPartidxExprLookup(Parse *pParse, Expr *pExpr, int iTarget){ return 0; } +/* +** Generate code that evaluates an AND or OR operator leaving a +** boolean result in a register. pExpr is the AND/OR expression. +** Store the result in the "target" register. Use short-circuit +** evaluation to avoid computing both operands, if possible. +** +** The code generated might require the use of a temporary register. +** If it does, then write the number of that temporary register +** into *pTmpReg. If not, leave *pTmpReg unchanged. +*/ +static SQLITE_NOINLINE int exprCodeTargetAndOr( + Parse *pParse, /* Parsing context */ + Expr *pExpr, /* AND or OR expression to be coded */ + int target, /* Put result in this register, guaranteed */ + int *pTmpReg /* Write a temporary register here */ +){ + int op; /* The opcode. TK_AND or TK_OR */ + int skipOp; /* Opcode for the branch that skips one operand */ + int addrSkip; /* Branch instruction that skips one of the operands */ + int regSS = 0; /* Register holding computed operand when other omitted */ + int r1, r2; /* Registers for left and right operands, respectively */ + Expr *pAlt; /* Alternative, simplified expression */ + Vdbe *v; /* statement being coded */ + + assert( pExpr!=0 ); + op = pExpr->op; + assert( op==TK_AND || op==TK_OR ); + assert( TK_AND==OP_And ); testcase( op==TK_AND ); + assert( TK_OR==OP_Or ); testcase( op==TK_OR ); + assert( pParse->pVdbe!=0 ); + v = pParse->pVdbe; + pAlt = sqlite3ExprSimplifiedAndOr(pExpr); + if( pAlt!=pExpr ){ + r1 = sqlite3ExprCodeTarget(pParse, pAlt, target); + sqlite3VdbeAddOp3(v, OP_And, r1, r1, target); + return target; + } + skipOp = op==TK_AND ? OP_IfNot : OP_If; + if( exprEvalRhsFirst(pExpr) ){ + /* Compute the right operand first. Skip the computation of the left + ** operand if the right operand fully determines the result */ + r2 = regSS = sqlite3ExprCodeTarget(pParse, pExpr->pRight, target); + addrSkip = sqlite3VdbeAddOp1(v, skipOp, r2); + VdbeComment((v, "skip left operand")); + VdbeCoverage(v); + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, pTmpReg); + }else{ + /* Compute the left operand first */ + r1 = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + if( ExprHasProperty(pExpr->pRight, EP_Subquery) ){ + /* Skip over the computation of the right operand if the right + ** operand is a subquery and the left operand completely determines + ** the result */ + regSS = r1; + addrSkip = sqlite3VdbeAddOp1(v, skipOp, r1); + VdbeComment((v, "skip right operand")); + VdbeCoverage(v); + }else{ + addrSkip = regSS = 0; + } + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, pTmpReg); + } + sqlite3VdbeAddOp3(v, op, r2, r1, target); + testcase( (*pTmpReg)==0 ); + if( addrSkip ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2); + sqlite3VdbeJumpHere(v, addrSkip); + sqlite3VdbeAddOp3(v, OP_Or, regSS, regSS, target); + VdbeComment((v, "short-circut value")); + } + return target; +} + + /* ** Generate code into the current Vdbe to evaluate the given @@ -114434,6 +118129,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) sqlite3VdbeLoadString(v, target, pExpr->u.zToken); return target; } + case TK_NULLS: { + /* Set a range of registers to NULL. pExpr->y.nReg registers starting + ** with target */ + sqlite3VdbeAddOp3(v, OP_Null, 0, target, target + pExpr->y.nReg - 1); + return target; + } default: { /* Make NULL the default case so that if a bug causes an illegal ** Expr node to be passed into this function, it will be handled @@ -114484,7 +118185,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) case TK_ISNOT: op = (op==TK_IS) ? TK_EQ : TK_NE; p5 = SQLITE_NULLEQ; - /* fall-through */ + /* no break */ deliberate_fall_through case TK_LT: case TK_LE: case TK_GT: @@ -114492,11 +118193,17 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) case TK_NE: case TK_EQ: { Expr *pLeft = pExpr->pLeft; + int addrIsNull = 0; if( sqlite3ExprIsVector(pLeft) ){ codeVectorCompare(pParse, pExpr, target, op, p5); }else{ - r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + if( ExprHasProperty(pExpr, EP_Subquery) && p5!=SQLITE_NULLEQ ){ + addrIsNull = exprComputeOperands(pParse, pExpr, + &r1, &r2, ®Free1, ®Free2); + }else{ + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + } sqlite3VdbeAddOp2(v, OP_Integer, 1, inReg); codeCompare(pParse, pLeft, pExpr->pRight, op, r1, r2, sqlite3VdbeCurrentAddr(v)+2, p5, @@ -114511,6 +118218,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) sqlite3VdbeAddOp2(v, OP_Integer, 0, inReg); }else{ sqlite3VdbeAddOp3(v, OP_ZeroOrNull, r1, inReg, r2); + if( addrIsNull ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2); + sqlite3VdbeJumpHere(v, addrIsNull); + sqlite3VdbeAddOp2(v, OP_Null, 0, inReg); + } } testcase( regFree1==0 ); testcase( regFree2==0 ); @@ -114518,7 +118230,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) break; } case TK_AND: - case TK_OR: + case TK_OR: { + inReg = exprCodeTargetAndOr(pParse, pExpr, target, ®Free1); + break; + } case TK_PLUS: case TK_STAR: case TK_MINUS: @@ -114529,8 +118244,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) case TK_LSHIFT: case TK_RSHIFT: case TK_CONCAT: { - assert( TK_AND==OP_And ); testcase( op==TK_AND ); - assert( TK_OR==OP_Or ); testcase( op==TK_OR ); + int addrIsNull; assert( TK_PLUS==OP_Add ); testcase( op==TK_PLUS ); assert( TK_MINUS==OP_Subtract ); testcase( op==TK_MINUS ); assert( TK_REM==OP_Remainder ); testcase( op==TK_REM ); @@ -114540,11 +118254,23 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) assert( TK_LSHIFT==OP_ShiftLeft ); testcase( op==TK_LSHIFT ); assert( TK_RSHIFT==OP_ShiftRight ); testcase( op==TK_RSHIFT ); assert( TK_CONCAT==OP_Concat ); testcase( op==TK_CONCAT ); - r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + if( ExprHasProperty(pExpr, EP_Subquery) ){ + addrIsNull = exprComputeOperands(pParse, pExpr, + &r1, &r2, ®Free1, ®Free2); + }else{ + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + addrIsNull = 0; + } sqlite3VdbeAddOp3(v, op, r2, r1, target); testcase( regFree1==0 ); testcase( regFree2==0 ); + if( addrIsNull ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2); + sqlite3VdbeJumpHere(v, addrIsNull); + sqlite3VdbeAddOp2(v, OP_Null, 0, target); + VdbeComment((v, "short-circut value")); + } break; } case TK_UMINUS: { @@ -115118,6 +118844,25 @@ SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce( return regDest; } +/* +** Make arrangements to invoke OP_Null on a range of registers +** during initialization. +*/ +SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3ExprNullRegisterRange( + Parse *pParse, /* Parsing context */ + int iReg, /* First register to set to NULL */ + int nReg /* Number of sequential registers to NULL out */ +){ + u8 okConstFactor = pParse->okConstFactor; + Expr t; + memset(&t, 0, sizeof(t)); + t.op = TK_NULLS; + t.y.nReg = nReg; + pParse->okConstFactor = 1; + sqlite3ExprCodeRunJustOnce(pParse, &t, iReg); + pParse->okConstFactor = okConstFactor; +} + /* ** Generate code to evaluate an expression and store the results ** into a register. Return the register number where the results @@ -115393,17 +119138,27 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); if( pAlt!=pExpr ){ sqlite3ExprIfTrue(pParse, pAlt, dest, jumpIfNull); - }else if( op==TK_AND ){ - int d2 = sqlite3VdbeMakeLabel(pParse); - testcase( jumpIfNull==0 ); - sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, - jumpIfNull^SQLITE_JUMPIFNULL); - sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3VdbeResolveLabel(v, d2); }else{ - testcase( jumpIfNull==0 ); - sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); - sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + Expr *pFirst, *pSecond; + if( exprEvalRhsFirst(pExpr) ){ + pFirst = pExpr->pRight; + pSecond = pExpr->pLeft; + }else{ + pFirst = pExpr->pLeft; + pSecond = pExpr->pRight; + } + if( op==TK_AND ){ + int d2 = sqlite3VdbeMakeLabel(pParse); + testcase( jumpIfNull==0 ); + sqlite3ExprIfFalse(pParse, pFirst, d2, + jumpIfNull^SQLITE_JUMPIFNULL); + sqlite3ExprIfTrue(pParse, pSecond, dest, jumpIfNull); + sqlite3VdbeResolveLabel(v, d2); + }else{ + testcase( jumpIfNull==0 ); + sqlite3ExprIfTrue(pParse, pFirst, dest, jumpIfNull); + sqlite3ExprIfTrue(pParse, pSecond, dest, jumpIfNull); + } } break; } @@ -115442,10 +119197,16 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int case TK_GE: case TK_NE: case TK_EQ: { + int addrIsNull; if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr; - testcase( jumpIfNull==0 ); - r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + if( ExprHasProperty(pExpr, EP_Subquery) && jumpIfNull!=SQLITE_NULLEQ ){ + addrIsNull = exprComputeOperands(pParse, pExpr, + &r1, &r2, ®Free1, ®Free2); + }else{ + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + addrIsNull = 0; + } codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull, ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); @@ -115460,6 +119221,13 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ); testcase( regFree1==0 ); testcase( regFree2==0 ); + if( addrIsNull ){ + if( jumpIfNull ){ + sqlite3VdbeChangeP2(v, addrIsNull, dest); + }else{ + sqlite3VdbeJumpHere(v, addrIsNull); + } + } break; } case TK_ISNULL: @@ -115467,11 +119235,11 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - sqlite3VdbeTypeofColumn(v, r1); + assert( regFree1==0 || regFree1==r1 ); + if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1); sqlite3VdbeAddOp2(v, op, r1, dest); VdbeCoverageIf(v, op==TK_ISNULL); VdbeCoverageIf(v, op==TK_NOTNULL); - testcase( regFree1==0 ); break; } case TK_BETWEEN: { @@ -115567,17 +119335,27 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); if( pAlt!=pExpr ){ sqlite3ExprIfFalse(pParse, pAlt, dest, jumpIfNull); - }else if( pExpr->op==TK_AND ){ - testcase( jumpIfNull==0 ); - sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); - sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); }else{ - int d2 = sqlite3VdbeMakeLabel(pParse); - testcase( jumpIfNull==0 ); - sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, - jumpIfNull^SQLITE_JUMPIFNULL); - sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3VdbeResolveLabel(v, d2); + Expr *pFirst, *pSecond; + if( exprEvalRhsFirst(pExpr) ){ + pFirst = pExpr->pRight; + pSecond = pExpr->pLeft; + }else{ + pFirst = pExpr->pLeft; + pSecond = pExpr->pRight; + } + if( pExpr->op==TK_AND ){ + testcase( jumpIfNull==0 ); + sqlite3ExprIfFalse(pParse, pFirst, dest, jumpIfNull); + sqlite3ExprIfFalse(pParse, pSecond, dest, jumpIfNull); + }else{ + int d2 = sqlite3VdbeMakeLabel(pParse); + testcase( jumpIfNull==0 ); + sqlite3ExprIfTrue(pParse, pFirst, d2, + jumpIfNull^SQLITE_JUMPIFNULL); + sqlite3ExprIfFalse(pParse, pSecond, dest, jumpIfNull); + sqlite3VdbeResolveLabel(v, d2); + } } break; } @@ -115619,10 +119397,16 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int case TK_GE: case TK_NE: case TK_EQ: { + int addrIsNull; if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr; - testcase( jumpIfNull==0 ); - r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + if( ExprHasProperty(pExpr, EP_Subquery) && jumpIfNull!=SQLITE_NULLEQ ){ + addrIsNull = exprComputeOperands(pParse, pExpr, + &r1, &r2, ®Free1, ®Free2); + }else{ + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + addrIsNull = 0; + } codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull,ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); @@ -115637,16 +119421,23 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ); testcase( regFree1==0 ); testcase( regFree2==0 ); + if( addrIsNull ){ + if( jumpIfNull ){ + sqlite3VdbeChangeP2(v, addrIsNull, dest); + }else{ + sqlite3VdbeJumpHere(v, addrIsNull); + } + } break; } case TK_ISNULL: case TK_NOTNULL: { r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); - sqlite3VdbeTypeofColumn(v, r1); + assert( regFree1==0 || regFree1==r1 ); + if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1); sqlite3VdbeAddOp2(v, op, r1, dest); testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL); testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL); - testcase( regFree1==0 ); break; } case TK_BETWEEN: { @@ -115712,16 +119503,23 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i ** same as that currently bound to variable pVar, non-zero is returned. ** Otherwise, if the values are not the same or if pExpr is not a simple ** SQL value, zero is returned. +** +** If the SQLITE_EnableQPSG flag is set on the database connection, then +** this routine always returns false. */ -static int exprCompareVariable( +static SQLITE_NOINLINE int exprCompareVariable( const Parse *pParse, const Expr *pVar, const Expr *pExpr ){ - int res = 0; + int res = 2; int iVar; sqlite3_value *pL, *pR = 0; + if( pExpr->op==TK_VARIABLE && pVar->iColumn==pExpr->iColumn ){ + return 0; + } + if( (pParse->db->flags & SQLITE_EnableQPSG)!=0 ) return 2; sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR); if( pR ){ iVar = pVar->iColumn; @@ -115731,12 +119529,11 @@ static int exprCompareVariable( if( sqlite3_value_type(pL)==SQLITE_TEXT ){ sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */ } - res = 0==sqlite3MemCompare(pL, pR, 0); + res = sqlite3MemCompare(pL, pR, 0) ? 2 : 0; } sqlite3ValueFree(pR); sqlite3ValueFree(pL); } - return res; } @@ -115762,12 +119559,10 @@ static int exprCompareVariable( ** just might result in some slightly slower code. But returning ** an incorrect 0 or 1 could lead to a malfunction. ** -** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in -** pParse->pReprepare can be matched against literals in pB. The -** pParse->pVdbe->expmask bitmask is updated for each variable referenced. -** If pParse is NULL (the normal case) then any TK_VARIABLE term in -** Argument pParse should normally be NULL. If it is not NULL and pA or -** pB causes a return value of 2. +** If pParse is not NULL and SQLITE_EnableQPSG is off then TK_VARIABLE +** terms in pA with bindings in pParse->pReprepare can be matched against +** literals in pB. The pParse->pVdbe->expmask bitmask is updated for +** each variable referenced. */ SQLITE_PRIVATE int sqlite3ExprCompare( const Parse *pParse, @@ -115779,8 +119574,8 @@ SQLITE_PRIVATE int sqlite3ExprCompare( if( pA==0 || pB==0 ){ return pB==pA ? 0 : 2; } - if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){ - return 0; + if( pParse && pA->op==TK_VARIABLE ){ + return exprCompareVariable(pParse, pA, pB); } combinedFlags = pA->flags | pB->flags; if( combinedFlags & EP_IntValue ){ @@ -115975,18 +119770,70 @@ static int exprImpliesNotNull( return 0; } +/* +** Return true if the boolean value of the expression is always either +** FALSE or NULL. +*/ +static int sqlite3ExprIsNotTrue(Expr *pExpr){ + int v; + if( pExpr->op==TK_NULL ) return 1; + if( pExpr->op==TK_TRUEFALSE && sqlite3ExprTruthValue(pExpr)==0 ) return 1; + v = 1; + if( sqlite3ExprIsInteger(pExpr, &v, 0) && v==0 ) return 1; + return 0; +} + +/* +** Return true if the expression is one of the following: +** +** CASE WHEN x THEN y END +** CASE WHEN x THEN y ELSE NULL END +** CASE WHEN x THEN y ELSE false END +** iif(x,y) +** iif(x,y,NULL) +** iif(x,y,false) +*/ +static int sqlite3ExprIsIIF(sqlite3 *db, const Expr *pExpr){ + ExprList *pList; + if( pExpr->op==TK_FUNCTION ){ + const char *z = pExpr->u.zToken; + FuncDef *pDef; + if( (z[0]!='i' && z[0]!='I') ) return 0; + if( pExpr->x.pList==0 ) return 0; + pDef = sqlite3FindFunction(db, z, pExpr->x.pList->nExpr, ENC(db), 0); +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + if( pDef==0 ) return 0; +#else + if( NEVER(pDef==0) ) return 0; +#endif + if( (pDef->funcFlags & SQLITE_FUNC_INLINE)==0 ) return 0; + if( SQLITE_PTR_TO_INT(pDef->pUserData)!=INLINEFUNC_iif ) return 0; + }else if( pExpr->op==TK_CASE ){ + if( pExpr->pLeft!=0 ) return 0; + }else{ + return 0; + } + pList = pExpr->x.pList; + assert( pList!=0 ); + if( pList->nExpr==2 ) return 1; + if( pList->nExpr==3 && sqlite3ExprIsNotTrue(pList->a[2].pExpr) ) return 1; + return 0; +} + /* ** Return true if we can prove the pE2 will always be true if pE1 is ** true. Return false if we cannot complete the proof or if pE2 might ** be false. Examples: ** -** pE1: x==5 pE2: x==5 Result: true -** pE1: x>0 pE2: x==5 Result: false -** pE1: x=21 pE2: x=21 OR y=43 Result: true -** pE1: x!=123 pE2: x IS NOT NULL Result: true -** pE1: x!=?1 pE2: x IS NOT NULL Result: true -** pE1: x IS NULL pE2: x IS NOT NULL Result: false -** pE1: x IS ?2 pE2: x IS NOT NULL Result: false +** pE1: x==5 pE2: x==5 Result: true +** pE1: x>0 pE2: x==5 Result: false +** pE1: x=21 pE2: x=21 OR y=43 Result: true +** pE1: x!=123 pE2: x IS NOT NULL Result: true +** pE1: x!=?1 pE2: x IS NOT NULL Result: true +** pE1: x IS NULL pE2: x IS NOT NULL Result: false +** pE1: x IS ?2 pE2: x IS NOT NULL Result: false +** pE1: iif(x,y) pE2: x Result: true +** PE1: iif(x,y,0) pE2: x Result: true ** ** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has ** Expr.iTable<0 then assume a table number given by iTab. @@ -116020,6 +119867,9 @@ SQLITE_PRIVATE int sqlite3ExprImpliesExpr( ){ return 1; } + if( sqlite3ExprIsIIF(pParse->db, pE1) ){ + return sqlite3ExprImpliesExpr(pParse,pE1->x.pList->a[0].pExpr,pE2,iTab); + } return 0; } @@ -116487,7 +120337,9 @@ static void findOrCreateAggInfoColumn( ){ struct AggInfo_col *pCol; int k; + int mxTerm = pParse->db->aLimit[SQLITE_LIMIT_COLUMN]; + assert( mxTerm <= SMXV(i16) ); assert( pAggInfo->iFirstReg==0 ); pCol = pAggInfo->aCol; for(k=0; knColumn; k++, pCol++){ @@ -116505,6 +120357,10 @@ static void findOrCreateAggInfoColumn( assert( pParse->db->mallocFailed ); return; } + if( k>mxTerm ){ + sqlite3ErrorMsg(pParse, "more than %d aggregate terms", mxTerm); + k = mxTerm; + } pCol = &pAggInfo->aCol[k]; assert( ExprUseYTab(pExpr) ); pCol->pTab = pExpr->y.pTab; @@ -116538,6 +120394,7 @@ static void findOrCreateAggInfoColumn( if( pExpr->op==TK_COLUMN ){ pExpr->op = TK_AGG_COLUMN; } + assert( k <= SMXV(pExpr->iAgg) ); pExpr->iAgg = (i16)k; } @@ -116570,7 +120427,10 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ if( pIEpr==0 ) break; if( NEVER(!ExprUseYTab(pExpr)) ) break; for(i=0; inSrc; i++){ - if( pSrcList->a[0].iCursor==pIEpr->iDataCur ) break; + if( pSrcList->a[i].iCursor==pIEpr->iDataCur ){ + testcase( i>0 ); + break; + } } if( i>=pSrcList->nSrc ) break; if( NEVER(pExpr->pAggInfo!=0) ) break; /* Resolved by outer context */ @@ -116622,13 +120482,19 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ ** function that is already in the pAggInfo structure */ struct AggInfo_func *pItem = pAggInfo->aFunc; + int mxTerm = pParse->db->aLimit[SQLITE_LIMIT_COLUMN]; + assert( mxTerm <= SMXV(i16) ); for(i=0; inFunc; i++, pItem++){ if( NEVER(pItem->pFExpr==pExpr) ) break; if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){ break; } } - if( i>=pAggInfo->nFunc ){ + if( i>mxTerm ){ + sqlite3ErrorMsg(pParse, "more than %d aggregate terms", mxTerm); + i = mxTerm; + assert( inFunc ); + }else if( i>=pAggInfo->nFunc ){ /* pExpr is original. Make a new entry in pAggInfo->aFunc[] */ u8 enc = ENC(pParse->db); @@ -116682,6 +120548,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ */ assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(pExpr, EP_NoReduce); + assert( i <= SMXV(pExpr->iAgg) ); pExpr->iAgg = (i16)i; pExpr->pAggInfo = pAggInfo; return WRC_Prune; @@ -117352,7 +121219,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); assert( sqlite3BtreeHoldsAllMutexes(db) ); - if( db->mallocFailed ) goto exit_begin_add_column; + if( NEVER(db->mallocFailed) ) goto exit_begin_add_column; pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_begin_add_column; @@ -117392,13 +121259,13 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ assert( pNew->nCol>0 ); nAlloc = (((pNew->nCol-1)/8)*8)+8; assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 ); - pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc); + pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*(u32)nAlloc); pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName); if( !pNew->aCol || !pNew->zName ){ assert( db->mallocFailed ); goto exit_begin_add_column; } - memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); + memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*(size_t)pNew->nCol); for(i=0; inCol; i++){ Column *pCol = &pNew->aCol[i]; pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName); @@ -117424,7 +121291,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ ** Or, if pTab is not a view or virtual table, zero is returned. */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) -static int isRealTable(Parse *pParse, Table *pTab, int bDrop){ +static int isRealTable(Parse *pParse, Table *pTab, int iOp){ const char *zType = 0; #ifndef SQLITE_OMIT_VIEW if( IsView(pTab) ){ @@ -117437,9 +121304,12 @@ static int isRealTable(Parse *pParse, Table *pTab, int bDrop){ } #endif if( zType ){ + const char *azMsg[] = { + "rename columns of", "drop column from", "edit constraints of" + }; + assert( iOp>=0 && iOpzName + azMsg[iOp], zType, pTab->zName ); return 1; } @@ -117493,10 +121363,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn( ** altered. Set iCol to be the index of the column being renamed */ zOld = sqlite3NameFromToken(db, pOld); if( !zOld ) goto exit_rename_column; - for(iCol=0; iColnCol; iCol++){ - if( 0==sqlite3StrICmp(pTab->aCol[iCol].zCnName, zOld) ) break; - } - if( iCol==pTab->nCol ){ + iCol = sqlite3ColumnIndex(pTab, zOld); + if( iCol<0 ){ sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pOld); goto exit_rename_column; } @@ -117912,6 +121780,25 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){ return pBest; } +/* +** Set the error message of the context passed as the first argument to +** the result of formatting zFmt using printf() style formatting. +*/ +static void errorMPrintf(sqlite3_context *pCtx, const char *zFmt, ...){ + sqlite3 *db = sqlite3_context_db_handle(pCtx); + char *zErr = 0; + va_list ap; + va_start(ap, zFmt); + zErr = sqlite3VMPrintf(db, zFmt, ap); + va_end(ap); + if( zErr ){ + sqlite3_result_error(pCtx, zErr, -1); + sqlite3DbFree(db, zErr); + }else{ + sqlite3_result_error_nomem(pCtx); + } +} + /* ** An error occurred while parsing or otherwise processing a database ** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an @@ -117999,6 +121886,7 @@ static int renameParseSql( int bTemp /* True if SQL is from temp schema */ ){ int rc; + u64 flags; sqlite3ParseObjectInit(p, db); if( zSql==0 ){ @@ -118007,11 +121895,21 @@ static int renameParseSql( if( sqlite3StrNICmp(zSql,"CREATE ",7)!=0 ){ return SQLITE_CORRUPT_BKPT; } - db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb); + if( bTemp ){ + db->init.iDb = 1; + }else{ + int iDb = sqlite3FindDbName(db, zDb); + assert( iDb>=0 && iDb<=0xff ); + db->init.iDb = (u8)iDb; + } p->eParseMode = PARSE_MODE_RENAME; p->db = db; p->nQueryLoop = 1; + flags = db->flags; + testcase( (db->flags & SQLITE_Comments)==0 && strstr(zSql," /* ")!=0 ); + db->flags |= SQLITE_Comments; rc = sqlite3RunParser(p, zSql); + db->flags = flags; if( db->mallocFailed ) rc = SQLITE_NOMEM; if( rc==SQLITE_OK && NEVER(p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0) @@ -118074,10 +121972,11 @@ static int renameEditSql( nQuot = sqlite3Strlen30(zQuot)-1; } - assert( nQuot>=nNew ); - zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1); + assert( nQuot>=nNew && nSql>=0 && nNew>=0 ); + zOut = sqlite3DbMallocZero(db, (u64)nSql + pRename->nList*(u64)nQuot + 1); }else{ - zOut = (char*)sqlite3DbMallocZero(db, (nSql*2+1) * 3); + assert( nSql>0 ); + zOut = (char*)sqlite3DbMallocZero(db, (2*(u64)nSql + 1) * 3); if( zOut ){ zBuf1 = &zOut[nSql*2+1]; zBuf2 = &zOut[nSql*4+2]; @@ -118089,16 +121988,17 @@ static int renameEditSql( ** with the new column name, or with single-quoted versions of themselves. ** All that remains is to construct and return the edited SQL string. */ if( zOut ){ - int nOut = nSql; - memcpy(zOut, zSql, nSql); + i64 nOut = nSql; + assert( nSql>0 ); + memcpy(zOut, zSql, (size_t)nSql); while( pRename->pList ){ int iOff; /* Offset of token to replace in zOut */ - u32 nReplace; + i64 nReplace; const char *zReplace; RenameToken *pBest = renameColumnTokenNext(pRename); if( zNew ){ - if( bQuote==0 && sqlite3IsIdChar(*pBest->t.z) ){ + if( bQuote==0 && sqlite3IsIdChar(*(u8*)pBest->t.z) ){ nReplace = nNew; zReplace = zNew; }else{ @@ -118116,14 +122016,15 @@ static int renameEditSql( memcpy(zBuf1, pBest->t.z, pBest->t.n); zBuf1[pBest->t.n] = 0; sqlite3Dequote(zBuf1); - sqlite3_snprintf(nSql*2, zBuf2, "%Q%s", zBuf1, + assert( nSql < 0x15555554 /* otherwise malloc would have failed */ ); + sqlite3_snprintf((int)(nSql*2), zBuf2, "%Q%s", zBuf1, pBest->t.z[pBest->t.n]=='\'' ? " " : "" ); zReplace = zBuf2; nReplace = sqlite3Strlen30(zReplace); } - iOff = pBest->t.z - zSql; + iOff = (int)(pBest->t.z - zSql); if( pBest->t.n!=nReplace ){ memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n], nOut - (iOff + pBest->t.n) @@ -118149,11 +122050,12 @@ static int renameEditSql( ** Set all pEList->a[].fg.eEName fields in the expression-list to val. */ static void renameSetENames(ExprList *pEList, int val){ + assert( val==ENAME_NAME || val==ENAME_TAB || val==ENAME_SPAN ); if( pEList ){ int i; for(i=0; inExpr; i++){ assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME ); - pEList->a[i].fg.eEName = val; + pEList->a[i].fg.eEName = val&0x3; } } } @@ -118194,8 +122096,8 @@ static int renameResolveTrigger(Parse *pParse){ sqlite3SelectPrep(pParse, pStep->pSelect, &sNC); if( pParse->nErr ) rc = pParse->rc; } - if( rc==SQLITE_OK && pStep->zTarget ){ - SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep); + if( rc==SQLITE_OK && pStep->pSrc ){ + SrcList *pSrc = sqlite3SrcListDup(db, pStep->pSrc, 0); if( pSrc ){ Select *pSel = sqlite3SelectNew( pParse, pStep->pExprList, pSrc, 0, 0, 0, 0, 0, 0 @@ -118223,10 +122125,10 @@ static int renameResolveTrigger(Parse *pParse){ pSel->pSrc = 0; sqlite3SelectDelete(db, pSel); } - if( pStep->pFrom ){ + if( ALWAYS(pStep->pSrc) ){ int i; - for(i=0; ipFrom->nSrc && rc==SQLITE_OK; i++){ - SrcItem *p = &pStep->pFrom->a[i]; + for(i=0; ipSrc->nSrc && rc==SQLITE_OK; i++){ + SrcItem *p = &pStep->pSrc->a[i]; if( p->fg.isSubquery ){ assert( p->u4.pSubq!=0 ); sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0); @@ -118295,13 +122197,13 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){ sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere); sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere); } - if( pStep->pFrom ){ + if( pStep->pSrc ){ int i; - SrcList *pFrom = pStep->pFrom; - for(i=0; inSrc; i++){ - if( pFrom->a[i].fg.isSubquery ){ - assert( pFrom->a[i].u4.pSubq!=0 ); - sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect); + SrcList *pSrc = pStep->pSrc; + for(i=0; inSrc; i++){ + if( pSrc->a[i].fg.isSubquery ){ + assert( pSrc->a[i].u4.pSubq!=0 ); + sqlite3WalkSelect(pWalker, pSrc->a[i].u4.pSubq->pSelect); } } } @@ -118410,7 +122312,7 @@ static void renameColumnFunc( if( sParse.pNewTable ){ if( IsView(sParse.pNewTable) ){ Select *pSelect = sParse.pNewTable->u.view.pSelect; - pSelect->selFlags &= ~SF_View; + pSelect->selFlags &= ~(u32)SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); @@ -118472,8 +122374,8 @@ static void renameColumnFunc( if( rc!=SQLITE_OK ) goto renameColumnFunc_done; for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){ - if( pStep->zTarget ){ - Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb); + if( pStep->pSrc ){ + Table *pTarget = sqlite3LocateTableItem(&sParse, 0, &pStep->pSrc->a[0]); if( pTarget==pTab ){ if( pStep->pUpsert ){ ExprList *pUpsertSet = pStep->pUpsert->pUpsertSet; @@ -118485,7 +122387,6 @@ static void renameColumnFunc( } } - /* Find tokens to edit in UPDATE OF clause */ if( sParse.pTriggerTab==pTab ){ renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld); @@ -118628,7 +122529,7 @@ static void renameTableFunc( sNC.pParse = &sParse; assert( pSelect->selFlags & SF_View ); - pSelect->selFlags &= ~SF_View; + pSelect->selFlags &= ~(u32)SF_View; sqlite3SelectPrep(&sParse, pTab->u.view.pSelect, &sNC); if( sParse.nErr ){ rc = sParse.rc; @@ -118687,13 +122588,10 @@ static void renameTableFunc( if( rc==SQLITE_OK ){ renameWalkTrigger(&sWalker, pTrigger); for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){ - if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){ - renameTokenFind(&sParse, &sCtx, pStep->zTarget); - } - if( pStep->pFrom ){ + if( pStep->pSrc ){ int i; - for(i=0; ipFrom->nSrc; i++){ - SrcItem *pItem = &pStep->pFrom->a[i]; + for(i=0; ipSrc->nSrc; i++){ + SrcItem *pItem = &pStep->pSrc->a[i]; if( 0==sqlite3_stricmp(pItem->zName, zOld) ){ renameTokenFind(&sParse, &sCtx, pItem->zName); } @@ -118801,7 +122699,7 @@ static void renameQuotefixFunc( if( sParse.pNewTable ){ if( IsView(sParse.pNewTable) ){ Select *pSelect = sParse.pNewTable->u.view.pSelect; - pSelect->selFlags &= ~SF_View; + pSelect->selFlags &= ~(u32)SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); @@ -118900,10 +122798,10 @@ static void renameTableTest( if( zDb && zInput ){ int rc; Parse sParse; - int flags = db->flags; + u64 flags = db->flags; if( bNoDQS ) db->flags &= ~(SQLITE_DqsDML|SQLITE_DqsDDL); rc = renameParseSql(&sParse, zDb, db, zInput, bTemp); - db->flags |= (flags & (SQLITE_DqsDML|SQLITE_DqsDDL)); + db->flags = flags; if( rc==SQLITE_OK ){ if( isLegacy==0 && sParse.pNewTable && IsView(sParse.pNewTable) ){ NameContext sNC; @@ -118940,6 +122838,57 @@ static void renameTableTest( #endif } + +/* +** Return the number of bytes until the end of the next non-whitespace and +** non-comment token. For the purpose of this function, a "(" token includes +** all of the bytes through and including the matching ")", or until the +** first illegal token, whichever comes first. +** +** Write the token type into *piToken. +** +** The value returned is the number of bytes in the token itself plus +** the number of bytes of leading whitespace and comments skipped plus +** all bytes through the next matching ")" if the token is TK_LP. +** +** Example: (Note: '.' used in place of '*' in the example z[] text) +** +** ,--------- *piToken := TK_RP +** v +** z[] = " /.comment./ --comment\n (two three four) five" +** | | +** |<-------------------------------------->| +** | +** `--- return value +*/ +static int getConstraintToken(const u8 *z, int *piToken){ + int iOff = 0; + int t = 0; + do { + iOff += sqlite3GetToken(&z[iOff], &t); + }while( t==TK_SPACE || t==TK_COMMENT ); + + *piToken = t; + + if( t==TK_LP ){ + int nNest = 1; + while( nNest>0 ){ + iOff += sqlite3GetToken(&z[iOff], &t); + if( t==TK_LP ){ + nNest++; + }else if( t==TK_RP ){ + t = TK_LP; + nNest--; + }else if( t==TK_ILLEGAL ){ + break; + } + } + } + + *piToken = t; + return iOff; +} + /* ** The implementation of internal UDF sqlite_drop_column(). ** @@ -118984,15 +122933,24 @@ static void dropColumnFunc( goto drop_column_done; } - pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName); if( iColnCol-1 ){ RenameToken *pEnd; + pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName); pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zCnName); zEnd = (const char*)pEnd->t.z; }else{ + int eTok; assert( IsOrdinaryTable(pTab) ); + assert( iCol!=0 ); + /* Point pCol->t.z at the "," immediately preceding the definition of + ** the column being dropped. To do this, start at the name of the + ** previous column, and tokenize until the next ",". */ + pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol-1].zCnName); + do { + pCol->t.z += getConstraintToken((const u8*)pCol->t.z, &eTok); + }while( eTok!=TK_COMMA ); + pCol->t.z--; zEnd = (const char*)&zSql[pTab->u.tab.addColOffset]; - while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--; } zNew = sqlite3MPrintf(db, "%.*s%s", pCol->t.z-zSql, zSql, zEnd); @@ -119161,6 +123119,665 @@ SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const T sqlite3SrcListDelete(db, pSrc); } +/* +** Return the number of bytes of leading whitespace/comments in string z[]. +*/ +static int getWhitespace(const u8 *z){ + int nRet = 0; + while( 1 ){ + int t = 0; + int n = sqlite3GetToken(&z[nRet], &t); + if( t!=TK_SPACE && t!=TK_COMMENT ) break; + nRet += n; + } + return nRet; +} + + +/* +** Argument z points into the body of a constraint - specifically the +** second token of the constraint definition. For a named constraint, +** z points to the first token past the CONSTRAINT keyword. For an +** unnamed NOT NULL constraint, z points to the first byte past the NOT +** keyword. +** +** Return the number of bytes until the end of the constraint. +*/ +static int getConstraint(const u8 *z){ + int iOff = 0; + int t = 0; + + /* Now, the current constraint proceeds until the next occurence of one + ** of the following tokens: + ** + ** CONSTRAINT, PRIMARY, NOT, UNIQUE, CHECK, DEFAULT, + ** COLLATE, REFERENCES, FOREIGN, GENERATED, AS, RP, or COMMA + ** + ** Also exit the loop if ILLEGAL turns up. + */ + while( 1 ){ + int n = getConstraintToken(&z[iOff], &t); + if( t==TK_CONSTRAINT || t==TK_PRIMARY || t==TK_NOT || t==TK_UNIQUE + || t==TK_CHECK || t==TK_DEFAULT || t==TK_COLLATE || t==TK_REFERENCES + || t==TK_FOREIGN || t==TK_RP || t==TK_COMMA || t==TK_ILLEGAL + || t==TK_AS || t==TK_GENERATED + ){ + break; + } + iOff += n; + } + + return iOff; +} + +/* +** Compare two constraint names. +** +** Summary: *pRes := zQuote != zCmp +** +** Details: +** Compare the (possibly quoted) constraint name zQuote[0..nQuote-1] +** against zCmp[]. Write zero into *pRes if they are the same and +** non-zero if they differ. Normally return SQLITE_OK, except if there +** is an OOM, set the OOM error condition on ctx and return SQLITE_NOMEM. +*/ +static int quotedCompare( + sqlite3_context *ctx, /* Function context on which to report errors */ + int t, /* Token type */ + const u8 *zQuote, /* Possibly quoted text. Not zero-terminated. */ + int nQuote, /* Length of zQuote in bytes */ + const u8 *zCmp, /* Zero-terminated, unquoted name to compare against */ + int *pRes /* OUT: Set to 0 if equal, non-zero if unequal */ +){ + char *zCopy = 0; /* De-quoted, zero-terminated copy of zQuote[] */ + + if( t==TK_ILLEGAL ){ + *pRes = 1; + return SQLITE_OK; + } + zCopy = sqlite3MallocZero(nQuote+1); + if( zCopy==0 ){ + sqlite3_result_error_nomem(ctx); + return SQLITE_NOMEM_BKPT; + } + memcpy(zCopy, zQuote, nQuote); + sqlite3Dequote(zCopy); + *pRes = sqlite3_stricmp((const char*)zCopy, (const char*)zCmp); + sqlite3_free(zCopy); + return SQLITE_OK; +} + +/* +** zSql[] is a CREATE TABLE statement, supposedly. Find the offset +** into zSql[] of the first character past the first "(" and write +** that offset into *piOff and return SQLITE_OK. Or, if not found, +** set the SQLITE_CORRUPT error code and return SQLITE_ERROR. +*/ +static int skipCreateTable(sqlite3_context *ctx, const u8 *zSql, int *piOff){ + int iOff = 0; + + if( zSql==0 ) return SQLITE_ERROR; + + /* Jump past the "CREATE TABLE" bit. */ + while( 1 ){ + int t = 0; + iOff += sqlite3GetToken(&zSql[iOff], &t); + if( t==TK_LP ) break; + if( t==TK_ILLEGAL ){ + sqlite3_result_error_code(ctx, SQLITE_CORRUPT_BKPT); + return SQLITE_ERROR; + } + } + + *piOff = iOff; + return SQLITE_OK; +} + +/* +** Internal SQL function sqlite3_drop_constraint(): Given an input +** CREATE TABLE statement, return a revised CREATE TABLE statement +** with a constraint removed. Two forms, depending on the datatype +** of argv[2]: +** +** sqlite_drop_constraint(SQL, INT) -- Omit NOT NULL from the INT-th column +** sqlite_drop_constraint(SQL, TEXT) -- OMIT constraint with name TEXT +** +** In the first case, the left-most column is 0. +*/ +static void dropConstraintFunc( + sqlite3_context *ctx, + int NotUsed, + sqlite3_value **argv +){ + const u8 *zSql = sqlite3_value_text(argv[0]); + const u8 *zCons = 0; + int iNotNull = -1; + int ii; + int iOff = 0; + int iStart = 0; + int iEnd = 0; + char *zNew = 0; + int t = 0; + sqlite3 *db; + UNUSED_PARAMETER(NotUsed); + + if( zSql==0 ) return; + + /* Jump past the "CREATE TABLE" bit. */ + if( skipCreateTable(ctx, zSql, &iOff) ) return; + + if( sqlite3_value_type(argv[1])==SQLITE_INTEGER ){ + iNotNull = sqlite3_value_int(argv[1]); + }else{ + zCons = sqlite3_value_text(argv[1]); + } + + /* Search for the named constraint within column definitions. */ + for(ii=0; iEnd==0; ii++){ + + /* Now parse the column or table constraint definition. Search + ** for the token CONSTRAINT if this is a DROP CONSTRAINT command, or + ** NOT in the right column if this is a DROP NOT NULL. */ + while( 1 ){ + iStart = iOff; + iOff += getConstraintToken(&zSql[iOff], &t); + if( t==TK_CONSTRAINT && (zCons || iNotNull==ii) ){ + /* Check if this is the constraint we are searching for. */ + int nTok = 0; + int cmp = 1; + + /* Skip past any whitespace. */ + iOff += getWhitespace(&zSql[iOff]); + + /* Compare the next token - which may be quoted - with the name of + ** the constraint being dropped. */ + nTok = getConstraintToken(&zSql[iOff], &t); + if( zCons ){ + if( quotedCompare(ctx, t, &zSql[iOff], nTok, zCons, &cmp) ) return; + } + iOff += nTok; + + /* The next token is usually the first token of the constraint + ** definition. This is enough to tell the type of the constraint - + ** TK_NOT means it is a NOT NULL, TK_CHECK a CHECK constraint etc. + ** + ** There is also the chance that the next token is TK_CONSTRAINT + ** (or TK_DEFAULT or TK_COLLATE), for example if a table has been + ** created as follows: + ** + ** CREATE TABLE t1(cols, CONSTRAINT one CONSTRAINT two NOT NULL); + ** + ** In this case, allow the "CONSTRAINT one" bit to be dropped by + ** this command if that is what is requested, or to advance to + ** the next iteration of the loop with &zSql[iOff] still pointing + ** to the CONSTRAINT keyword. */ + nTok = getConstraintToken(&zSql[iOff], &t); + if( t==TK_CONSTRAINT || t==TK_DEFAULT || t==TK_COLLATE + || t==TK_COMMA || t==TK_RP || t==TK_GENERATED || t==TK_AS + ){ + t = TK_CHECK; + }else{ + iOff += nTok; + iOff += getConstraint(&zSql[iOff]); + } + + if( cmp==0 || (iNotNull>=0 && t==TK_NOT) ){ + if( t!=TK_NOT && t!=TK_CHECK ){ + errorMPrintf(ctx, "constraint may not be dropped: %s", zCons); + return; + } + iEnd = iOff; + break; + } + + }else if( t==TK_NOT && iNotNull==ii ){ + iEnd = iOff + getConstraint(&zSql[iOff]); + break; + }else if( t==TK_RP || t==TK_ILLEGAL ){ + iEnd = -1; + break; + }else if( t==TK_COMMA ){ + break; + } + } + } + + /* If the constraint has not been found it is an error. */ + if( iEnd<=0 ){ + if( zCons ){ + errorMPrintf(ctx, "no such constraint: %s", zCons); + }else{ + /* SQLite follows postgres in that a DROP NOT NULL on a column that is + ** not NOT NULL is not an error. So just return the original SQL here. */ + sqlite3_result_text(ctx, (const char*)zSql, -1, SQLITE_TRANSIENT); + } + }else{ + + /* Figure out if an extra space should be inserted after the constraint + ** is removed. And if an additional comma preceding the constraint + ** should be removed. */ + const char *zSpace = " "; + iEnd += getWhitespace(&zSql[iEnd]); + sqlite3GetToken(&zSql[iEnd], &t); + if( t==TK_RP || t==TK_COMMA ){ + zSpace = ""; + if( zSql[iStart-1]==',' ) iStart--; + } + + db = sqlite3_context_db_handle(ctx); + zNew = sqlite3MPrintf(db, "%.*s%s%s", iStart, zSql, zSpace, &zSql[iEnd]); + sqlite3_result_text(ctx, zNew, -1, SQLITE_DYNAMIC); + } +} + +/* +** Internal SQL function: +** +** sqlite_add_constraint(SQL, CONSTRAINT-TEXT, ICOL) +** +** SQL is a CREATE TABLE statement. Return a modified version of +** SQL that adds CONSTRAINT-TEXT at the end of the ICOL-th column +** definition. (The left-most column defintion is 0.) +*/ +static void addConstraintFunc( + sqlite3_context *ctx, + int NotUsed, + sqlite3_value **argv +){ + const u8 *zSql = sqlite3_value_text(argv[0]); + const char *zCons = (const char*)sqlite3_value_text(argv[1]); + int iCol = sqlite3_value_int(argv[2]); + int iOff = 0; + int ii; + char *zNew = 0; + int t = 0; + sqlite3 *db; + UNUSED_PARAMETER(NotUsed); + + if( skipCreateTable(ctx, zSql, &iOff) ) return; + + for(ii=0; ii<=iCol || (iCol<0 && t!=TK_RP); ii++){ + iOff += getConstraintToken(&zSql[iOff], &t); + while( 1 ){ + int nTok = getConstraintToken(&zSql[iOff], &t); + if( t==TK_COMMA || t==TK_RP ) break; + if( t==TK_ILLEGAL ){ + sqlite3_result_error_code(ctx, SQLITE_CORRUPT_BKPT); + return; + } + iOff += nTok; + } + } + + iOff += getWhitespace(&zSql[iOff]); + + db = sqlite3_context_db_handle(ctx); + if( iCol<0 ){ + zNew = sqlite3MPrintf(db, "%.*s, %s%s", iOff, zSql, zCons, &zSql[iOff]); + }else{ + zNew = sqlite3MPrintf(db, "%.*s %s%s", iOff, zSql, zCons, &zSql[iOff]); + } + sqlite3_result_text(ctx, zNew, -1, SQLITE_DYNAMIC); +} + +/* +** Find a column named pCol in table pTab. If successful, set output +** parameter *piCol to the index of the column in the table and return +** SQLITE_OK. Otherwise, set *piCol to -1 and return an SQLite error +** code. +*/ +static int alterFindCol(Parse *pParse, Table *pTab, Token *pCol, int *piCol){ + sqlite3 *db = pParse->db; + char *zName = sqlite3NameFromToken(db, pCol); + int rc = SQLITE_NOMEM; + int iCol = -1; + + if( zName ){ + iCol = sqlite3ColumnIndex(pTab, zName); + if( iCol<0 ){ + sqlite3ErrorMsg(pParse, "no such column: %s", zName); + rc = SQLITE_ERROR; + }else{ + rc = SQLITE_OK; + } + } + +#ifndef SQLITE_OMIT_AUTHORIZATION + if( rc==SQLITE_OK ){ + const char *zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; + const char *zCol = pTab->aCol[iCol].zCnName; + if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, zCol) ){ + pTab = 0; + } + } +#endif + + sqlite3DbFree(db, zName); + *piCol = iCol; + return rc; +} + + +/* +** Find the table named by the first entry in source list pSrc. If successful, +** return a pointer to the Table structure and set output variable (*pzDb) +** to point to the name of the database containin the table (i.e. "main", +** "temp" or the name of an attached database). +** +** If the table cannot be located, return NULL. The value of the two output +** parameters is undefined in this case. +*/ +static Table *alterFindTable( + Parse *pParse, /* Parsing context */ + SrcList *pSrc, /* Name of the table to look for */ + int *piDb, /* OUT: write the iDb here */ + const char **pzDb, /* OUT: write name of schema here */ + int bAuth /* Do ALTER TABLE authorization checks if true */ +){ + sqlite3 *db = pParse->db; + Table *pTab = 0; + assert( sqlite3BtreeHoldsAllMutexes(db) ); + pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); + if( pTab ){ + int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + *pzDb = db->aDb[iDb].zDbSName; + *piDb = iDb; + + if( SQLITE_OK!=isRealTable(pParse, pTab, 2) + || SQLITE_OK!=isAlterableTable(pParse, pTab) + ){ + pTab = 0; + } + } +#ifndef SQLITE_OMIT_AUTHORIZATION + if( pTab && bAuth ){ + if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, *pzDb, pTab->zName, 0) ){ + pTab = 0; + } + } +#endif + sqlite3SrcListDelete(db, pSrc); + return pTab; +} + +/* +** Generate bytecode for one of: +** +** (1) ALTER TABLE pSrc DROP CONSTRAINT pCons +** (2) ALTER TABLE pSrc ALTER pCol DROP NOT NULL +** +** One of pCons and pCol must be NULL and the other non-null. +*/ +SQLITE_PRIVATE void sqlite3AlterDropConstraint( + Parse *pParse, /* Parsing context */ + SrcList *pSrc, /* The table being altered */ + Token *pCons, /* Name of the constraint to drop */ + Token *pCol /* Name of the column from which to remove the NOT NULL */ +){ + sqlite3 *db = pParse->db; + Table *pTab = 0; + int iDb = 0; + const char *zDb = 0; + char *zArg = 0; + + assert( (pCol==0)!=(pCons==0) ); + assert( pSrc->nSrc==1 ); + pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, pCons!=0); + if( !pTab ) return; + + if( pCons ){ + char *z = sqlite3NameFromToken(db, pCons); + zArg = sqlite3MPrintf(db, "%Q", z); + sqlite3DbFree(db, z); + }else{ + int iCol; + if( alterFindCol(pParse, pTab, pCol, &iCol) ) return; + zArg = sqlite3MPrintf(db, "%d", iCol); + } + + /* Edit the SQL for the named table. */ + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " + "sql = sqlite_drop_constraint(sql, %s) " + "WHERE type='table' AND tbl_name=%Q COLLATE nocase" + , zDb, zArg, pTab->zName + ); + sqlite3DbFree(db, zArg); + + /* Finally, reload the database schema. */ + renameReloadSchema(pParse, iDb, INITFLAG_AlterDropCons); +} + +/* +** The implementation of SQL function sqlite_fail(MSG). This takes a single +** argument, and returns it as an error message with the error code set to +** SQLITE_CONSTRAINT. +*/ +static void failConstraintFunc( + sqlite3_context *ctx, + int NotUsed, + sqlite3_value **argv +){ + const char *zText = (const char*)sqlite3_value_text(argv[0]); + int err = sqlite3_value_int(argv[1]); + (void)NotUsed; + sqlite3_result_error(ctx, zText, -1); + sqlite3_result_error_code(ctx, err); +} + +/* +** Buffer pCons, which is nCons bytes in size, contains the text of a +** NOT NULL or CHECK constraint that will be inserted into a CREATE TABLE +** statement. If successful, this function returns the size of the buffer in +** bytes not including any trailing whitespace or "--" style comments. Or, +** if an OOM occurs, it returns 0 and sets db->mallocFailed to true. +** +** C-style comments at the end are preserved. "--" style comments are +** removed because the comment terminator might be \000, and we are about +** to insert the pCons[] text into the middle of a larger string, and that +** will have the effect of removing the comment terminator and messing up +** the syntax. +*/ +static int alterRtrimConstraint( + sqlite3 *db, /* used to record OOM error */ + const char *pCons, /* Buffer containing constraint */ + int nCons /* Size of pCons in bytes */ +){ + u8 *zTmp = (u8*)sqlite3MPrintf(db, "%.*s", nCons, pCons); + int iOff = 0; + int iEnd = 0; + + if( zTmp==0 ) return 0; + + while( 1 ){ + int t = 0; + int nToken = sqlite3GetToken(&zTmp[iOff], &t); + if( t==TK_ILLEGAL ) break; + if( t!=TK_SPACE && (t!=TK_COMMENT || zTmp[iOff]!='-') ){ + iEnd = iOff+nToken; + } + iOff += nToken; + } + + sqlite3DbFree(db, zTmp); + return iEnd; +} + +/* +** Prepare a statement of the form: +** +** ALTER TABLE pSrc ALTER pCol SET NOT NULL +*/ +SQLITE_PRIVATE void sqlite3AlterSetNotNull( + Parse *pParse, /* Parsing context */ + SrcList *pSrc, /* Name of the table being altered */ + Token *pCol, /* Name of the column to add a NOT NULL constraint to */ + Token *pFirst /* The NOT token of the NOT NULL constraint text */ +){ + Table *pTab = 0; + int iCol = 0; + int iDb = 0; + const char *zDb = 0; + const char *pCons = 0; + int nCons = 0; + + /* Look up the table being altered. */ + assert( pSrc->nSrc==1 ); + pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, 0); + if( !pTab ) return; + + /* Find the column being altered. */ + if( alterFindCol(pParse, pTab, pCol, &iCol) ){ + return; + } + + /* Find the length in bytes of the constraint definition */ + pCons = pFirst->z; + nCons = alterRtrimConstraint(pParse->db, pCons, pParse->sLastToken.z - pCons); + + /* Search for a constraint violation. Throw an exception if one is found. */ + sqlite3NestedParse(pParse, + "SELECT sqlite_fail('constraint failed', %d) " + "FROM %Q.%Q AS x WHERE x.%.*s IS NULL", + SQLITE_CONSTRAINT, zDb, pTab->zName, (int)pCol->n, pCol->z + ); + + /* Edit the SQL for the named table. */ + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " + "sql = sqlite_add_constraint(sqlite_drop_constraint(sql, %d), %.*Q, %d) " + "WHERE type='table' AND tbl_name=%Q COLLATE nocase" + , zDb, iCol, nCons, pCons, iCol, pTab->zName + ); + + /* Finally, reload the database schema. */ + renameReloadSchema(pParse, iDb, INITFLAG_AlterDropCons); +} + +/* +** Implementation of internal SQL function: +** +** sqlite_find_constraint(SQL, CONSTRAINT-NAME) +** +** This function returns true if the SQL passed as the first argument is a +** CREATE TABLE that contains a constraint with the name CONSTRAINT-NAME, +** or false otherwise. +*/ +static void findConstraintFunc( + sqlite3_context *ctx, + int NotUsed, + sqlite3_value **argv +){ + const u8 *zSql = 0; + const u8 *zCons = 0; + int iOff = 0; + int t = 0; + + (void)NotUsed; + zSql = sqlite3_value_text(argv[0]); + zCons = sqlite3_value_text(argv[1]); + + if( zSql==0 || zCons==0 ) return; + while( t!=TK_LP && t!=TK_ILLEGAL ){ + iOff += sqlite3GetToken(&zSql[iOff], &t); + } + + while( 1 ){ + iOff += getConstraintToken(&zSql[iOff], &t); + if( t==TK_CONSTRAINT ){ + int nTok = 0; + int cmp = 0; + iOff += getWhitespace(&zSql[iOff]); + nTok = getConstraintToken(&zSql[iOff], &t); + if( quotedCompare(ctx, t, &zSql[iOff], nTok, zCons, &cmp) ) return; + if( cmp==0 ){ + sqlite3_result_int(ctx, 1); + return; + } + }else if( t==TK_ILLEGAL ){ + break; + } + } + + sqlite3_result_int(ctx, 0); +} + +/* +** Generate bytecode to implement: +** +** ALTER TABLE pSrc ADD [CONSTRAINT pName] CHECK(pExpr) +** +** Any "ON CONFLICT" text that occurs after the "CHECK(...)", up +** until pParse->sLastToken, is included as part of the new constraint. +*/ +SQLITE_PRIVATE void sqlite3AlterAddConstraint( + Parse *pParse, /* Parse context */ + SrcList *pSrc, /* Table to add constraint to */ + Token *pFirst, /* First token of new constraint */ + Token *pName, /* Name of new constraint. NULL if name omitted. */ + const char *zExpr, /* Text of CHECK expression */ + int nExpr, /* Size of pExpr in bytes */ + Expr *pExpr /* The parsed CHECK expression */ +){ + Table *pTab = 0; /* Table identified by pSrc */ + int iDb = 0; /* Which schema does pTab live in */ + const char *zDb = 0; /* Name of the schema in which pTab lives */ + const char *pCons = 0; /* Text of the constraint */ + int nCons; /* Bytes of text to use from pCons[] */ + int rc; /* Result from error checking pExpr */ + + /* Look up the table being altered. */ + assert( pSrc->nSrc==1 ); + pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, 1); + if( !pTab ){ + sqlite3ExprDelete(pParse->db, pExpr); + return; + } + + /* Verify that the new CHECK constraint does not contain any + ** internal-use-only function. Forum post 2026-05-10T01:11:28Z + */ + rc = sqlite3ResolveSelfReference(pParse, pTab, NC_IsCheck, pExpr, 0); + sqlite3ExprDelete(pParse->db, pExpr); + if( rc ) return; + + /* If this new constraint has a name, check that it is not a duplicate of + ** an existing constraint. It is an error if it is. */ + if( pName ){ + char *zName = sqlite3NameFromToken(pParse->db, pName); + + sqlite3NestedParse(pParse, + "SELECT sqlite_fail('constraint %q already exists', %d) " + "FROM \"%w\"." LEGACY_SCHEMA_TABLE " " + "WHERE type='table' AND tbl_name=%Q COLLATE nocase " + "AND sqlite_find_constraint(sql, %Q)", + zName, SQLITE_ERROR, zDb, pTab->zName, zName + ); + sqlite3DbFree(pParse->db, zName); + } + + /* Search for a constraint violation. Throw an exception if one is found. */ + sqlite3NestedParse(pParse, + "SELECT sqlite_fail('constraint failed', %d) " + "FROM %Q.%Q WHERE (%.*s) IS NOT TRUE", + SQLITE_CONSTRAINT, zDb, pTab->zName, nExpr, zExpr + ); + + /* Edit the SQL for the named table. */ + pCons = pFirst->z; + nCons = alterRtrimConstraint(pParse->db, pCons, pParse->sLastToken.z - pCons); + + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " + "sql = sqlite_add_constraint(sql, %.*Q, -1) " + "WHERE type='table' AND tbl_name=%Q COLLATE nocase" + , zDb, nCons, pCons, pTab->zName + ); + + /* Finally, reload the database schema. */ + renameReloadSchema(pParse, iDb, INITFLAG_AlterDropCons); +} + /* ** Register built-in functions used to help implement ALTER TABLE */ @@ -119171,6 +123788,10 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){ INTERNAL_FUNCTION(sqlite_rename_test, 7, renameTableTest), INTERNAL_FUNCTION(sqlite_drop_column, 3, dropColumnFunc), INTERNAL_FUNCTION(sqlite_rename_quotefix,2, renameQuotefixFunc), + INTERNAL_FUNCTION(sqlite_drop_constraint,2, dropConstraintFunc), + INTERNAL_FUNCTION(sqlite_fail, 2, failConstraintFunc), + INTERNAL_FUNCTION(sqlite_add_constraint, 3, addConstraintFunc), + INTERNAL_FUNCTION(sqlite_find_constraint,2, findConstraintFunc), }; sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); } @@ -119395,7 +124016,8 @@ static void openStatTable( sqlite3NestedParse(pParse, "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols ); - aRoot[i] = (u32)pParse->regRoot; + assert( pParse->isCreate || pParse->nErr ); + aRoot[i] = (u32)pParse->u1.cr.regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } }else{ @@ -119586,7 +124208,7 @@ static void statInit( int nCol; /* Number of columns in index being sampled */ int nKeyCol; /* Number of key columns */ int nColUp; /* nCol rounded up for alignment */ - int n; /* Bytes of space to allocate */ + i64 n; /* Bytes of space to allocate */ sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */ #ifdef SQLITE_ENABLE_STAT4 /* Maximum number of samples. 0 if STAT4 data is not collected */ @@ -119622,7 +124244,7 @@ static void statInit( p->db = db; p->nEst = sqlite3_value_int64(argv[2]); p->nRow = 0; - p->nLimit = sqlite3_value_int64(argv[3]); + p->nLimit = sqlite3_value_int(argv[3]); p->nCol = nCol; p->nKeyCol = nKeyCol; p->nSkipAhead = 0; @@ -120755,16 +125377,6 @@ static void decodeIntArray( while( z[0]!=0 && z[0]!=' ' ) z++; while( z[0]==' ' ) z++; } - - /* Set the bLowQual flag if the peak number of rows obtained - ** from a full equality match is so large that a full table scan - ** seems likely to be faster than using the index. - */ - if( aLog[0] > 66 /* Index has more than 100 rows */ - && aLog[0] <= aLog[nOut-1] /* And only a single value seen */ - ){ - pIndex->bLowQual = 1; - } } } @@ -121003,9 +125615,9 @@ static int loadStatTbl( } pIdx->nSampleCol = nIdxCol; pIdx->mxSample = nSample; - nByte = ROUND8(sizeof(IndexSample) * nSample); - nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample; - nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ + nByte = ROUND8(sizeof64(IndexSample) * nSample); + nByte += sizeof64(tRowcnt) * nIdxCol * 3 * nSample; + nByte += nIdxCol * sizeof64(tRowcnt); /* Space for Index.aAvgEq[] */ pIdx->aSample = sqlite3DbMallocZero(db, nByte); if( pIdx->aSample==0 ){ @@ -121013,7 +125625,7 @@ static int loadStatTbl( return SQLITE_NOMEM_BKPT; } pPtr = (u8*)pIdx->aSample; - pPtr += ROUND8(nSample*sizeof(pIdx->aSample[0])); + pPtr += ROUND8(nSample*sizeof64(pIdx->aSample[0])); pSpace = (tRowcnt*)pPtr; assert( EIGHT_BYTE_ALIGNMENT( pSpace ) ); pIdx->aAvgEq = pSpace; pSpace += nIdxCol; @@ -121310,6 +125922,16 @@ static void attachFunc( ** from sqlite3_deserialize() to close database db->init.iDb and ** reopen it as a MemDB */ Btree *pNewBt = 0; + + pNew = &db->aDb[db->init.iDb]; + assert( pNew->pBt!=0 ); + if( sqlite3BtreeTxnState(pNew->pBt)!=SQLITE_TXN_NONE + || sqlite3BtreeIsInBackup(pNew->pBt) + ){ + rc = SQLITE_BUSY; + goto attach_error; + } + pVfs = sqlite3_vfs_find("memdb"); if( pVfs==0 ) return; rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNewBt, 0, SQLITE_OPEN_MAIN_DB); @@ -121319,8 +125941,7 @@ static void attachFunc( /* Both the Btree and the new Schema were allocated successfully. ** Close the old db and update the aDb[] slot with the new memdb ** values. */ - pNew = &db->aDb[db->init.iDb]; - if( ALWAYS(pNew->pBt) ) sqlite3BtreeClose(pNew->pBt); + sqlite3BtreeClose(pNew->pBt); pNew->pBt = pNewBt; pNew->pSchema = pNewSchema; }else{ @@ -121360,7 +125981,7 @@ static void attachFunc( if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ - aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); + aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(1+(i64)db->nDb)); if( aNew==0 ) return; } db->aDb = aNew; @@ -121379,6 +126000,12 @@ static void attachFunc( sqlite3_free(zErr); return; } + if( (db->flags & SQLITE_AttachWrite)==0 ){ + flags &= ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE); + flags |= SQLITE_OPEN_READONLY; + }else if( (db->flags & SQLITE_AttachCreate)==0 ){ + flags &= ~SQLITE_OPEN_CREATE; + } assert( pVfs ); flags |= SQLITE_OPEN_MAIN_DB; rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags); @@ -121430,21 +126057,19 @@ static void attachFunc( sqlite3BtreeEnterAll(db); db->init.iDb = 0; db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( db->setlkFlags & SQLITE_SETLK_BLOCK_ON_CONNECT ){ + int val = 1; + sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pNew->pBt)); + sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, &val); + } +#endif if( !REOPEN_AS_MEMDB(db) ){ rc = sqlite3Init(db, &zErrDyn); } sqlite3BtreeLeaveAll(db); assert( zErrDyn==0 || rc!=SQLITE_OK ); } -#ifdef SQLITE_USER_AUTHENTICATION - if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){ - u8 newAuth = 0; - rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); - if( newAuthauth.authLevel ){ - rc = SQLITE_AUTH_USER; - } - } -#endif if( rc ){ if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){ int iDb = db->nDb - 1; @@ -121801,7 +126426,7 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep( if( sqlite3WalkSelect(&pFix->w, pStep->pSelect) || sqlite3WalkExpr(&pFix->w, pStep->pWhere) || sqlite3WalkExprList(&pFix->w, pStep->pExprList) - || sqlite3FixSrcList(pFix, pStep->pFrom) + || sqlite3FixSrcList(pFix, pStep->pSrc) ){ return 1; } @@ -121908,7 +126533,7 @@ SQLITE_API int sqlite3_set_authorizer( sqlite3_mutex_enter(db->mutex); db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; - if( db->xAuth ) sqlite3ExpirePreparedStatements(db, 1); + sqlite3ExpirePreparedStatements(db, 1); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -121942,11 +126567,7 @@ SQLITE_PRIVATE int sqlite3AuthReadCol( int rc; /* Auth callback return code */ if( db->init.busy ) return SQLITE_OK; - rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext -#ifdef SQLITE_USER_AUTHENTICATION - ,db->auth.zAuthUser -#endif - ); + rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext); if( rc==SQLITE_DENY ){ char *z = sqlite3_mprintf("%s.%s", zTab, zCol); if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z); @@ -122053,11 +126674,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck( testcase( zArg3==0 ); testcase( pParse->zAuthContext==0 ); - rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext -#ifdef SQLITE_USER_AUTHENTICATION - ,db->auth.zAuthUser -#endif - ); + rc = db->xAuth(db->pAuthArg,code,zArg1,zArg2,zArg3,pParse->zAuthContext); if( rc==SQLITE_DENY ){ sqlite3ErrorMsg(pParse, "not authorized"); pParse->rc = SQLITE_AUTH; @@ -122169,6 +126786,7 @@ static SQLITE_NOINLINE void lockTable( } } + assert( pToplevel->nTableLock < 0x7fff0000 ); nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1); pToplevel->aTableLock = sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes); @@ -122269,10 +126887,12 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort)); if( v ){ if( pParse->bReturning ){ - Returning *pReturning = pParse->u1.pReturning; + Returning *pReturning; int addrRewind; int reg; + assert( !pParse->isCreate ); + pReturning = pParse->u1.d.pReturning; if( pReturning->nRetCol ){ sqlite3VdbeAddOp0(v, OP_FkCheck); addrRewind = @@ -122290,17 +126910,6 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ } sqlite3VdbeAddOp0(v, OP_Halt); -#if SQLITE_USER_AUTHENTICATION && !defined(SQLITE_OMIT_SHARED_CACHE) - if( pParse->nTableLock>0 && db->init.busy==0 ){ - sqlite3UserAuthInit(db); - if( db->auth.authLevelrc = SQLITE_AUTH_USER; - return; - } - } -#endif - /* The cookie mask contains one bit for each database file open. ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are ** set for each database that is used. Generate code to start a @@ -122359,7 +126968,9 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ } if( pParse->bReturning ){ - Returning *pRet = pParse->u1.pReturning; + Returning *pRet; + assert( !pParse->isCreate ); + pRet = pParse->u1.d.pReturning; if( pRet->nRetCol ){ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol); } @@ -122429,16 +127040,6 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ pParse->nested--; } -#if SQLITE_USER_AUTHENTICATION -/* -** Return TRUE if zTable is the name of the system table that stores the -** list of users and their access credentials. -*/ -SQLITE_PRIVATE int sqlite3UserAuthTable(const char *zTable){ - return sqlite3_stricmp(zTable, "sqlite_user")==0; -} -#endif - /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the @@ -122457,13 +127058,6 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); -#if SQLITE_USER_AUTHENTICATION - /* Only the admin user is allowed to know that the sqlite_user table - ** exists */ - if( db->auth.authLevelnDb; i++){ if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break; @@ -122557,6 +127151,16 @@ SQLITE_PRIVATE Table *sqlite3LocateTable( if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ pMod = sqlite3PragmaVtabRegister(db, zName); } +#ifndef SQLITE_OMIT_JSON + if( pMod==0 && sqlite3_strnicmp(zName, "json", 4)==0 ){ + pMod = sqlite3JsonVtabRegister(db, zName); + } +#endif +#ifdef SQLITE_ENABLE_CARRAY + if( pMod==0 && sqlite3_stricmp(zName, "carray")==0 ){ + pMod = sqlite3CarrayRegister(db); + } +#endif if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ testcase( pMod->pEpoTab==0 ); return pMod->pEpoTab; @@ -122600,6 +127204,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem( const char *zDb; if( p->fg.fixedSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema); + assert( iDb>=0 && iDbdb->nDb ); zDb = pParse->db->aDb[iDb].zDbSName; }else{ assert( !p->fg.isSubquery ); @@ -123191,10 +127796,16 @@ SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){ ** find the (first) offset of that column in index pIdx. Or return -1 ** if column iCol is not used in index pIdx. */ -SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){ +SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index *pIdx, int iCol){ int i; + i16 iCol16; + assert( iCol>=(-1) && iCol<=SQLITE_MAX_COLUMN ); + assert( pIdx->nColumn<=SQLITE_MAX_COLUMN*2 ); + iCol16 = iCol; for(i=0; inColumn; i++){ - if( iCol==pIdx->aiColumn[i] ) return i; + if( iCol16==pIdx->aiColumn[i] ){ + return i; + } } return -1; } @@ -123448,8 +128059,9 @@ SQLITE_PRIVATE void sqlite3StartTable( /* If the file format and encoding in the database have not been set, ** set them now. */ - reg1 = pParse->regRowid = ++pParse->nMem; - reg2 = pParse->regRoot = ++pParse->nMem; + assert( pParse->isCreate ); + reg1 = pParse->u1.cr.regRowid = ++pParse->nMem; + reg2 = pParse->u1.cr.regRoot = ++pParse->nMem; reg3 = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT); sqlite3VdbeUsesBtree(v, iDb); @@ -123464,8 +128076,8 @@ SQLITE_PRIVATE void sqlite3StartTable( ** The record created does not contain anything yet. It will be replaced ** by the real entry in code generated at sqlite3EndTable(). ** - ** The rowid for the new entry is left in register pParse->regRowid. - ** The root page number of the new table is left in reg pParse->regRoot. + ** The rowid for the new entry is left in register pParse->u1.cr.regRowid. + ** The root page of the new table is left in reg pParse->u1.cr.regRoot. ** The rowid and root page number values are needed by the code that ** sqlite3EndTable will generate. */ @@ -123476,7 +128088,7 @@ SQLITE_PRIVATE void sqlite3StartTable( #endif { assert( !pParse->bReturning ); - pParse->u1.addrCrTab = + pParse->u1.cr.addrCrTab = sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY); } sqlite3OpenSchemaTable(pParse, iDb); @@ -123485,6 +128097,9 @@ SQLITE_PRIVATE void sqlite3StartTable( sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeAddOp0(v, OP_Close); + }else if( db->init.imposterTable ){ + pTable->tabFlags |= TF_Imposter; + if( db->init.imposterTable>=2 ) pTable->tabFlags |= TF_Readonly; } /* Normal (non-error) return. */ @@ -123554,7 +128169,8 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){ sqlite3ExprListDelete(db, pList); return; } - pParse->u1.pReturning = pRet; + assert( !pParse->isCreate ); + pParse->u1.d.pReturning = pRet; pRet->pParse = pParse; pRet->pReturnEL = pList; sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet); @@ -123596,7 +128212,6 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ char *zType; Column *pCol; sqlite3 *db = pParse->db; - u8 hName; Column *aNew; u8 eType = COLTYPE_CUSTOM; u8 szEst = 1; @@ -123650,13 +128265,10 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ memcpy(z, sName.z, sName.n); z[sName.n] = 0; sqlite3Dequote(z); - hName = sqlite3StrIHash(z); - for(i=0; inCol; i++){ - if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==0 ){ - sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); - sqlite3DbFree(db, z); - return; - } + if( p->nCol && sqlite3ColumnIndex(p, z)>=0 ){ + sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); + sqlite3DbFree(db, z); + return; } aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0])); if( aNew==0 ){ @@ -123667,7 +128279,7 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ pCol = &p->aCol[p->nCol]; memset(pCol, 0, sizeof(p->aCol[0])); pCol->zCnName = z; - pCol->hName = hName; + pCol->hName = sqlite3StrIHash(z); sqlite3ColumnPropertiesFromName(p, pCol); if( sType.n==0 ){ @@ -123691,9 +128303,14 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ pCol->affinity = sqlite3AffinityType(zType, pCol); pCol->colFlags |= COLFLAG_HASTYPE; } + if( p->nCol<=0xff ){ + u8 h = pCol->hName % sizeof(p->aHx); + p->aHx[h] = p->nCol; + } p->nCol++; p->nNVCol++; - pParse->constraintName.n = 0; + assert( pParse->isCreate ); + pParse->u1.cr.constraintName.n = 0; } /* @@ -123957,15 +128574,11 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( assert( pCExpr!=0 ); sqlite3StringToId(pCExpr); if( pCExpr->op==TK_ID ){ - const char *zCName; assert( !ExprHasProperty(pCExpr, EP_IntValue) ); - zCName = pCExpr->u.zToken; - for(iCol=0; iColnCol; iCol++){ - if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){ - pCol = &pTab->aCol[iCol]; - makeColumnPartOfPrimaryKey(pParse, pCol); - break; - } + iCol = sqlite3ColumnIndex(pTab, pCExpr->u.zToken); + if( iCol>=0 ){ + pCol = &pTab->aCol[iCol]; + makeColumnPartOfPrimaryKey(pParse, pCol); } } } @@ -124017,8 +128630,10 @@ SQLITE_PRIVATE void sqlite3AddCheckConstraint( && !sqlite3BtreeIsReadonly(db->aDb[db->init.iDb].pBt) ){ pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); - if( pParse->constraintName.n ){ - sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1); + assert( pParse->isCreate ); + if( pParse->u1.cr.constraintName.n ){ + sqlite3ExprListSetName(pParse, pTab->pCheck, + &pParse->u1.cr.constraintName, 1); }else{ Token t; for(zStart++; sqlite3Isspace(zStart[0]); zStart++){} @@ -124163,8 +128778,8 @@ SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){ ** The estimate is conservative. It might be larger that what is ** really needed. */ -static int identLength(const char *z){ - int n; +static i64 identLength(const char *z){ + i64 n; for(n=0; *z; n++, z++){ if( *z=='"' ){ n++; } } @@ -124213,7 +128828,8 @@ static void identPut(char *z, int *pIdx, char *zSignedIdent){ ** from sqliteMalloc() and must be freed by the calling function. */ static char *createTableStmt(sqlite3 *db, Table *p){ - int i, k, n; + int i, k, len; + i64 n; char *zStmt; char *zSep, *zSep2, *zEnd; Column *pCol; @@ -124237,8 +128853,9 @@ static char *createTableStmt(sqlite3 *db, Table *p){ sqlite3OomFault(db); return 0; } - sqlite3_snprintf(n, zStmt, "CREATE TABLE "); - k = sqlite3Strlen30(zStmt); + assert( n>14 && n<=0x7fffffff ); + memcpy(zStmt, "CREATE TABLE ", 13); + k = 13; identPut(zStmt, &k, p->zName); zStmt[k++] = '('; for(pCol=p->aCol, i=0; inCol; i++, pCol++){ @@ -124250,13 +128867,15 @@ static char *createTableStmt(sqlite3 *db, Table *p){ /* SQLITE_AFF_REAL */ " REAL", /* SQLITE_AFF_FLEXNUM */ " NUM", }; - int len; const char *zType; - sqlite3_snprintf(n-k, &zStmt[k], zSep); - k += sqlite3Strlen30(&zStmt[k]); + len = sqlite3Strlen30(zSep); + assert( k+lenzCnName); + assert( kaffinity-SQLITE_AFF_BLOB >= 0 ); assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) ); testcase( pCol->affinity==SQLITE_AFF_BLOB ); @@ -124271,11 +128890,14 @@ static char *createTableStmt(sqlite3 *db, Table *p){ assert( pCol->affinity==SQLITE_AFF_BLOB || pCol->affinity==SQLITE_AFF_FLEXNUM || pCol->affinity==sqlite3AffinityType(zType, 0) ); + assert( k+lennColumn>=N ) return SQLITE_OK; + db = pParse->db; + assert( N>0 ); + assert( N <= SQLITE_MAX_COLUMN*2 /* tag-20250221-1 */ ); + testcase( N==2*pParse->db->aLimit[SQLITE_LIMIT_COLUMN] ); assert( pIdx->isResized==0 ); - nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N; + nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*(u64)N; zExtra = sqlite3DbMallocZero(db, nByte); if( zExtra==0 ) return SQLITE_NOMEM_BKPT; memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn); @@ -124302,7 +128929,7 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){ zExtra += sizeof(i16)*N; memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn); pIdx->aSortOrder = (u8*)zExtra; - pIdx->nColumn = N; + pIdx->nColumn = (u16)N; /* See tag-20250221-1 above for proof of safety */ pIdx->isResized = 1; return SQLITE_OK; } @@ -124468,9 +129095,9 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ ** into BTREE_BLOBKEY. */ assert( !pParse->bReturning ); - if( pParse->u1.addrCrTab ){ + if( pParse->u1.cr.addrCrTab ){ assert( v ); - sqlite3VdbeChangeP3(v, pParse->u1.addrCrTab, BTREE_BLOBKEY); + sqlite3VdbeChangeP3(v, pParse->u1.cr.addrCrTab, BTREE_BLOBKEY); } /* Locate the PRIMARY KEY index. Or, if this table was originally @@ -124556,14 +129183,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ pIdx->nColumn = pIdx->nKeyCol; continue; } - if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return; + if( resizeIndexObject(pParse, pIdx, pIdx->nKeyCol+n) ) return; for(i=0, j=pIdx->nKeyCol; inKeyCol, pPk, i) ){ testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); pIdx->aiColumn[j] = pPk->aiColumn[i]; pIdx->azColl[j] = pPk->azColl[i]; if( pPk->aSortOrder[i] ){ - /* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */ + /* See ticket https://sqlite.org/src/info/bba7b69f9849b5bf */ pIdx->bAscKeyBug = 1; } j++; @@ -124580,14 +129207,15 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ if( !hasColumn(pPk->aiColumn, nPk, i) && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++; } - if( resizeIndexObject(db, pPk, nPk+nExtra) ) return; + if( resizeIndexObject(pParse, pPk, nPk+nExtra) ) return; for(i=0, j=nPk; inCol; i++){ if( !hasColumn(pPk->aiColumn, j, i) && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ + const char *zColl = sqlite3ColumnColl(&pTab->aCol[i]); assert( jnColumn ); pPk->aiColumn[j] = i; - pPk->azColl[j] = sqlite3StrBINARY; + pPk->azColl[j] = zColl ? zColl : sqlite3StrBINARY; j++; } } @@ -124662,13 +129290,14 @@ SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){ ** restored to its original value prior to this routine returning. */ SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){ - char *zTail; /* Pointer to the last "_" in zName */ + const char *zTail; /* Pointer to the last "_" in zName */ Table *pTab; /* Table that zName is a shadow of */ + char *zCopy; zTail = strrchr(zName, '_'); if( zTail==0 ) return 0; - *zTail = 0; - pTab = sqlite3FindTable(db, zName, 0); - *zTail = '_'; + zCopy = sqlite3DbStrNDup(db, zName, (int)(zTail-zName)); + pTab = zCopy ? sqlite3FindTable(db, zCopy, 0) : 0; + sqlite3DbFree(db, zCopy); if( pTab==0 ) return 0; if( !IsVirtual(pTab) ) return 0; return sqlite3IsShadowTableOf(db, pTab, zName); @@ -124821,6 +129450,7 @@ SQLITE_PRIVATE void sqlite3EndTable( convertToWithoutRowidTable(pParse, p); } iDb = sqlite3SchemaToIndex(db, p->pSchema); + assert( iDb>=0 && iDb<=db->nDb ); #ifndef SQLITE_OMIT_CHECK /* Resolve names in all CHECK constraint expressions. @@ -124910,7 +129540,7 @@ SQLITE_PRIVATE void sqlite3EndTable( /* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT ** statement to populate the new table. The root-page number for the - ** new table is in register pParse->regRoot. + ** new table is in register pParse->u1.cr.regRoot. ** ** Once the SELECT has been coded by sqlite3Select(), it is in a ** suitable state to query for the column names and types to be used @@ -124941,7 +129571,8 @@ SQLITE_PRIVATE void sqlite3EndTable( regRec = ++pParse->nMem; regRowid = ++pParse->nMem; sqlite3MayAbort(pParse); - sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->regRoot, iDb); + assert( pParse->isCreate ); + sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->u1.cr.regRoot, iDb); sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); @@ -124986,6 +129617,7 @@ SQLITE_PRIVATE void sqlite3EndTable( ** schema table. We just need to update that slot with all ** the information we've collected. */ + assert( pParse->isCreate ); sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q" @@ -124994,9 +129626,9 @@ SQLITE_PRIVATE void sqlite3EndTable( zType, p->zName, p->zName, - pParse->regRoot, + pParse->u1.cr.regRoot, zStmt, - pParse->regRowid + pParse->u1.cr.regRowid ); sqlite3DbFree(db, zStmt); sqlite3ChangeCookie(pParse, iDb); @@ -125114,6 +129746,7 @@ SQLITE_PRIVATE void sqlite3CreateView( sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); + assert( iDb>=0 && iDbnDb ); sqlite3FixInit(&sFix, pParse, iDb, "view", pName); if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; @@ -125736,7 +130369,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( }else{ nCol = pFromCol->nExpr; } - nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1; + nByte = SZ_FKEY(nCol) + pTo->n + 1; if( pToCol ){ for(i=0; inExpr; i++){ nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1; @@ -125938,7 +130571,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ ** not work for UNIQUE constraint indexes on WITHOUT ROWID tables ** with DESC primary keys, since those indexes have there keys in ** a different order from the main table. - ** See ticket: https://www.sqlite.org/src/info/bba7b69f9849b5bf + ** See ticket: https://sqlite.org/src/info/bba7b69f9849b5bf */ sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); } @@ -125962,13 +130595,14 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ */ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( sqlite3 *db, /* Database connection */ - i16 nCol, /* Total number of columns in the index */ + int nCol, /* Total number of columns in the index */ int nExtra, /* Number of bytes of extra space to alloc */ char **ppExtra /* Pointer to the "extra" space */ ){ Index *p; /* Allocated index object */ - int nByte; /* Bytes of space for Index object + arrays */ + i64 nByte; /* Bytes of space for Index object + arrays */ + assert( nCol <= 2*db->aLimit[SQLITE_LIMIT_COLUMN] ); nByte = ROUND8(sizeof(Index)) + /* Index structure */ ROUND8(sizeof(char*)*nCol) + /* Index.azColl */ ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */ @@ -125981,8 +130615,9 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1); p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol; p->aSortOrder = (u8*)pExtra; - p->nColumn = nCol; - p->nKeyCol = nCol - 1; + assert( nCol>0 ); + p->nColumn = (u16)nCol; + p->nKeyCol = (u16)(nCol - 1); *ppExtra = ((char*)p) + nByte; } return p; @@ -126122,9 +130757,6 @@ SQLITE_PRIVATE void sqlite3CreateIndex( if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 && pTblName!=0 -#if SQLITE_USER_AUTHENTICATION - && sqlite3UserAuthTable(pTab->zName)==0 -#endif ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; @@ -126711,6 +131343,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists goto exit_drop_index; } iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); + assert( iDb>=0 && iDbnDb ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; @@ -126796,12 +131429,11 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token * sqlite3 *db = pParse->db; int i; if( pList==0 ){ - pList = sqlite3DbMallocZero(db, sizeof(IdList) ); + pList = sqlite3DbMallocZero(db, SZ_IDLIST(1)); if( pList==0 ) return 0; }else{ IdList *pNew; - pNew = sqlite3DbRealloc(db, pList, - sizeof(IdList) + pList->nId*sizeof(pList->a)); + pNew = sqlite3DbRealloc(db, pList, SZ_IDLIST(pList->nId+1)); if( pNew==0 ){ sqlite3IdListDelete(db, pList); return 0; @@ -126823,7 +131455,6 @@ SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){ int i; assert( db!=0 ); if( pList==0 ) return; - assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */ for(i=0; inId; i++){ sqlite3DbFree(db, pList->a[i].zName); } @@ -126901,8 +131532,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( return 0; } if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST; - pNew = sqlite3DbRealloc(db, pSrc, - sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) ); + pNew = sqlite3DbRealloc(db, pSrc, SZ_SRCLIST(nAlloc)); if( pNew==0 ){ assert( db->mallocFailed ); return 0; @@ -126977,7 +131607,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( assert( pParse->db!=0 ); db = pParse->db; if( pList==0 ){ - pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) ); + pList = sqlite3DbMallocRawNN(pParse->db, SZ_SRCLIST(1)); if( pList==0 ) return 0; pList->nAlloc = 1; pList->nSrc = 1; @@ -127244,16 +131874,22 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI ** are deleted by this function. */ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){ - assert( p1 && p1->nSrc==1 ); + assert( p1 ); + assert( p2 || pParse->nErr ); + assert( p2==0 || p2->nSrc>=1 ); + testcase( p1->nSrc==0 ); if( p2 ){ - SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, 1); + int nOld = p1->nSrc; + SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, nOld); if( pNew==0 ){ sqlite3SrcListDelete(pParse->db, p2); }else{ p1 = pNew; - memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(SrcItem)); + memcpy(&p1->a[nOld], p2->a, p2->nSrc*sizeof(SrcItem)); + assert( nOld==1 || (p2->a[0].fg.jointype & JT_LTORJ)==0 ); + assert( p1->nSrc>=1 ); + p1->a[0].fg.jointype |= (JT_LTORJ & p2->a[0].fg.jointype); sqlite3DbFree(pParse->db, p2); - p1->a[0].fg.jointype |= (JT_LTORJ & p1->a[1].fg.jointype); } } return p1; @@ -127605,8 +132241,7 @@ SQLITE_PRIVATE void sqlite3RowidConstraint( } /* -** Check to see if pIndex uses the collating sequence pColl. Return -** true if it does and false if it does not. +** Return true if any column of pIndex uses the zColl collation */ #ifndef SQLITE_OMIT_REINDEX static int collationMatch(const char *zColl, Index *pIndex){ @@ -127614,8 +132249,8 @@ static int collationMatch(const char *zColl, Index *pIndex){ assert( zColl!=0 ); for(i=0; inColumn; i++){ const char *z = pIndex->azColl[i]; - assert( z!=0 || pIndex->aiColumn[i]<0 ); - if( pIndex->aiColumn[i]>=0 && 0==sqlite3StrICmp(z, zColl) ){ + assert( z!=0 ); + if( 0==sqlite3StrICmp(z, zColl) ){ return 1; } } @@ -127623,73 +132258,39 @@ static int collationMatch(const char *zColl, Index *pIndex){ } #endif -/* -** Recompute all indices of pTab that use the collating sequence pColl. -** If pColl==0 then recompute all indices of pTab. -*/ -#ifndef SQLITE_OMIT_REINDEX -static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ - if( !IsVirtual(pTab) ){ - Index *pIndex; /* An index associated with pTab */ - - for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ - if( zColl==0 || collationMatch(zColl, pIndex) ){ - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3RefillIndex(pParse, pIndex, -1); - } - } - } -} -#endif - -/* -** Recompute all indices of all tables in all databases where the -** indices use the collating sequence pColl. If pColl==0 then recompute -** all indices everywhere. -*/ -#ifndef SQLITE_OMIT_REINDEX -static void reindexDatabases(Parse *pParse, char const *zColl){ - Db *pDb; /* A single database */ - int iDb; /* The database index number */ - sqlite3 *db = pParse->db; /* The database connection */ - HashElem *k; /* For looping over tables in pDb */ - Table *pTab; /* A table in the database */ - - assert( sqlite3BtreeHoldsAllMutexes(db) ); /* Needed for schema access */ - for(iDb=0, pDb=db->aDb; iDbnDb; iDb++, pDb++){ - assert( pDb!=0 ); - for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ - pTab = (Table*)sqliteHashData(k); - reindexTable(pParse, pTab, zColl); - } - } -} -#endif - /* ** Generate code for the REINDEX command. ** ** REINDEX -- 1 ** REINDEX -- 2 -** REINDEX ?.? -- 3 -** REINDEX ?.? -- 4 +** REINDEX ?.? -- 3 +** REINDEX ?.? -- 4 +** REINDEX EXPRESSIONS -- 5 ** -** Form 1 causes all indices in all attached databases to be rebuilt. -** Form 2 rebuilds all indices in all databases that use the named +** Form 1 causes all indexes in all attached databases to be rebuilt. +** Form 2 rebuilds all indexes in all databases that use the named ** collating function. Forms 3 and 4 rebuild the named index or all -** indices associated with the named table. +** indexes associated with the named table, respectively. Form 5 +** rebuilds all expression indexes in addition to all collations, +** indexes, or tables named "EXPRESSIONS". +** +** If the name is ambiguous such that it matches two or more of +** forms 2 through 5, then rebuild the union of all matching indexes, +** taken care to avoid rebuilding the same index more than once. */ #ifndef SQLITE_OMIT_REINDEX SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ - CollSeq *pColl; /* Collating sequence to be reindexed, or NULL */ - char *z; /* Name of a table or index */ - const char *zDb; /* Name of the database */ - Table *pTab; /* A table in the database */ - Index *pIndex; /* An index associated with pTab */ - int iDb; /* The database index number */ + char *z = 0; /* Name of a table or index or collation */ + const char *zDb = 0; /* Name of the database */ + int iReDb = -1; /* The database index number */ sqlite3 *db = pParse->db; /* The database connection */ Token *pObjName; /* Name of the table or index to be reindexed */ + int bMatch = 0; /* At least one name match */ + const char *zColl = 0; /* Rebuild indexes using this collation */ + Table *pReTab = 0; /* Rebuild all indexes of this table */ + Index *pReIndex = 0; /* Rebuild this index */ + int isExprIdx = 0; /* Rebuild all expression indexes */ + int bAll = 0; /* Rebuild all indexes */ /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ @@ -127698,41 +132299,66 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ } if( pName1==0 ){ - reindexDatabases(pParse, 0); - return; + /* rebuild all indexes */ + bMatch = 1; + bAll = 1; }else if( NEVER(pName2==0) || pName2->z==0 ){ - char *zColl; assert( pName1->z ); - zColl = sqlite3NameFromToken(pParse->db, pName1); - if( !zColl ) return; - pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); - if( pColl ){ - reindexDatabases(pParse, zColl); - sqlite3DbFree(db, zColl); - return; + z = sqlite3NameFromToken(pParse->db, pName1); + if( z==0 ) return; + }else{ + iReDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); + if( iReDb<0 ) return; + z = sqlite3NameFromToken(db, pObjName); + if( z==0 ) return; + zDb = db->aDb[iReDb].zDbSName; + } + if( !bAll ){ + if( zDb==0 && sqlite3StrICmp(z, "expressions")==0 ){ + isExprIdx = 1; + bMatch = 1; + } + if( zDb==0 && sqlite3FindCollSeq(db, ENC(db), z, 0)!=0 ){ + zColl = z; + bMatch = 1; + } + if( zColl==0 && (pReTab = sqlite3FindTable(db, z, zDb))!=0 ){ + bMatch = 1; + } + if( zColl==0 && (pReIndex = sqlite3FindIndex(db, z, zDb))!=0 ){ + bMatch = 1; } - sqlite3DbFree(db, zColl); } - iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); - if( iDb<0 ) return; - z = sqlite3NameFromToken(db, pObjName); - if( z==0 ) return; - zDb = pName2->n ? db->aDb[iDb].zDbSName : 0; - pTab = sqlite3FindTable(db, z, zDb); - if( pTab ){ - reindexTable(pParse, pTab, 0); - sqlite3DbFree(db, z); - return; + if( bMatch ){ + int iDb; + HashElem *k; + Table *pTab; + Index *pIdx; + Db *pDb; + for(iDb=0, pDb=db->aDb; iDbnDb; iDb++, pDb++){ + assert( pDb!=0 ); + if( iReDb>=0 && iReDb!=iDb ) continue; + for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ + pTab = (Table*)sqliteHashData(k); + if( IsVirtual(pTab) ) continue; + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( bAll + || pTab==pReTab + || pIdx==pReIndex + || (isExprIdx && pIdx->bHasExpr) + || (zColl!=0 && collationMatch(zColl,pIdx)) + ){ + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3RefillIndex(pParse, pIdx, -1); + } + } /* End loop over indexes of pTab */ + } /* End loop over tables of iDb */ + } /* End loop over databases */ + }else{ + sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); } - pIndex = sqlite3FindIndex(db, z, zDb); sqlite3DbFree(db, z); - if( pIndex ){ - iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema); - sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3RefillIndex(pParse, pIndex, -1); - return; - } - sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); + return; } #endif @@ -127764,14 +132390,19 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ } if( pParse->nErr ){ assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ ); - if( pIdx->bNoQuery==0 ){ + if( pIdx->bNoQuery==0 + && sqlite3HashFind(&pIdx->pSchema->idxHash, pIdx->zName) + ){ /* Deactivate the index because it contains an unknown collating ** sequence. The only way to reactive the index is to reload the ** schema. Adding the missing collating sequence later does not ** reactive the index. The application had the chance to register ** the missing index using the collation-needed callback. For ** simplicity, SQLite will not give the application a second chance. - */ + ** + ** Except, do not do this if the index is not in the schema hash + ** table. In this case the index is currently being constructed + ** by a CREATE INDEX statement, and retrying will not help. */ pIdx->bNoQuery = 1; pParse->rc = SQLITE_ERROR_RETRY; } @@ -127863,10 +132494,9 @@ SQLITE_PRIVATE With *sqlite3WithAdd( } if( pWith ){ - sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); - pNew = sqlite3DbRealloc(db, pWith, nByte); + pNew = sqlite3DbRealloc(db, pWith, SZ_WITH(pWith->nCte+1)); }else{ - pNew = sqlite3DbMallocZero(db, sizeof(*pWith)); + pNew = sqlite3DbMallocZero(db, SZ_WITH(1)); } assert( (pNew!=0 && zName!=0) || db->mallocFailed ); @@ -128204,12 +132834,18 @@ static int matchQuality( u8 enc /* Desired text encoding */ ){ int match; - assert( p->nArg>=-1 ); + assert( p->nArg>=(-4) && p->nArg!=(-2) ); + assert( nArg>=(-2) ); /* Wrong number of arguments means "no match" */ if( p->nArg!=nArg ){ - if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH; + if( nArg==(-2) ) return p->xSFunc==0 ? 0 : FUNC_PERFECT_MATCH; if( p->nArg>=0 ) return 0; + /* Special p->nArg values available to built-in functions only: + ** -3 1 or more arguments required + ** -4 2 or more arguments required + */ + if( p->nArg<(-2) && nArg<(-2-p->nArg) ) return 0; } /* Give a better score to a function with a specific number of arguments @@ -128403,6 +133039,7 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){ for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem)); } + sqlite3HashClear(&temp2); sqlite3HashInit(&pSchema->tblHash); for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ @@ -128531,7 +133168,7 @@ static int vtabIsReadOnly(Parse *pParse, Table *pTab){ ** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS ** virtual tables if PRAGMA trusted_schema=ON. */ - if( pParse->pToplevel!=0 + if( (pParse->pToplevel!=0 || (pParse->prepFlags & SQLITE_PREPARE_FROM_DDL)) && pTab->u.vtab.p->eVtabRisk > ((pParse->db->flags & SQLITE_TrustedSchema)!=0) ){ @@ -129368,8 +134005,9 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete( r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel, pPrior, r1); sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, - pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); - sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */ + pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn + ); + sqlite3VdbeChangeP4(v, -1, (const char*)pIdx, P4_INDEX); sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); pPrior = pIdx; } @@ -129804,9 +134442,18 @@ static void printfFunc( sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); str.printfFlags = SQLITE_PRINTF_SQLFUNC; sqlite3_str_appendf(&str, zFormat, &x); - n = str.nChar; - sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, - SQLITE_DYNAMIC); + if( str.accError==SQLITE_OK ){ + n = str.nChar; + sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, + SQLITE_DYNAMIC); + }else{ + if( str.accError==SQLITE_NOMEM ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_error_toobig(context); + } + sqlite3_str_reset(&str); + } } } @@ -129832,16 +134479,10 @@ static void substrFunc( int len; int p0type; i64 p1, p2; - int negP2 = 0; assert( argc==3 || argc==2 ); - if( sqlite3_value_type(argv[1])==SQLITE_NULL - || (argc==3 && sqlite3_value_type(argv[2])==SQLITE_NULL) - ){ - return; - } p0type = sqlite3_value_type(argv[0]); - p1 = sqlite3_value_int(argv[1]); + p1 = sqlite3_value_int64(argv[1]); if( p0type==SQLITE_BLOB ){ len = sqlite3_value_bytes(argv[0]); z = sqlite3_value_blob(argv[0]); @@ -129857,28 +134498,31 @@ static void substrFunc( } } } -#ifdef SQLITE_SUBSTR_COMPATIBILITY - /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as - ** as substr(X,1,N) - it returns the first N characters of X. This - ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8] - ** from 2009-02-02 for compatibility of applications that exploited the - ** old buggy behavior. */ - if( p1==0 ) p1 = 1; /* */ -#endif if( argc==3 ){ - p2 = sqlite3_value_int(argv[2]); - if( p2<0 ){ - p2 = -p2; - negP2 = 1; - } + p2 = sqlite3_value_int64(argv[2]); + if( p2==0 && sqlite3_value_type(argv[2])==SQLITE_NULL ) return; }else{ p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH]; } + if( p1==0 ){ +#ifdef SQLITE_SUBSTR_COMPATIBILITY + /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as + ** as substr(X,1,N) - it returns the first N characters of X. This + ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8] + ** from 2009-02-02 for compatibility of applications that exploited the + ** old buggy behavior. */ + p1 = 1; /* */ +#endif + if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return; + } if( p1<0 ){ p1 += len; if( p1<0 ){ - p2 += p1; - if( p2<0 ) p2 = 0; + if( p2<0 ){ + p2 = 0; + }else{ + p2 += p1; + } p1 = 0; } }else if( p1>0 ){ @@ -129886,12 +134530,13 @@ static void substrFunc( }else if( p2>0 ){ p2--; } - if( negP2 ){ - p1 -= p2; - if( p1<0 ){ - p2 += p1; - p1 = 0; + if( p2<0 ){ + if( p2<-p1 ){ + p2 = p1; + }else{ + p2 = -p2; } + p1 -= p2; } assert( p1>=0 && p2>=0 ); if( p0type!=SQLITE_BLOB ){ @@ -129905,9 +134550,11 @@ static void substrFunc( sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT, SQLITE_UTF8); }else{ - if( p1+p2>len ){ + if( p1>=len ){ + p1 = p2 = 0; + }else if( p2>len-p1 ){ p2 = len-p1; - if( p2<0 ) p2 = 0; + assert( p2>0 ); } sqlite3_result_blob64(context, (char*)&z[p1], (u64)p2, SQLITE_TRANSIENT); } @@ -129918,13 +134565,13 @@ static void substrFunc( */ #ifndef SQLITE_OMIT_FLOATING_POINT static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ - int n = 0; + i64 n = 0; double r; char *zBuf; assert( argc==1 || argc==2 ); if( argc==2 ){ if( SQLITE_NULL==sqlite3_value_type(argv[1]) ) return; - n = sqlite3_value_int(argv[1]); + n = sqlite3_value_int64(argv[1]); if( n>30 ) n = 30; if( n<0 ) n = 0; } @@ -129939,12 +134586,12 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ }else if( n==0 ){ r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5))); }else{ - zBuf = sqlite3_mprintf("%!.*f",n,r); + zBuf = sqlite3_mprintf("%!.*f",(int)n,r); if( zBuf==0 ){ sqlite3_result_error_nomem(context); return; } - sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8); + sqlite3AtoF(zBuf, &r); sqlite3_free(zBuf); } sqlite3_result_double(context, r); @@ -129963,7 +134610,7 @@ static void *contextMalloc(sqlite3_context *context, i64 nByte){ sqlite3 *db = sqlite3_context_db_handle(context); assert( nByte>0 ); testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH] ); - testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); + testcase( nByte==(i64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(context); z = 0; @@ -130568,7 +135215,7 @@ static const char hexdigits[] = { ** Append to pStr text that is the SQL literal representation of the ** value contained in pValue. */ -SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ +SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){ /* As currently implemented, the string must be initially empty. ** we might relax this requirement in the future, but that will ** require enhancements to the implementation. */ @@ -130576,18 +135223,11 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ switch( sqlite3_value_type(pValue) ){ case SQLITE_FLOAT: { - double r1, r2; - const char *zVal; - r1 = sqlite3_value_double(pValue); - sqlite3_str_appendf(pStr, "%!0.15g", r1); - zVal = sqlite3_str_value(pStr); - if( zVal ){ - sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8); - if( r1!=r2 ){ - sqlite3_str_reset(pStr); - sqlite3_str_appendf(pStr, "%!0.20e", r1); - } - } + /* ,--- Show infinity as 9.0e+999 + ** | + ** | ,--- 17 precision guarantees round-trip + ** v v */ + sqlite3_str_appendf(pStr, "%!0.17g", sqlite3_value_double(pValue)); break; } case SQLITE_INTEGER: { @@ -130616,7 +135256,7 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ } case SQLITE_TEXT: { const unsigned char *zArg = sqlite3_value_text(pValue); - sqlite3_str_appendf(pStr, "%Q", zArg); + sqlite3_str_appendf(pStr, bEscape ? "%#Q" : "%Q", zArg); break; } default: { @@ -130627,6 +135267,105 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ } } +/* +** Return true if z[] begins with N hexadecimal digits, and write +** a decoding of those digits into *pVal. Or return false if any +** one of the first N characters in z[] is not a hexadecimal digit. +*/ +static int isNHex(const char *z, int N, u32 *pVal){ + int i; + u32 v = 0; + for(i=0; i0 ){ + memmove(&zOut[j], &zIn[i], n); + j += n; + i += n; + } + if( zIn[i+1]=='\\' ){ + i += 2; + zOut[j++] = '\\'; + }else if( sqlite3Isxdigit(zIn[i+1]) ){ + if( !isNHex(&zIn[i+1], 4, &v) ) goto unistr_error; + i += 5; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else if( zIn[i+1]=='+' ){ + if( !isNHex(&zIn[i+2], 6, &v) ) goto unistr_error; + i += 8; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else if( zIn[i+1]=='u' ){ + if( !isNHex(&zIn[i+2], 4, &v) ) goto unistr_error; + i += 6; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else if( zIn[i+1]=='U' ){ + if( !isNHex(&zIn[i+2], 8, &v) ) goto unistr_error; + i += 10; + j += sqlite3AppendOneUtf8Character(&zOut[j], v); + }else{ + goto unistr_error; + } + } + zOut[j] = 0; + sqlite3_result_text64(context, zOut, j, sqlite3_free, SQLITE_UTF8_ZT); + return; + +unistr_error: + sqlite3_free(zOut); + sqlite3_result_error(context, "invalid Unicode escape", -1); + return; +} + + /* ** Implementation of the QUOTE() function. ** @@ -130636,6 +135375,10 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ ** as needed. BLOBs are encoded as hexadecimal literals. Strings with ** embedded NUL characters cannot be represented as string literals in SQL ** and hence the returned string literal is truncated prior to the first NUL. +** +** If sqlite3_user_data() is non-zero, then the UNISTR_QUOTE() function is +** implemented instead. The difference is that UNISTR_QUOTE() uses the +** UNISTR() function to escape control characters. */ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_str str; @@ -130643,7 +135386,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ assert( argc==1 ); UNUSED_PARAMETER(argc); sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); - sqlite3QuoteValue(&str,argv[0]); + sqlite3QuoteValue(&str,argv[0],SQLITE_PTR_TO_INT(sqlite3_user_data(context))); sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar, SQLITE_DYNAMIC); if( str.accError!=SQLITE_OK ){ @@ -130706,7 +135449,7 @@ static void charFunc( } \ } *zOut = 0; - sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8); + sqlite3_result_text64(context, (char*)z, zOut-z,sqlite3_free,SQLITE_UTF8_ZT); } /* @@ -130735,7 +135478,7 @@ static void hexFunc( } *z = 0; sqlite3_result_text64(context, zHex, (u64)(z-zHex), - sqlite3_free, SQLITE_UTF8); + sqlite3_free, SQLITE_UTF8_ZT); } } @@ -130898,7 +135641,7 @@ static void replaceFunc( assert( zRep==sqlite3_value_text(argv[2]) ); nOut = nStr + 1; assert( nOut0 ){ + if( sqlite3_value_type(argv[i])!=SQLITE_NULL ){ + int k = sqlite3_value_bytes(argv[i]); const char *v = (const char*)sqlite3_value_text(argv[i]); if( v!=0 ){ - if( j>0 && nSep>0 ){ + if( bNotNull && nSep>0 ){ memcpy(&z[j], zSep, nSep); j += nSep; } memcpy(&z[j], v, k); j += k; + bNotNull = 1; } } } z[j] = 0; assert( j<=n ); - sqlite3_result_text64(context, z, j, sqlite3_free, SQLITE_UTF8); + sqlite3_result_text64(context, z, j, sqlite3_free, SQLITE_UTF8_ZT); } /* @@ -131294,7 +136039,7 @@ static void kahanBabuskaNeumaierInit( ** that it returns NULL if it sums over no inputs. TOTAL returns ** 0.0 in that case. In addition, TOTAL always returns a float where ** SUM might return an integer if it never encounters a floating point -** value. TOTAL never fails, but SUM might through an exception if +** value. TOTAL never fails, but SUM might throw an exception if ** it overflows an integer. */ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ @@ -131346,8 +136091,16 @@ static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){ assert( p->cnt>0 ); p->cnt--; if( !p->approx ){ - p->iSum -= sqlite3_value_int64(argv[0]); - }else if( type==SQLITE_INTEGER ){ + i64 x = p->iSum; + if( sqlite3SubInt64(&x, sqlite3_value_int64(argv[0]))==0 ){ + p->iSum = x; + return; + } + p->ovrfl = 1; + p->approx = 1; + kahanBabuskaNeumaierInit(p, p->iSum); + } + if( type==SQLITE_INTEGER ){ i64 iVal = sqlite3_value_int64(argv[0]); if( iVal!=SMALLEST_INT64 ){ kahanBabuskaNeumaierStepInt64(p, -iVal); @@ -131734,6 +136487,8 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive) sqlite3CreateFunc(db, "like", nArg, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); pDef = sqlite3FindFunction(db, "like", nArg, SQLITE_UTF8, 0); + assert( pDef!=0 ); /* The sqlite3CreateFunc() call above cannot fail + ** because the "like" SQL-function already exists */ pDef->funcFlags |= flags; pDef->funcFlags &= ~SQLITE_FUNC_UNSAFE; } @@ -132008,6 +136763,501 @@ static void signFunc( sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0); } +#if defined(SQLITE_ENABLE_PERCENTILE) +/*********************************************************************** +** This section implements the percentile(Y,P) SQL function and similar. +** Requirements: +** +** (1) The percentile(Y,P) function is an aggregate function taking +** exactly two arguments. +** +** (2) If the P argument to percentile(Y,P) is not the same for every +** row in the aggregate then an error is thrown. The word "same" +** in the previous sentence means that the value differ by less +** than 0.001. +** +** (3) If the P argument to percentile(Y,P) evaluates to anything other +** than a number in the range of 0.0 to 100.0 inclusive then an +** error is thrown. +** +** (4) If any Y argument to percentile(Y,P) evaluates to a value that +** is not NULL and is not numeric then an error is thrown. +** +** (5) If any Y argument to percentile(Y,P) evaluates to plus or minus +** infinity then an error is thrown. (SQLite always interprets NaN +** values as NULL.) +** +** (6) Both Y and P in percentile(Y,P) can be arbitrary expressions, +** including CASE WHEN expressions. +** +** (7) The percentile(Y,P) aggregate is able to handle inputs of at least +** one million (1,000,000) rows. +** +** (8) If there are no non-NULL values for Y, then percentile(Y,P) +** returns NULL. +** +** (9) If there is exactly one non-NULL value for Y, the percentile(Y,P) +** returns the one Y value. +** +** (10) If there N non-NULL values of Y where N is two or more and +** the Y values are ordered from least to greatest and a graph is +** drawn from 0 to N-1 such that the height of the graph at J is +** the J-th Y value and such that straight lines are drawn between +** adjacent Y values, then the percentile(Y,P) function returns +** the height of the graph at P*(N-1)/100. +** +** (11) The percentile(Y,P) function always returns either a floating +** point number or NULL. +** +** (12) The percentile(Y,P) is implemented as a single C99 source-code +** file that compiles into a shared-library or DLL that can be loaded +** into SQLite using the sqlite3_load_extension() interface. +** +** (13) A separate median(Y) function is the equivalent percentile(Y,50). +** +** (14) A separate percentile_cont(Y,P) function is equivalent to +** percentile(Y,P/100.0). In other words, the fraction value in +** the second argument is in the range of 0 to 1 instead of 0 to 100. +** +** (15) A separate percentile_disc(Y,P) function is like +** percentile_cont(Y,P) except that instead of returning the weighted +** average of the nearest two input values, it returns the next lower +** value. So the percentile_disc(Y,P) will always return a value +** that was one of the inputs. +** +** (16) All of median(), percentile(Y,P), percentile_cont(Y,P) and +** percentile_disc(Y,P) can be used as window functions. +** +** Differences from standard SQL: +** +** * The percentile_cont(X,P) function is equivalent to the following in +** standard SQL: +** +** (percentile_cont(P) WITHIN GROUP (ORDER BY X)) +** +** The SQLite syntax is much more compact. The standard SQL syntax +** is also supported if SQLite is compiled with the +** -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES option. +** +** * No median(X) function exists in the SQL standard. App developers +** are expected to write "percentile_cont(0.5)WITHIN GROUP(ORDER BY X)". +** +** * No percentile(Y,P) function exists in the SQL standard. Instead of +** percential(Y,P), developers must write this: +** "percentile_cont(P/100.0) WITHIN GROUP (ORDER BY Y)". Note that +** the fraction parameter to percentile() goes from 0 to 100 whereas +** the fraction parameter in SQL standard percentile_cont() goes from +** 0 to 1. +** +** Implementation notes as of 2024-08-31: +** +** * The regular aggregate-function versions of these routines work +** by accumulating all values in an array of doubles, then sorting +** that array using quicksort before computing the answer. Thus +** the runtime is O(NlogN) where N is the number of rows of input. +** +** * For the window-function versions of these routines, the array of +** inputs is sorted as soon as the first value is computed. Thereafter, +** the array is kept in sorted order using an insert-sort. This +** results in O(N*K) performance where K is the size of the window. +** One can imagine alternative implementations that give O(N*logN*logK) +** performance, but they require more complex logic and data structures. +** The developers have elected to keep the asymptotically slower +** algorithm for now, for simplicity, under the theory that window +** functions are seldom used and when they are, the window size K is +** often small. The developers might revisit that decision later, +** should the need arise. +*/ + +/* The following object is the group context for a single percentile() +** aggregate. Remember all input Y values until the very end. +** Those values are accumulated in the Percentile.a[] array. +*/ +typedef struct Percentile Percentile; +struct Percentile { + u64 nAlloc; /* Number of slots allocated for a[] */ + u64 nUsed; /* Number of slots actually used in a[] */ + char bSorted; /* True if a[] is already in sorted order */ + char bKeepSorted; /* True if advantageous to keep a[] sorted */ + char bPctValid; /* True if rPct is valid */ + double rPct; /* Fraction. 0.0 to 1.0 */ + double *a; /* Array of Y values */ +}; + +/* +** Return TRUE if the input floating-point number is an infinity. +*/ +static int percentIsInfinity(double r){ + sqlite3_uint64 u; + assert( sizeof(u)==sizeof(r) ); + memcpy(&u, &r, sizeof(u)); + return ((u>>52)&0x7ff)==0x7ff; +} + +/* +** Return TRUE if two doubles differ by 0.001 or less. +*/ +static int percentSameValue(double a, double b){ + a -= b; + return a>=-0.001 && a<=0.001; +} + +/* +** Search p (which must have p->bSorted) looking for an entry with +** value y. Return the index of that entry. +** +** If bExact is true, return -1 if the entry is not found. +** +** If bExact is false, return the index at which a new entry with +** value y should be insert in order to keep the values in sorted +** order. The smallest return value in this case will be 0, and +** the largest return value will be p->nUsed. +*/ +static i64 percentBinarySearch(Percentile *p, double y, int bExact){ + i64 iFirst = 0; /* First element of search range */ + i64 iLast = (i64)p->nUsed - 1; /* Last element of search range */ + while( iLast>=iFirst ){ + i64 iMid = (iFirst+iLast)/2; + double x = p->a[iMid]; + if( xy ){ + iLast = iMid - 1; + }else{ + return iMid; + } + } + if( bExact ) return -1; + return iFirst; +} + +/* +** Generate an error for a percentile function. +** +** The error format string must have exactly one occurrence of "%%s()" +** (with two '%' characters). That substring will be replaced by the name +** of the function. +*/ +static void percentError(sqlite3_context *pCtx, const char *zFormat, ...){ + char *zMsg1; + char *zMsg2; + va_list ap; + + va_start(ap, zFormat); + zMsg1 = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + zMsg2 = zMsg1 ? sqlite3_mprintf(zMsg1, sqlite3VdbeFuncName(pCtx)) : 0; + sqlite3_result_error(pCtx, zMsg2, -1); + sqlite3_free(zMsg1); + sqlite3_free(zMsg2); +} + +/* +** The "step" function for percentile(Y,P) is called once for each +** input row. +*/ +static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){ + Percentile *p; + double rPct; + int eType; + double y; + assert( argc==2 || argc==1 ); + + if( argc==1 ){ + /* Requirement 13: median(Y) is the same as percentile(Y,50). */ + rPct = 0.5; + }else{ + /* P must be a number between 0 and 100 for percentile() or between + ** 0.0 and 1.0 for percentile_cont() and percentile_disc(). + ** + ** The user-data is an integer which is 10 times the upper bound. + */ + double mxFrac = (SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx))&2)? 100.0 : 1.0; + eType = sqlite3_value_numeric_type(argv[1]); + rPct = sqlite3_value_double(argv[1])/mxFrac; + if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT) + || rPct<0.0 || rPct>1.0 + ){ + percentError(pCtx, "the fraction argument to %%s()" + " is not between 0.0 and %.1f", + (double)mxFrac); + return; + } + } + + /* Allocate the session context. */ + p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p==0 ) return; + + /* Remember the P value. Throw an error if the P value is different + ** from any prior row, per Requirement (2). */ + if( !p->bPctValid ){ + p->rPct = rPct; + p->bPctValid = 1; + }else if( !percentSameValue(p->rPct,rPct) ){ + percentError(pCtx, "the fraction argument to %%s()" + " is not the same for all input rows"); + return; + } + + /* Ignore rows for which Y is NULL */ + eType = sqlite3_value_type(argv[0]); + if( eType==SQLITE_NULL ) return; + + /* If not NULL, then Y must be numeric. Otherwise throw an error. + ** Requirement 4 */ + if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){ + percentError(pCtx, "input to %%s() is not numeric"); + return; + } + + /* Throw an error if the Y value is infinity or NaN */ + y = sqlite3_value_double(argv[0]); + if( percentIsInfinity(y) ){ + percentError(pCtx, "Inf input to %%s()"); + return; + } + + /* Allocate and store the Y */ + if( p->nUsed>=p->nAlloc ){ + u64 n = p->nAlloc*2 + 250; + double *a = sqlite3_realloc64(p->a, sizeof(double)*n); + if( a==0 ){ + sqlite3_free(p->a); + memset(p, 0, sizeof(*p)); + sqlite3_result_error_nomem(pCtx); + return; + } + p->nAlloc = n; + p->a = a; + } + if( p->nUsed==0 ){ + p->a[p->nUsed++] = y; + p->bSorted = 1; + }else if( !p->bSorted || y>=p->a[p->nUsed-1] ){ + p->a[p->nUsed++] = y; + }else if( p->bKeepSorted ){ + i64 i; + i = percentBinarySearch(p, y, 0); + if( i<(int)p->nUsed ){ + memmove(&p->a[i+1], &p->a[i], (p->nUsed-i)*sizeof(p->a[0])); + } + p->a[i] = y; + p->nUsed++; + }else{ + p->a[p->nUsed++] = y; + p->bSorted = 0; + } +} + +/* +** Interchange two doubles. +*/ +#define SWAP_DOUBLE(X,Y) {double ttt=(X);(X)=(Y);(Y)=ttt;} + +/* +** Sort an array of doubles. +** +** Algorithm: quicksort +** +** This is implemented separately rather than using the qsort() routine +** from the standard library because: +** +** (1) To avoid a dependency on qsort() +** (2) To avoid the function call to the comparison routine for each +** comparison. +*/ +static void percentSort(double *a, unsigned int n){ + int iLt; /* Entries before a[iLt] are less than rPivot */ + int iGt; /* Entries at or after a[iGt] are greater than rPivot */ + int i; /* Loop counter */ + double rPivot; /* The pivot value */ + + while( n>=2 ){ + if( a[0]>a[n-1] ){ + SWAP_DOUBLE(a[0],a[n-1]) + } + if( n==2 ) return; + iGt = n-1; + i = n/2; + if( a[0]>a[i] ){ + SWAP_DOUBLE(a[0],a[i]) + }else if( a[i]>a[iGt] ){ + SWAP_DOUBLE(a[i],a[iGt]) + } + if( n==3 ) return; + rPivot = a[i]; + iLt = i = 1; + do{ + if( a[i]iLt ) SWAP_DOUBLE(a[i],a[iLt]) + iLt++; + i++; + }else if( a[i]>rPivot ){ + do{ + iGt--; + }while( iGt>i && a[iGt]>rPivot ); + SWAP_DOUBLE(a[i],a[iGt]) + }else{ + i++; + } + }while( i(int)(n/2) ){ + if( n-iGt>=2 ) percentSort(a+iGt, n-iGt); + n = iLt; + }else{ + if( iLt>=2 ) percentSort(a, iLt); + a += iGt; + n -= iGt; + } + } +} + +/* +** The "inverse" function for percentile(Y,P) is called to remove a +** row that was previously inserted by "step". +*/ +static void percentInverse(sqlite3_context *pCtx,int argc,sqlite3_value **argv){ + Percentile *p; + int eType; + double y; + i64 i; + assert( argc==2 || argc==1 ); + + /* Allocate the session context. */ + p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + assert( p!=0 ); + + /* Ignore rows for which Y is NULL */ + eType = sqlite3_value_type(argv[0]); + if( eType==SQLITE_NULL ) return; + + /* If not NULL, then Y must be numeric. Otherwise throw an error. + ** Requirement 4 */ + if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){ + return; + } + + /* Ignore the Y value if it is infinity or NaN */ + y = sqlite3_value_double(argv[0]); + if( percentIsInfinity(y) ){ + return; + } + if( p->bSorted==0 ){ + assert( p->nUsed>1 ); + percentSort(p->a, p->nUsed); + p->bSorted = 1; + } + p->bKeepSorted = 1; + + /* Find and remove the row */ + i = percentBinarySearch(p, y, 1); + if( i>=0 ){ + p->nUsed--; + if( i<(int)p->nUsed ){ + memmove(&p->a[i], &p->a[i+1], (p->nUsed - i)*sizeof(p->a[0])); + } + } +} + +/* +** Compute the final output of percentile(). Clean up all allocated +** memory if and only if bIsFinal is true. +*/ +static void percentCompute(sqlite3_context *pCtx, int bIsFinal){ + Percentile *p; + int settings = SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx))&1; /* Discrete? */ + unsigned i1, i2; + double v1, v2; + double ix, vx; + p = (Percentile*)sqlite3_aggregate_context(pCtx, 0); + if( p==0 ) return; + if( p->a==0 ) return; + if( p->nUsed ){ + if( p->bSorted==0 ){ + assert( p->nUsed>1 ); + percentSort(p->a, p->nUsed); + p->bSorted = 1; + } + ix = p->rPct*(p->nUsed-1); + i1 = (unsigned)ix; + if( settings & 1 ){ + vx = p->a[i1]; + }else{ + i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1; + v1 = p->a[i1]; + v2 = p->a[i2]; + vx = v1 + (v2-v1)*(ix-i1); + } + sqlite3_result_double(pCtx, vx); + } + if( bIsFinal ){ + sqlite3_free(p->a); + memset(p, 0, sizeof(*p)); + }else{ + p->bKeepSorted = 1; + } +} +static void percentFinal(sqlite3_context *pCtx){ + percentCompute(pCtx, 1); +} +static void percentValue(sqlite3_context *pCtx){ + percentCompute(pCtx, 0); +} +/****** End of percentile family of functions ******/ +#endif /* SQLITE_ENABLE_PERCENTILE */ + +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT) +/* +** Implementation of sqlite_filestat(SCHEMA). +** +** Return JSON text that describes low-level debug/diagnostic information +** about the sqlite3_file object associated with SCHEMA. +*/ +static void filestatFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + const char *zDbName; + sqlite3_str *pStr; + Btree *pBtree; + + zDbName = (const char*)sqlite3_value_text(argv[0]); + pBtree = sqlite3DbNameToBtree(db, zDbName); + if( pBtree ){ + Pager *pPager; + sqlite3_file *fd; + int rc; + sqlite3BtreeEnter(pBtree); + pPager = sqlite3BtreePager(pBtree); + assert( pPager!=0 ); + fd = sqlite3PagerFile(pPager); + pStr = sqlite3_str_new(db); + if( pStr==0 ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_str_append(pStr, "{\"db\":", 6); + rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_FILESTAT, pStr); + if( rc ) sqlite3_str_append(pStr, "null", 4); + fd = sqlite3PagerJrnlFile(pPager); + if( fd && fd->pMethods!=0 ){ + sqlite3_str_appendall(pStr, ",\"journal\":"); + rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_FILESTAT, pStr); + if( rc ) sqlite3_str_append(pStr, "null", 4); + } + sqlite3_str_append(pStr, "}", 1); + sqlite3_result_text(context, sqlite3_str_finish(pStr), -1, + sqlite3_free); + } + sqlite3BtreeLeave(pBtree); + }else{ + sqlite3_result_text(context, "{}", 2, SQLITE_STATIC); + } +} +#endif /* SQLITE_DEBUG || SQLITE_ENABLE_FILESTAT */ + #ifdef SQLITE_DEBUG /* ** Implementation of fpdecode(x,y,z) function. @@ -132156,9 +137406,6 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ SFUNCTION(load_extension, 1, 0, 0, loadExt ), SFUNCTION(load_extension, 2, 0, 0, loadExt ), #endif -#if SQLITE_USER_AUTHENTICATION - FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ), -#endif #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), @@ -132168,6 +137415,9 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC INLINE_FUNC(sqlite_offset, 1, INLINEFUNC_sqlite_offset, 0 ), +#endif +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT) + FUNCTION(sqlite_filestat, 1, 0, 0, filestatFunc ), #endif FUNCTION(ltrim, 1, 1, 0, trimFunc ), FUNCTION(ltrim, 2, 1, 0, trimFunc ), @@ -132175,12 +137425,10 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(rtrim, 2, 2, 0, trimFunc ), FUNCTION(trim, 1, 3, 0, trimFunc ), FUNCTION(trim, 2, 3, 0, trimFunc ), - FUNCTION(min, -1, 0, 1, minmaxFunc ), - FUNCTION(min, 0, 0, 1, 0 ), + FUNCTION(min, -3, 0, 1, minmaxFunc ), WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), - FUNCTION(max, -1, 1, 1, minmaxFunc ), - FUNCTION(max, 0, 1, 1, 0 ), + FUNCTION(max, -3, 1, 1, minmaxFunc ), WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), @@ -132207,11 +137455,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(hex, 1, 0, 0, hexFunc ), FUNCTION(unhex, 1, 0, 0, unhexFunc ), FUNCTION(unhex, 2, 0, 0, unhexFunc ), - FUNCTION(concat, -1, 0, 0, concatFunc ), - FUNCTION(concat, 0, 0, 0, 0 ), - FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ), - FUNCTION(concat_ws, 0, 0, 0, 0 ), - FUNCTION(concat_ws, 1, 0, 0, 0 ), + FUNCTION(concat, -3, 0, 0, concatFunc ), + FUNCTION(concat_ws, -4, 0, 0, concatwsFunc ), INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ), VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), @@ -132219,7 +137464,9 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ), DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), + FUNCTION(unistr, 1, 0, 0, unistrFunc ), FUNCTION(quote, 1, 0, 0, quoteFunc ), + FUNCTION(unistr_quote, 1, 1, 0, quoteFunc ), VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid), VFUNCTION(changes, 0, 0, 0, changes ), VFUNCTION(total_changes, 0, 0, 0, total_changes ), @@ -132244,6 +137491,21 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ WAGGREGATE(string_agg, 2, 0, 0, groupConcatStep, groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), +#ifdef SQLITE_ENABLE_PERCENTILE + WAGGREGATE(median, 1, 0,0, percentStep, + percentFinal, percentValue, percentInverse, + SQLITE_INNOCUOUS|SQLITE_SELFORDER1), + WAGGREGATE(percentile, 2, 0x2,0, percentStep, + percentFinal, percentValue, percentInverse, + SQLITE_INNOCUOUS|SQLITE_SELFORDER1), + WAGGREGATE(percentile_cont, 2, 0,0, percentStep, + percentFinal, percentValue, percentInverse, + SQLITE_INNOCUOUS|SQLITE_SELFORDER1), + WAGGREGATE(percentile_disc, 2, 0x1,0, percentStep, + percentFinal, percentValue, percentInverse, + SQLITE_INNOCUOUS|SQLITE_SELFORDER1), +#endif /* SQLITE_ENABLE_PERCENTILE */ + LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #ifdef SQLITE_CASE_SENSITIVE_LIKE LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), @@ -132255,8 +137517,6 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION FUNCTION(unknown, -1, 0, 0, unknownFunc ), #endif - FUNCTION(coalesce, 1, 0, 0, 0 ), - FUNCTION(coalesce, 0, 0, 0, 0 ), #ifdef SQLITE_ENABLE_MATH_FUNCTIONS MFUNCTION(ceil, 1, xCeil, ceilingFunc ), MFUNCTION(ceiling, 1, xCeil, ceilingFunc ), @@ -132294,8 +137554,9 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ MFUNCTION(pi, 0, 0, piFunc ), #endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ FUNCTION(sign, 1, 0, 0, signFunc ), - INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ), - INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ), + INLINE_FUNC(coalesce, -4, INLINEFUNC_coalesce, 0 ), + INLINE_FUNC(iif, -4, INLINEFUNC_iif, 0 ), + INLINE_FUNC(if, -4, INLINEFUNC_iif, 0 ), }; #ifndef SQLITE_OMIT_ALTERTABLE sqlite3AlterFunctions(); @@ -133015,6 +138276,7 @@ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *pTab){ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ if( p ){ TriggerStep *pStep = p->step_list; + sqlite3SrcListDelete(dbMem, pStep->pSrc); sqlite3ExprDelete(dbMem, pStep->pWhere); sqlite3ExprListDelete(dbMem, pStep->pExprList); sqlite3SelectDelete(dbMem, pStep->pSelect); @@ -133234,6 +138496,7 @@ SQLITE_PRIVATE void sqlite3FkCheck( if( !IsOrdinaryTable(pTab) ) return; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iDb>=00 && iDbnDb ); zDb = db->aDb[iDb].zDbSName; /* Loop through all the foreign key constraints for which pTab is the @@ -133651,7 +138914,6 @@ static Trigger *fkActionTrigger( nFrom = sqlite3Strlen30(zFrom); if( action==OE_Restrict ){ - int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); SrcList *pSrc; Expr *pRaise; @@ -133662,10 +138924,10 @@ static Trigger *fkActionTrigger( } pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pSrc ){ - assert( pSrc->nSrc==1 ); - pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom); - assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 ); - pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); + SrcItem *pItem = &pSrc->a[0]; + pItem->zName = sqlite3DbStrDup(db, zFrom); + pItem->fg.fixedSchema = 1; + pItem->u4.pSchema = pTab->pSchema; } pSelect = sqlite3SelectNew(pParse, sqlite3ExprListAppend(pParse, 0, pRaise), @@ -133681,14 +138943,17 @@ static Trigger *fkActionTrigger( pTrigger = (Trigger *)sqlite3DbMallocZero(db, sizeof(Trigger) + /* struct Trigger */ - sizeof(TriggerStep) + /* Single step in trigger program */ - nFrom + 1 /* Space for pStep->zTarget */ + sizeof(TriggerStep) /* Single step in trigger program */ ); if( pTrigger ){ pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1]; - pStep->zTarget = (char *)&pStep[1]; - memcpy((char *)pStep->zTarget, zFrom, nFrom); - + pStep->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); + if( pStep->pSrc ){ + SrcItem *pItem = &pStep->pSrc->a[0]; + pItem->zName = sqlite3DbStrNDup(db, zFrom, nFrom); + pItem->u4.pSchema = pTab->pSchema; + pItem->fg.fixedSchema = 1; + } pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE); pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); @@ -133999,12 +139264,15 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ ** by one slot and insert a new OP_TypeCheck where the current ** OP_MakeRecord is found */ VdbeOp *pPrev; + int p3; sqlite3VdbeAppendP4(v, pTab, P4_TABLE); pPrev = sqlite3VdbeGetLastOp(v); assert( pPrev!=0 ); assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed ); pPrev->opcode = OP_TypeCheck; - sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, pPrev->p3); + p3 = pPrev->p3; + pPrev->p3 = 0; + sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, p3); }else{ /* Insert an isolated OP_Typecheck */ sqlite3VdbeAddOp2(v, OP_TypeCheck, iReg, pTab->nNVCol); @@ -134507,7 +139775,7 @@ SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList f = (f & pLeft->selFlags); } pSelect = sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0); - pLeft->selFlags &= ~SF_MultiValue; + pLeft->selFlags &= ~(u32)SF_MultiValue; if( pSelect ){ pSelect->op = TK_ALL; pSelect->pPrior = pLeft; @@ -134741,6 +140009,7 @@ SQLITE_PRIVATE void sqlite3Insert( int regRowid; /* registers holding insert rowid */ int regData; /* register holding first column to insert */ int *aRegIdx = 0; /* One register allocated to each index */ + int *aTabColMap = 0; /* Mapping from pTab columns to pCol entries */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to insert into a view */ @@ -134885,31 +140154,25 @@ SQLITE_PRIVATE void sqlite3Insert( */ bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0; if( pColumn ){ - assert( pColumn->eU4!=EU4_EXPR ); - pColumn->eU4 = EU4_IDX; + aTabColMap = sqlite3DbMallocZero(db, pTab->nCol*sizeof(int)); + if( aTabColMap==0 ) goto insert_cleanup; for(i=0; inId; i++){ - pColumn->a[i].u4.idx = -1; - } - for(i=0; inId; i++){ - for(j=0; jnCol; j++){ - if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){ - pColumn->a[i].u4.idx = j; - if( i!=j ) bIdListInOrder = 0; - if( j==pTab->iPKey ){ - ipkColumn = i; assert( !withoutRowid ); - } + j = sqlite3ColumnIndex(pTab, pColumn->a[i].zName); + if( j>=0 ){ + if( aTabColMap[j]==0 ) aTabColMap[j] = i+1; + if( i!=j ) bIdListInOrder = 0; + if( j==pTab->iPKey ){ + ipkColumn = i; assert( !withoutRowid ); + } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ - sqlite3ErrorMsg(pParse, - "cannot INSERT into generated column \"%s\"", - pTab->aCol[j].zCnName); - goto insert_cleanup; - } -#endif - break; + if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ + sqlite3ErrorMsg(pParse, + "cannot INSERT into generated column \"%s\"", + pTab->aCol[j].zCnName); + goto insert_cleanup; } - } - if( j>=pTab->nCol ){ +#endif + }else{ if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){ ipkColumn = i; bIdListInOrder = 0; @@ -135207,7 +140470,7 @@ SQLITE_PRIVATE void sqlite3Insert( continue; }else if( pColumn==0 ){ /* Hidden columns that are not explicitly named in the INSERT - ** get there default value */ + ** get their default value */ sqlite3ExprCodeFactorable(pParse, sqlite3ColumnExpr(pTab, &pTab->aCol[i]), iRegStore); @@ -135215,9 +140478,9 @@ SQLITE_PRIVATE void sqlite3Insert( } } if( pColumn ){ - assert( pColumn->eU4==EU4_IDX ); - for(j=0; jnId && pColumn->a[j].u4.idx!=i; j++){} - if( j>=pColumn->nId ){ + j = aTabColMap[i]; + assert( j>=0 && j<=pColumn->nId ); + if( j==0 ){ /* A column not named in the insert column list gets its ** default value */ sqlite3ExprCodeFactorable(pParse, @@ -135225,7 +140488,7 @@ SQLITE_PRIVATE void sqlite3Insert( iRegStore); continue; } - k = j; + k = j - 1; }else if( nColumn==0 ){ /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */ sqlite3ExprCodeFactorable(pParse, @@ -135470,7 +140733,10 @@ SQLITE_PRIVATE void sqlite3Insert( sqlite3ExprListDelete(db, pList); sqlite3UpsertDelete(db, pUpsert); sqlite3SelectDelete(db, pSelect); - sqlite3IdListDelete(db, pColumn); + if( pColumn ){ + sqlite3IdListDelete(db, pColumn); + sqlite3DbFree(db, aTabColMap); + } if( aRegIdx ) sqlite3DbNNFreeNN(db, aRegIdx); } @@ -135929,7 +141195,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** could happen in any order, but they are grouped up front for ** convenience. ** - ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43 + ** 2018-08-14: Ticket https://sqlite.org/src/info/908f001483982c43 ** The order of constraints used to have OE_Update as (2) and OE_Abort ** and so forth as (1). But apparently PostgreSQL checks the OE_Update ** constraint before any others, so it had to be moved. @@ -137739,6 +143005,16 @@ struct sqlite3_api_routines { /* Version 3.44.0 and later */ void *(*get_clientdata)(sqlite3*,const char*); int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); + /* Version 3.50.0 and later */ + int (*setlk_timeout)(sqlite3*,int,int); + /* Version 3.51.0 and later */ + int (*set_errmsg)(sqlite3*,int,const char*); + int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int); + /* Version 3.52.0 and later */ + void (*str_truncate)(sqlite3_str*,int); + void (*str_free)(sqlite3_str*); + int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*)); + int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*); }; /* @@ -138072,6 +143348,16 @@ typedef int (*sqlite3_loadext_entry)( /* Version 3.44.0 and later */ #define sqlite3_get_clientdata sqlite3_api->get_clientdata #define sqlite3_set_clientdata sqlite3_api->set_clientdata +/* Version 3.50.0 and later */ +#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout +/* Version 3.51.0 and later */ +#define sqlite3_set_errmsg sqlite3_api->set_errmsg +#define sqlite3_db_status64 sqlite3_api->db_status64 +/* Version 3.52.0 and later */ +#define sqlite3_str_truncate sqlite3_api->str_truncate +#define sqlite3_str_free sqlite3_api->str_free +#define sqlite3_carray_bind sqlite3_api->carray_bind +#define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2 #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -138593,7 +143879,22 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_stmt_explain, /* Version 3.44.0 and later */ sqlite3_get_clientdata, - sqlite3_set_clientdata + sqlite3_set_clientdata, + /* Version 3.50.0 and later */ + sqlite3_setlk_timeout, + /* Version 3.51.0 and later */ + sqlite3_set_errmsg, + sqlite3_db_status64, + /* Version 3.52.0 and later */ + sqlite3_str_truncate, + sqlite3_str_free, +#ifdef SQLITE_ENABLE_CARRAY + sqlite3_carray_bind, + sqlite3_carray_bind_v2 +#else + 0, + 0 +#endif }; /* True if x is the directory separator character @@ -138695,33 +143996,42 @@ static int sqlite3LoadExtension( ** entry point name "sqlite3_extension_init" was not found, then ** construct an entry point name "sqlite3_X_init" where the X is ** replaced by the lowercase value of every ASCII alphabetic - ** character in the filename after the last "/" upto the first ".", - ** and eliding the first three characters if they are "lib". + ** character in the filename after the last "/" up to the first ".", + ** and skipping the first three characters if they are "lib". ** Examples: ** ** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example_init ** C:/lib/mathfuncs.dll ==> sqlite3_mathfuncs_init + ** + ** If that still finds no entry point, repeat a second time but this + ** time include both alphabetic and numeric characters up to the first + ** ".". Example: + ** + ** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example5_init */ if( xInit==0 && zProc==0 ){ int iFile, iEntry, c; int ncFile = sqlite3Strlen30(zFile); + int cnt = 0; zAltEntry = sqlite3_malloc64(ncFile+30); if( zAltEntry==0 ){ sqlite3OsDlClose(pVfs, handle); return SQLITE_NOMEM_BKPT; } - memcpy(zAltEntry, "sqlite3_", 8); - for(iFile=ncFile-1; iFile>=0 && !DirSep(zFile[iFile]); iFile--){} - iFile++; - if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3; - for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){ - if( sqlite3Isalpha(c) ){ - zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c]; + do{ + memcpy(zAltEntry, "sqlite3_", 8); + for(iFile=ncFile-1; iFile>=0 && !DirSep(zFile[iFile]); iFile--){} + iFile++; + if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3; + for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){ + if( sqlite3Isalpha(c) || (cnt && sqlite3Isdigit(c)) ){ + zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c]; + } } - } - memcpy(zAltEntry+iEntry, "_init", 6); - zEntry = zAltEntry; - xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); + memcpy(zAltEntry+iEntry, "_init", 6); + zEntry = zAltEntry; + xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); + }while( xInit==0 && (++cnt)<2 ); } if( xInit==0 ){ if( pzErrMsg ){ @@ -139115,48 +144425,48 @@ static const char *const pragCName[] = { /* 13 */ "pk", /* 14 */ "hidden", /* table_info reuses 8 */ - /* 15 */ "schema", /* Used by: table_list */ - /* 16 */ "name", + /* 15 */ "name", /* Used by: function_list */ + /* 16 */ "builtin", /* 17 */ "type", - /* 18 */ "ncol", - /* 19 */ "wr", - /* 20 */ "strict", - /* 21 */ "seqno", /* Used by: index_xinfo */ - /* 22 */ "cid", - /* 23 */ "name", - /* 24 */ "desc", - /* 25 */ "coll", - /* 26 */ "key", - /* 27 */ "name", /* Used by: function_list */ - /* 28 */ "builtin", - /* 29 */ "type", - /* 30 */ "enc", - /* 31 */ "narg", - /* 32 */ "flags", - /* 33 */ "tbl", /* Used by: stats */ - /* 34 */ "idx", - /* 35 */ "wdth", - /* 36 */ "hght", - /* 37 */ "flgs", - /* 38 */ "seq", /* Used by: index_list */ - /* 39 */ "name", - /* 40 */ "unique", - /* 41 */ "origin", - /* 42 */ "partial", + /* 18 */ "enc", + /* 19 */ "narg", + /* 20 */ "flags", + /* 21 */ "schema", /* Used by: table_list */ + /* 22 */ "name", + /* 23 */ "type", + /* 24 */ "ncol", + /* 25 */ "wr", + /* 26 */ "strict", + /* 27 */ "seqno", /* Used by: index_xinfo */ + /* 28 */ "cid", + /* 29 */ "name", + /* 30 */ "desc", + /* 31 */ "coll", + /* 32 */ "key", + /* 33 */ "seq", /* Used by: index_list */ + /* 34 */ "name", + /* 35 */ "unique", + /* 36 */ "origin", + /* 37 */ "partial", + /* 38 */ "tbl", /* Used by: stats */ + /* 39 */ "idx", + /* 40 */ "wdth", + /* 41 */ "hght", + /* 42 */ "flgs", /* 43 */ "table", /* Used by: foreign_key_check */ /* 44 */ "rowid", /* 45 */ "parent", /* 46 */ "fkid", - /* index_info reuses 21 */ - /* 47 */ "seq", /* Used by: database_list */ - /* 48 */ "name", - /* 49 */ "file", - /* 50 */ "busy", /* Used by: wal_checkpoint */ - /* 51 */ "log", - /* 52 */ "checkpointed", - /* collation_list reuses 38 */ + /* 47 */ "busy", /* Used by: wal_checkpoint */ + /* 48 */ "log", + /* 49 */ "checkpointed", + /* 50 */ "seq", /* Used by: database_list */ + /* 51 */ "name", + /* 52 */ "file", + /* index_info reuses 27 */ /* 53 */ "database", /* Used by: lock_status */ /* 54 */ "status", + /* collation_list reuses 33 */ /* 55 */ "cache_size", /* Used by: default_cache_size */ /* module_list pragma_list reuses 9 */ /* 56 */ "timeout", /* Used by: busy_timeout */ @@ -139249,7 +144559,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 38, 2, + /* ColNames: */ 33, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) @@ -139284,7 +144594,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 47, 3, + /* ColNames: */ 50, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) @@ -139364,7 +144674,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "function_list", /* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 27, 6, + /* ColNames: */ 15, 6, /* iArg: */ 0 }, #endif #endif @@ -139393,17 +144703,17 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 21, 3, + /* ColNames: */ 27, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 38, 5, + /* ColNames: */ 33, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 21, 6, + /* ColNames: */ 27, 6, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) @@ -139582,7 +144892,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, - /* ColNames: */ 33, 5, + /* ColNames: */ 38, 5, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -139601,7 +144911,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "table_list", /* ePragTyp: */ PragTyp_TABLE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1, - /* ColNames: */ 15, 6, + /* ColNames: */ 21, 6, /* iArg: */ 0 }, {/* zName: */ "table_xinfo", /* ePragTyp: */ PragTyp_TABLE_INFO, @@ -139678,7 +144988,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 50, 3, + /* ColNames: */ 47, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -139700,7 +145010,7 @@ static const PragmaName aPragmaName[] = { ** the following macro or to the actual analysis_limit if it is non-zero, ** in order to prevent PRAGMA optimize from running for too long. ** -** The value of 2000 is chosen emperically so that the worst-case run-time +** The value of 2000 is chosen empirically so that the worst-case run-time ** for PRAGMA optimize does not exceed 100 milliseconds against a variety ** of test databases on a RaspberryPI-4 compiled using -Os and without ** -DSQLITE_DEBUG. Of course, your mileage may vary. For the purpose of @@ -140055,6 +145365,22 @@ static int integrityCheckResultRow(Vdbe *v){ return addr; } +/* +** Should table pTab be skipped when doing an integrity_check? +** Return true or false. +** +** If pObjTab is not null, the return true if pTab matches pObjTab. +** +** If pObjTab is null, then return true only if pTab is an imposter table. +*/ +static int tableSkipIntegrityCheck(const Table *pTab, const Table *pObjTab){ + if( pObjTab ){ + return pTab!=pObjTab; + }else{ + return (pTab->tabFlags & TF_Imposter)!=0; + } +} + /* ** Process a pragma statement. ** @@ -140808,12 +146134,6 @@ SQLITE_PRIVATE void sqlite3Pragma( ** in auto-commit mode. */ mask &= ~(SQLITE_ForeignKeys); } -#if SQLITE_USER_AUTHENTICATION - if( db->auth.authLevel==UAUTH_User ){ - /* Do not allow non-admin users to modify the schema arbitrarily */ - mask &= ~(SQLITE_WriteSchema); - } -#endif if( sqlite3GetBoolean(zRight, 0) ){ if( (mask & SQLITE_WriteSchema)==0 @@ -140823,7 +146143,10 @@ SQLITE_PRIVATE void sqlite3Pragma( } }else{ db->flags &= ~mask; - if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; + if( mask==SQLITE_DeferFKs ){ + db->nDeferredImmCons = 0; + db->nDeferredCons = 0; + } if( (mask & SQLITE_WriteSchema)!=0 && sqlite3_stricmp(zRight, "reset")==0 ){ @@ -140949,7 +146272,8 @@ SQLITE_PRIVATE void sqlite3Pragma( char *zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\"", pTab->zName); if( zSql ){ sqlite3_stmt *pDummy = 0; - (void)sqlite3_prepare(db, zSql, -1, &pDummy, 0); + (void)sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_DONT_LOG, + &pDummy, 0); (void)sqlite3_finalize(pDummy); sqlite3DbFree(db, zSql); } @@ -141402,7 +146726,7 @@ SQLITE_PRIVATE void sqlite3Pragma( Table *pTab = sqliteHashData(x); /* Current table */ Index *pIdx; /* An index on pTab */ int nIdx; /* Number of indexes on pTab */ - if( pObjTab && pObjTab!=pTab ) continue; + if( tableSkipIntegrityCheck(pTab,pObjTab) ) continue; if( HasRowid(pTab) ) cnt++; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; } } @@ -141415,7 +146739,7 @@ SQLITE_PRIVATE void sqlite3Pragma( for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; - if( pObjTab && pObjTab!=pTab ) continue; + if( tableSkipIntegrityCheck(pTab,pObjTab) ) continue; if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ aRoot[++cnt] = pIdx->tnum; @@ -141430,7 +146754,7 @@ SQLITE_PRIVATE void sqlite3Pragma( /* Do the b-tree integrity checks */ sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY); - sqlite3VdbeChangeP5(v, (u8)i); + sqlite3VdbeChangeP5(v, (u16)i); addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName), @@ -141446,7 +146770,7 @@ SQLITE_PRIVATE void sqlite3Pragma( int iTab = 0; Table *pTab = sqliteHashData(x); Index *pIdx; - if( pObjTab && pObjTab!=pTab ) continue; + if( tableSkipIntegrityCheck(pTab,pObjTab) ) continue; if( HasRowid(pTab) ){ iTab = cnt++; }else{ @@ -141482,7 +146806,7 @@ SQLITE_PRIVATE void sqlite3Pragma( int r2; /* Previous key for WITHOUT ROWID tables */ int mxCol; /* Maximum non-virtual column number */ - if( pObjTab && pObjTab!=pTab ) continue; + if( tableSkipIntegrityCheck(pTab,pObjTab) ) continue; if( !IsOrdinaryTable(pTab) ) continue; if( isQuick || HasRowid(pTab) ){ pPk = 0; @@ -141717,8 +147041,20 @@ SQLITE_PRIVATE void sqlite3Pragma( pPrior = pIdx; sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */ /* Verify that an index entry exists for the current table row */ - jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, + sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, pIdx->nColumn); VdbeCoverage(v); + jmp2 = sqlite3VdbeAddOp3(v, OP_IFindKey, iIdxCur+j, ckUniq, r1); + VdbeCoverage(v); + sqlite3VdbeChangeP4(v, -1, (const char*)pIdx, P4_INDEX); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, + sqlite3MPrintf(db, "index %s stores an imprecise floating-point " + "value for row ", pIdx->zName), + P4_DYNAMIC); + sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); + integrityCheckResultRow(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, ckUniq); + + sqlite3VdbeJumpHere(v, jmp2); sqlite3VdbeLoadString(v, 3, "row "); sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); sqlite3VdbeLoadString(v, 4, " missing from index "); @@ -141726,7 +147062,7 @@ SQLITE_PRIVATE void sqlite3Pragma( jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); jmp4 = integrityCheckResultRow(v); - sqlite3VdbeJumpHere(v, jmp2); + sqlite3VdbeResolveLabel(v, ckUniq); /* The OP_IdxRowid opcode is an optimized version of OP_Column ** that extracts the rowid off the end of the index record. @@ -141806,7 +147142,7 @@ SQLITE_PRIVATE void sqlite3Pragma( Table *pTab = sqliteHashData(x); sqlite3_vtab *pVTab; int a1; - if( pObjTab && pObjTab!=pTab ) continue; + if( tableSkipIntegrityCheck(pTab,pObjTab) ) continue; if( IsOrdinaryTable(pTab) ) continue; if( !IsVirtual(pTab) ) continue; if( pTab->nCol<=0 ){ @@ -142038,6 +147374,8 @@ SQLITE_PRIVATE void sqlite3Pragma( eMode = SQLITE_CHECKPOINT_RESTART; }else if( sqlite3StrICmp(zRight, "truncate")==0 ){ eMode = SQLITE_CHECKPOINT_TRUNCATE; + }else if( sqlite3StrICmp(zRight, "noop")==0 ){ + eMode = SQLITE_CHECKPOINT_NOOP; } } pParse->nMem = 3; @@ -142777,7 +148115,8 @@ static void corruptSchema( static const char *azAlterType[] = { "rename", "drop column", - "add column" + "add column", + "drop constraint" }; *pData->pzErrMsg = sqlite3MPrintf(db, "error in %s %s after %s: %s", azObj[0], azObj[1], @@ -143050,14 +148389,7 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl #else encoding = SQLITE_UTF8; #endif - if( db->nVdbeActive>0 && encoding!=ENC(db) - && (db->mDbFlags & DBFLAG_Vacuum)==0 - ){ - rc = SQLITE_LOCKED; - goto initone_error_out; - }else{ - sqlite3SetTextEncoding(db, encoding); - } + sqlite3SetTextEncoding(db, encoding); }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){ @@ -143611,9 +148943,11 @@ static int sqlite3LockAndPrepare( rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); assert( rc==SQLITE_OK || *ppStmt==0 ); if( rc==SQLITE_OK || db->mallocFailed ) break; - }while( (rc==SQLITE_ERROR_RETRY && (cnt++)errMask)==rc ); db->busyHandler.nBusy = 0; @@ -143865,7 +149199,7 @@ SQLITE_API int sqlite3_prepare16_v3( */ typedef struct DistinctCtx DistinctCtx; struct DistinctCtx { - u8 isTnct; /* 0: Not distinct. 1: DISTICT 2: DISTINCT and ORDER BY */ + u8 isTnct; /* 0: Not distinct. 1: DISTINCT 2: DISTINCT and ORDER BY */ u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ int tabTnct; /* Ephemeral table used for DISTINCT processing */ int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ @@ -143995,10 +149329,8 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( pNew->iLimit = 0; pNew->iOffset = 0; pNew->selId = ++pParse->nSelect; - pNew->addrOpenEphm[0] = -1; - pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = 0; - if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc)); + if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1); pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; @@ -144163,10 +149495,33 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p */ SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol){ int i; - u8 h = sqlite3StrIHash(zCol); - Column *pCol; - for(pCol=pTab->aCol, i=0; inCol; pCol++, i++){ - if( pCol->hName==h && sqlite3StrICmp(pCol->zCnName, zCol)==0 ) return i; + u8 h; + const Column *aCol; + int nCol; + + h = sqlite3StrIHash(zCol); + aCol = pTab->aCol; + nCol = pTab->nCol; + + /* See if the aHx gives us a lucky match */ + i = pTab->aHx[h % sizeof(pTab->aHx)]; + assert( i=nCol ) break; } return -1; } @@ -144205,7 +149560,7 @@ static int tableAndColumnIndex( int iEnd, /* Last member of pSrc->a[] to check */ const char *zCol, /* Name of the column we are looking for */ int *piTab, /* Write index of pSrc->a[] here */ - int *piCol, /* Write index of pSrc->a[*piTab].pTab->aCol[] here */ + int *piCol, /* Write index of pSrc->a[*piTab].pSTab->aCol[] here */ int bIgnoreHidden /* Ignore hidden columns */ ){ int i; /* For looping over tables in pSrc */ @@ -144264,8 +149619,7 @@ SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr *p, int iTable, u32 joinFlag){ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(p, EP_NoReduce); p->w.iJoin = iTable; - if( p->op==TK_FUNCTION ){ - assert( ExprUseXList(p) ); + if( ExprUseXList(p) ){ if( p->x.pList ){ int i; for(i=0; ix.pList->nExpr; i++){ @@ -144417,7 +149771,7 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ } pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iLeftCol); sqlite3SrcItemColumnUsed(&pSrc->a[iLeft], iLeftCol); - if( (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){ + if( (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 && pParse->nErr==0 ){ /* This branch runs if the query contains one or more RIGHT or FULL ** JOINs. If only a single table on the left side of this join ** contains the zName column, then this branch is a no-op. @@ -144433,6 +149787,8 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ */ ExprList *pFuncArgs = 0; /* Arguments to the coalesce() */ static const Token tkCoalesce = { "coalesce", 8 }; + assert( pE1!=0 ); + ExprSetProperty(pE1, EP_CanBeNull); while( tableAndColumnIndex(pSrc, iLeft+1, i, zName, &iLeft, &iLeftCol, pRight->fg.isSynthUsing)!=0 ){ if( pSrc->a[iLeft].fg.isUsing==0 @@ -144449,7 +149805,13 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ if( pFuncArgs ){ pFuncArgs = sqlite3ExprListAppend(pParse, pFuncArgs, pE1); pE1 = sqlite3ExprFunction(pParse, pFuncArgs, &tkCoalesce, 0); + if( pE1 ){ + pE1->affExpr = SQLITE_AFF_DEFER; + } } + }else if( (pSrc->a[i+1].fg.jointype & JT_LEFT)!=0 && pParse->nErr==0 ){ + assert( pE1!=0 ); + ExprSetProperty(pE1, EP_CanBeNull); } pE2 = sqlite3CreateColumnExpr(db, pSrc, i+1, iRightCol); sqlite3SrcItemColumnUsed(pRight, iRightCol); @@ -144473,6 +149835,11 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->u3.pOn); pRight->u3.pOn = 0; pRight->fg.isOn = 1; + p->selFlags |= SF_OnToWhere; + } + + if( IsVirtual(pRightTab) && joinType==EP_OuterON && pRight->u1.pFuncArg ){ + p->selFlags |= SF_OnToWhere; } } return 0; @@ -145113,29 +150480,6 @@ static void selectInnerLoop( } switch( eDest ){ - /* In this mode, write each query result to the key of the temporary - ** table iParm. - */ -#ifndef SQLITE_OMIT_COMPOUND_SELECT - case SRT_Union: { - int r1; - r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); - sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); - sqlite3ReleaseTempReg(pParse, r1); - break; - } - - /* Construct a record from the query result, but instead of - ** saving that record, use it as a key to delete elements from - ** the temporary table iParm. - */ - case SRT_Except: { - sqlite3VdbeAddOp3(v, OP_IdxDelete, iParm, regResult, nResultCol); - break; - } -#endif /* SQLITE_OMIT_COMPOUND_SELECT */ - /* Store the result as data using a unique key. */ case SRT_Fifo: @@ -145258,9 +150602,14 @@ static void selectInnerLoop( assert( nResultCol<=pDest->nSdst ); pushOntoSorter( pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); + pDest->iSDParm = regResult; }else{ assert( nResultCol==pDest->nSdst ); - assert( regResult==iParm ); + if( regResult!=iParm ){ + /* This occurs in cases where the SELECT had both a DISTINCT and + ** an OFFSET clause. */ + sqlite3VdbeAddOp3(v, OP_Copy, regResult, iParm, nResultCol-1); + } /* The LIMIT clause will jump out of the loop for us */ } break; @@ -145358,8 +150707,11 @@ static void selectInnerLoop( ** X extra columns. */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ - int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*); - KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra); + int nExtra = (N+X)*(sizeof(CollSeq*)+1); + KeyInfo *p; + assert( X>=0 ); + if( NEVER(N+X>0xffff) ) return (KeyInfo*)sqlite3OomFault(db); + p = sqlite3DbMallocRawNN(db, SZ_KEYINFO(0) + nExtra); if( p ){ p->aSortFlags = (u8*)&p->aColl[N+X]; p->nKeyField = (u16)N; @@ -145367,7 +150719,7 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ p->enc = ENC(db); p->db = db; p->nRef = 1; - memset(&p[1], 0, nExtra); + memset(p->aColl, 0, nExtra); }else{ return (KeyInfo*)sqlite3OomFault(db); } @@ -145926,6 +151278,10 @@ static void generateColumnTypes( #endif sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT); } +#else + UNUSED_PARAMETER(pParse); + UNUSED_PARAMETER(pTabList); + UNUSED_PARAMETER(pEList); #endif /* !defined(SQLITE_OMIT_DECLTYPE) */ } @@ -146236,8 +151592,8 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes( } } if( zType ){ - const i64 k = sqlite3Strlen30(zType); - n = sqlite3Strlen30(pCol->zCnName); + const i64 k = strlen(zType); + n = strlen(pCol->zCnName); pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+k+2); pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL); if( pCol->zCnName ){ @@ -146263,6 +151619,13 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, c sqlite3 *db = pParse->db; u64 savedFlags; + pParse->nNestSel++; +#if SQLITE_MAX_EXPR_DEPTH>0 + if( pParse->nNestSel >= db->aLimit[SQLITE_LIMIT_EXPR_DEPTH] ){ + sqlite3ErrorMsg(pParse, "VIEWs and/or subqueries nested too deep"); + return 0; + } +#endif savedFlags = db->flags; db->flags &= ~(u64)SQLITE_FullColNames; db->flags |= SQLITE_ShortColNames; @@ -146284,6 +151647,8 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, c sqlite3DeleteTable(db, pTab); return 0; } + pParse->nNestSel--; + assert( pParse->nNestSel>=0 ); return pTab; } @@ -146410,9 +151775,9 @@ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){ ** function is responsible for ensuring that this structure is eventually ** freed. */ -static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){ +static KeyInfo *multiSelectByMergeKeyInfo(Parse *pParse, Select *p, int nExtra){ ExprList *pOrderBy = p->pOrderBy; - int nOrderBy = ALWAYS(pOrderBy!=0) ? pOrderBy->nExpr : 0; + int nOrderBy = (pOrderBy!=0) ? pOrderBy->nExpr : 0; sqlite3 *db = pParse->db; KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1); if( pRet ){ @@ -146545,7 +151910,7 @@ static void generateWithRecursiveQuery( regCurrent = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_OpenPseudo, iCurrent, regCurrent, nCol); if( pOrderBy ){ - KeyInfo *pKeyInfo = multiSelectOrderByKeyInfo(pParse, p, 1); + KeyInfo *pKeyInfo = multiSelectByMergeKeyInfo(pParse, p, 1); sqlite3VdbeAddOp4(v, OP_OpenEphemeral, iQueue, pOrderBy->nExpr+2, 0, (char*)pKeyInfo, P4_KEYINFO); destQueue.pOrderBy = pOrderBy; @@ -146554,8 +151919,28 @@ static void generateWithRecursiveQuery( } VdbeComment((v, "Queue table")); if( iDistinct ){ - p->addrOpenEphm[0] = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iDistinct, 0); - p->selFlags |= SF_UsesEphemeral; + /* Generate an ephemeral table used to enforce distinctness on the + ** output of the recursive part of the CTE. + */ + KeyInfo *pKeyInfo; /* Collating sequence for the result set */ + CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */ + + assert( p->pNext==0 ); + assert( p->pEList!=0 ); + nCol = p->pEList->nExpr; + pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nCol, 1); + if( pKeyInfo ){ + for(i=0, apColl=pKeyInfo->aColl; idb->pDfltColl; + } + } + sqlite3VdbeAddOp4(v, OP_OpenEphemeral, iDistinct, nCol, 0, + (void*)pKeyInfo, P4_KEYINFO); + }else{ + assert( pParse->nErr>0 ); + } } /* Detach the ORDER BY clause from the compound SELECT */ @@ -146630,7 +152015,7 @@ static void generateWithRecursiveQuery( #endif /* SQLITE_OMIT_CTE */ /* Forward references */ -static int multiSelectOrderBy( +static int multiSelectByMerge( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ @@ -146779,12 +152164,26 @@ static int multiSelect( generateWithRecursiveQuery(pParse, p, &dest); }else #endif - - /* Compound SELECTs that have an ORDER BY clause are handled separately. - */ if( p->pOrderBy ){ - return multiSelectOrderBy(pParse, p, pDest); - }else{ + /* If the compound has an ORDER BY clause, then always use the merge + ** algorithm. */ + return multiSelectByMerge(pParse, p, pDest); + }else if( p->op!=TK_ALL ){ + /* If the compound is EXCEPT, INTERSECT, or UNION (anything other than + ** UNION ALL) then also always use the merge algorithm. However, the + ** multiSelectByMerge() routine requires that the compound have an + ** ORDER BY clause, and it doesn't right now. So invent one first. */ + Expr *pOne = sqlite3ExprInt32(db, 1); + p->pOrderBy = sqlite3ExprListAppend(pParse, 0, pOne); + if( pParse->nErr ) goto multi_select_end; + assert( p->pOrderBy!=0 ); + p->pOrderBy->a[0].u.x.iOrderByCol = 1; + return multiSelectByMerge(pParse, p, pDest); + }else{ + /* For a UNION ALL compound without ORDER BY, simply run the left + ** query, then run the right query */ + int addr = 0; + int nLimit = 0; /* Initialize to suppress harmless compiler warning */ #ifndef SQLITE_OMIT_EXPLAIN if( pPrior->pPrior==0 ){ @@ -146792,282 +152191,55 @@ static int multiSelect( ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY")); } #endif - - /* Generate code for the left and right SELECT statements. - */ - switch( p->op ){ - case TK_ALL: { - int addr = 0; - int nLimit = 0; /* Initialize to suppress harmless compiler warning */ - assert( !pPrior->pLimit ); - pPrior->iLimit = p->iLimit; - pPrior->iOffset = p->iOffset; - pPrior->pLimit = p->pLimit; - TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL left...\n")); - rc = sqlite3Select(pParse, pPrior, &dest); - pPrior->pLimit = 0; - if( rc ){ - goto multi_select_end; - } - p->pPrior = 0; - p->iLimit = pPrior->iLimit; - p->iOffset = pPrior->iOffset; - if( p->iLimit ){ - addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); - VdbeComment((v, "Jump ahead if LIMIT reached")); - if( p->iOffset ){ - sqlite3VdbeAddOp3(v, OP_OffsetLimit, - p->iLimit, p->iOffset+1, p->iOffset); - } - } - ExplainQueryPlan((pParse, 1, "UNION ALL")); - TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL right...\n")); - rc = sqlite3Select(pParse, p, &dest); - testcase( rc!=SQLITE_OK ); - pDelete = p->pPrior; - p->pPrior = pPrior; - p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); - if( p->pLimit - && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit, pParse) - && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) - ){ - p->nSelectRow = sqlite3LogEst((u64)nLimit); - } - if( addr ){ - sqlite3VdbeJumpHere(v, addr); - } - break; - } - case TK_EXCEPT: - case TK_UNION: { - int unionTab; /* Cursor number of the temp table holding result */ - u8 op = 0; /* One of the SRT_ operations to apply to self */ - int priorOp; /* The SRT_ operation to apply to prior selects */ - Expr *pLimit; /* Saved values of p->nLimit */ - int addr; - SelectDest uniondest; - - testcase( p->op==TK_EXCEPT ); - testcase( p->op==TK_UNION ); - priorOp = SRT_Union; - if( dest.eDest==priorOp ){ - /* We can reuse a temporary table generated by a SELECT to our - ** right. - */ - assert( p->pLimit==0 ); /* Not allowed on leftward elements */ - unionTab = dest.iSDParm; - }else{ - /* We will need to create our own temporary table to hold the - ** intermediate results. - */ - unionTab = pParse->nTab++; - assert( p->pOrderBy==0 ); - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); - assert( p->addrOpenEphm[0] == -1 ); - p->addrOpenEphm[0] = addr; - findRightmost(p)->selFlags |= SF_UsesEphemeral; - assert( p->pEList ); - } - - - /* Code the SELECT statements to our left - */ - assert( !pPrior->pOrderBy ); - sqlite3SelectDestInit(&uniondest, priorOp, unionTab); - TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION left...\n")); - rc = sqlite3Select(pParse, pPrior, &uniondest); - if( rc ){ - goto multi_select_end; - } - - /* Code the current SELECT statement - */ - if( p->op==TK_EXCEPT ){ - op = SRT_Except; - }else{ - assert( p->op==TK_UNION ); - op = SRT_Union; - } - p->pPrior = 0; - pLimit = p->pLimit; - p->pLimit = 0; - uniondest.eDest = op; - ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", - sqlite3SelectOpName(p->op))); - TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION right...\n")); - rc = sqlite3Select(pParse, p, &uniondest); - testcase( rc!=SQLITE_OK ); - assert( p->pOrderBy==0 ); - pDelete = p->pPrior; - p->pPrior = pPrior; - p->pOrderBy = 0; - if( p->op==TK_UNION ){ - p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); - } - sqlite3ExprDelete(db, p->pLimit); - p->pLimit = pLimit; - p->iLimit = 0; - p->iOffset = 0; - - /* Convert the data in the temporary table into whatever form - ** it is that we currently need. - */ - assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); - assert( p->pEList || db->mallocFailed ); - if( dest.eDest!=priorOp && db->mallocFailed==0 ){ - int iCont, iBreak, iStart; - iBreak = sqlite3VdbeMakeLabel(pParse); - iCont = sqlite3VdbeMakeLabel(pParse); - computeLimitRegisters(pParse, p, iBreak); - sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); - iStart = sqlite3VdbeCurrentAddr(v); - selectInnerLoop(pParse, p, unionTab, - 0, 0, &dest, iCont, iBreak); - sqlite3VdbeResolveLabel(v, iCont); - sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); - sqlite3VdbeResolveLabel(v, iBreak); - sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); - } - break; - } - default: assert( p->op==TK_INTERSECT ); { - int tab1, tab2; - int iCont, iBreak, iStart; - Expr *pLimit; - int addr; - SelectDest intersectdest; - int r1; - - /* INTERSECT is different from the others since it requires - ** two temporary tables. Hence it has its own case. Begin - ** by allocating the tables we will need. - */ - tab1 = pParse->nTab++; - tab2 = pParse->nTab++; - assert( p->pOrderBy==0 ); - - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); - assert( p->addrOpenEphm[0] == -1 ); - p->addrOpenEphm[0] = addr; - findRightmost(p)->selFlags |= SF_UsesEphemeral; - assert( p->pEList ); - - /* Code the SELECTs to our left into temporary table "tab1". - */ - sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); - TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT left...\n")); - rc = sqlite3Select(pParse, pPrior, &intersectdest); - if( rc ){ - goto multi_select_end; - } - - /* Code the current SELECT into temporary table "tab2" - */ - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); - assert( p->addrOpenEphm[1] == -1 ); - p->addrOpenEphm[1] = addr; - p->pPrior = 0; - pLimit = p->pLimit; - p->pLimit = 0; - intersectdest.iSDParm = tab2; - ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", - sqlite3SelectOpName(p->op))); - TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT right...\n")); - rc = sqlite3Select(pParse, p, &intersectdest); - testcase( rc!=SQLITE_OK ); - pDelete = p->pPrior; - p->pPrior = pPrior; - if( p->nSelectRow>pPrior->nSelectRow ){ - p->nSelectRow = pPrior->nSelectRow; - } - sqlite3ExprDelete(db, p->pLimit); - p->pLimit = pLimit; - - /* Generate code to take the intersection of the two temporary - ** tables. - */ - if( rc ) break; - assert( p->pEList ); - iBreak = sqlite3VdbeMakeLabel(pParse); - iCont = sqlite3VdbeMakeLabel(pParse); - computeLimitRegisters(pParse, p, iBreak); - sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); - r1 = sqlite3GetTempReg(pParse); - iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); - sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); - VdbeCoverage(v); - sqlite3ReleaseTempReg(pParse, r1); - selectInnerLoop(pParse, p, tab1, - 0, 0, &dest, iCont, iBreak); - sqlite3VdbeResolveLabel(v, iCont); - sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); - sqlite3VdbeResolveLabel(v, iBreak); - sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); - sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); - break; - } - } - - #ifndef SQLITE_OMIT_EXPLAIN - if( p->pNext==0 ){ - ExplainQueryPlanPop(pParse); - } - #endif - } - if( pParse->nErr ) goto multi_select_end; - - /* Compute collating sequences used by - ** temporary tables needed to implement the compound select. - ** Attach the KeyInfo structure to all temporary tables. - ** - ** This section is run by the right-most SELECT statement only. - ** SELECT statements to the left always skip this part. The right-most - ** SELECT might also skip this part if it has no ORDER BY clause and - ** no temp tables are required. - */ - if( p->selFlags & SF_UsesEphemeral ){ - int i; /* Loop counter */ - KeyInfo *pKeyInfo; /* Collating sequence for the result set */ - Select *pLoop; /* For looping through SELECT statements */ - CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */ - int nCol; /* Number of columns in result set */ - - assert( p->pNext==0 ); - assert( p->pEList!=0 ); - nCol = p->pEList->nExpr; - pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1); - if( !pKeyInfo ){ - rc = SQLITE_NOMEM_BKPT; + assert( !pPrior->pLimit ); + pPrior->iLimit = p->iLimit; + pPrior->iOffset = p->iOffset; + pPrior->pLimit = sqlite3ExprDup(db, p->pLimit, 0); + TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL left...\n")); + rc = sqlite3Select(pParse, pPrior, &dest); + sqlite3ExprDelete(db, pPrior->pLimit); + pPrior->pLimit = 0; + if( rc ){ goto multi_select_end; } - for(i=0, apColl=pKeyInfo->aColl; ipDfltColl; - } + p->pPrior = 0; + p->iLimit = pPrior->iLimit; + p->iOffset = pPrior->iOffset; + if( p->iLimit ){ + addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); + VdbeComment((v, "Jump ahead if LIMIT reached")); + if( p->iOffset ){ + sqlite3VdbeAddOp3(v, OP_OffsetLimit, + p->iLimit, p->iOffset+1, p->iOffset); + } + } + ExplainQueryPlan((pParse, 1, "UNION ALL")); + TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL right...\n")); + rc = sqlite3Select(pParse, p, &dest); + testcase( rc!=SQLITE_OK ); + pDelete = p->pPrior; + p->pPrior = pPrior; + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); + if( p->pLimit + && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit, pParse) + && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) + ){ + p->nSelectRow = sqlite3LogEst((u64)nLimit); } - - for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ - for(i=0; i<2; i++){ - int addr = pLoop->addrOpenEphm[i]; - if( addr<0 ){ - /* If [0] is unused then [1] is also unused. So we can - ** always safely abort as soon as the first unused slot is found */ - assert( pLoop->addrOpenEphm[1]<0 ); - break; - } - sqlite3VdbeChangeP2(v, addr, nCol); - sqlite3VdbeChangeP4(v, addr, (char*)sqlite3KeyInfoRef(pKeyInfo), - P4_KEYINFO); - pLoop->addrOpenEphm[i] = -1; - } + if( addr ){ + sqlite3VdbeJumpHere(v, addr); } - sqlite3KeyInfoUnref(pKeyInfo); +#ifndef SQLITE_OMIT_EXPLAIN + if( p->pNext==0 ){ + ExplainQueryPlanPop(pParse); + } +#endif } multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; + pDest->iSDParm2 = dest.iSDParm2; if( pDelete ){ sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete); } @@ -147093,8 +152265,8 @@ SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){ ** Code an output subroutine for a coroutine implementation of a ** SELECT statement. ** -** The data to be output is contained in pIn->iSdst. There are -** pIn->nSdst columns to be output. pDest is where the output should +** The data to be output is contained in an array of pIn->nSdst registers +** starting at register pIn->iSdst. pDest is where the output should ** be sent. ** ** regReturn is the number of the register holding the subroutine @@ -147123,6 +152295,8 @@ static int generateOutputSubroutine( int iContinue; int addr; + assert( pIn->eDest==SRT_Coroutine ); + addr = sqlite3VdbeCurrentAddr(v); iContinue = sqlite3VdbeMakeLabel(pParse); @@ -147144,23 +152318,60 @@ static int generateOutputSubroutine( */ codeOffset(v, p->iOffset, iContinue); - assert( pDest->eDest!=SRT_Exists ); - assert( pDest->eDest!=SRT_Table ); switch( pDest->eDest ){ /* Store the result as data using a unique key. */ + case SRT_Fifo: + case SRT_DistFifo: + case SRT_Table: case SRT_EphemTab: { int r1 = sqlite3GetTempReg(pParse); int r2 = sqlite3GetTempReg(pParse); + int iParm = pDest->iSDParm; + testcase( pDest->eDest==SRT_Table ); + testcase( pDest->eDest==SRT_EphemTab ); + testcase( pDest->eDest==SRT_Fifo ); + testcase( pDest->eDest==SRT_DistFifo ); sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1); - sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iSDParm, r2); - sqlite3VdbeAddOp3(v, OP_Insert, pDest->iSDParm, r1, r2); +#if !defined(SQLITE_ENABLE_NULL_TRIM) && defined(SQLITE_DEBUG) + /* A destination of SRT_Table and a non-zero iSDParm2 parameter means + ** that this is an "UPDATE ... FROM" on a virtual table or view. In this + ** case set the p5 parameter of the OP_MakeRecord to OPFLAG_NOCHNG_MAGIC. + ** This does not affect operation in any way - it just allows MakeRecord + ** to process OPFLAG_NOCHANGE values without an assert() failing. */ + if( pDest->eDest==SRT_Table && pDest->iSDParm2 ){ + sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC); + } +#endif +#ifndef SQLITE_OMIT_CTE + if( pDest->eDest==SRT_DistFifo ){ + /* If the destination is DistFifo, then cursor (iParm+1) is open + ** on an ephemeral index that is used to enforce uniqueness on the + ** total result. At this point, we are processing the setup portion + ** of the recursive CTE using the merge algorithm, so the results are + ** guaranteed to be unique anyhow. But we still need to populate the + ** (iParm+1) cursor for use by the subsequent recursive phase. + */ + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm+1, r1, + pIn->iSdst, pIn->nSdst); + } +#endif + sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); + sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3ReleaseTempReg(pParse, r2); sqlite3ReleaseTempReg(pParse, r1); break; } + /* If any row exist in the result set, record that fact and abort. + */ + case SRT_Exists: { + sqlite3VdbeAddOp2(v, OP_Integer, 1, pDest->iSDParm); + /* The LIMIT clause will terminate the loop for us */ + break; + } + #ifndef SQLITE_OMIT_SUBQUERY /* If we are creating a set for an "expr IN (SELECT ...)". */ @@ -147207,9 +152418,51 @@ static int generateOutputSubroutine( break; } +#ifndef SQLITE_OMIT_CTE + /* Write the results into a priority queue that is order according to + ** pDest->pOrderBy (in pSO). pDest->iSDParm (in iParm) is the cursor for an + ** index with pSO->nExpr+2 columns. Build a key using pSO for the first + ** pSO->nExpr columns, then make sure all keys are unique by adding a + ** final OP_Sequence column. The last column is the record as a blob. + */ + case SRT_DistQueue: + case SRT_Queue: { + int nKey; + int r1, r2, r3, ii; + ExprList *pSO; + int iParm = pDest->iSDParm; + pSO = pDest->pOrderBy; + assert( pSO ); + nKey = pSO->nExpr; + r1 = sqlite3GetTempReg(pParse); + r2 = sqlite3GetTempRange(pParse, nKey+2); + r3 = r2+nKey+1; + + sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r3); + if( pDest->eDest==SRT_DistQueue ){ + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r3); + } + for(ii=0; iiiSdst + pSO->a[ii].u.x.iOrderByCol - 1, + r2+ii); + } + sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey); + sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2); + sqlite3ReleaseTempReg(pParse, r1); + sqlite3ReleaseTempRange(pParse, r2, nKey+2); + break; + } +#endif /* SQLITE_OMIT_CTE */ + + /* Ignore the output */ + case SRT_Discard: { + break; + } + /* If none of the above, then the result destination must be - ** SRT_Output. This routine is never called with any other - ** destination other than the ones handled above or SRT_Output. + ** SRT_Output. ** ** For SRT_Output, results are stored in a sequence of registers. ** Then the OP_ResultRow opcode is used to cause sqlite3_step() to @@ -147237,8 +152490,9 @@ static int generateOutputSubroutine( } /* -** Alternative compound select code generator for cases when there -** is an ORDER BY clause. +** Generate code for a compound SELECT statement using a merge +** algorithm. The compound must have an ORDER BY clause for this +** to work. ** ** We assume a query of the following form: ** @@ -147255,7 +152509,7 @@ static int generateOutputSubroutine( ** ** outB: Move the output of the selectB coroutine into the output ** of the compound query. (Only generated for UNION and -** UNION ALL. EXCEPT and INSERTSECT never output a row that +** UNION ALL. EXCEPT and INTERSECT never output a row that ** appears only in B.) ** ** AltB: Called when there is data from both coroutines and Au.x.iOrderByCol==i ) break; } if( j==nOrderBy ){ - Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); + Expr *pNew = sqlite3ExprInt32(db, i); if( pNew==0 ) return SQLITE_NOMEM_BKPT; - pNew->flags |= EP_IntValue; - pNew->u.iValue = i; p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew); if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i; } @@ -147405,26 +152655,29 @@ static int multiSelectOrderBy( } /* Compute the comparison permutation and keyinfo that is used with - ** the permutation used to determine if the next - ** row of results comes from selectA or selectB. Also add explicit - ** collations to the ORDER BY clause terms so that when the subqueries - ** to the right and the left are evaluated, they use the correct - ** collation. + ** the permutation to determine if the next row of results comes + ** from selectA or selectB. Also add literal collations to the + ** ORDER BY clause terms so that when selectA and selectB are + ** evaluated, they use the correct collation. */ aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1)); if( aPermute ){ struct ExprList_item *pItem; + int bKeep = 0; aPermute[0] = nOrderBy; for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){ assert( pItem!=0 ); assert( pItem->u.x.iOrderByCol>0 ); assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ); aPermute[i] = pItem->u.x.iOrderByCol - 1; + if( aPermute[i]!=(u32)i-1 ) bKeep = 1; + } + if( bKeep==0 ){ + sqlite3DbFreeNN(db, aPermute); + aPermute = 0; } - pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1); - }else{ - pKeyMerge = 0; } + pKeyMerge = multiSelectByMergeKeyInfo(pParse, p, 1); /* Allocate a range of temporary registers and the KeyInfo needed ** for the logic that removes duplicate result rows when the @@ -147503,7 +152756,7 @@ static int multiSelectOrderBy( */ addrSelectA = sqlite3VdbeCurrentAddr(v) + 1; addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA); - VdbeComment((v, "left SELECT")); + VdbeComment((v, "SUBR: next-A")); pPrior->iLimit = regLimitA; ExplainQueryPlan((pParse, 1, "LEFT")); sqlite3Select(pParse, pPrior, &destA); @@ -147515,7 +152768,7 @@ static int multiSelectOrderBy( */ addrSelectB = sqlite3VdbeCurrentAddr(v) + 1; addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB); - VdbeComment((v, "right SELECT")); + VdbeComment((v, "SUBR: next-B")); savedLimit = p->iLimit; savedOffset = p->iOffset; p->iLimit = regLimitB; @@ -147529,7 +152782,7 @@ static int multiSelectOrderBy( /* Generate a subroutine that outputs the current row of the A ** select as the next output row of the compound select. */ - VdbeNoopComment((v, "Output routine for A")); + VdbeNoopComment((v, "SUBR: out-A")); addrOutA = generateOutputSubroutine(pParse, p, &destA, pDest, regOutA, regPrev, pKeyDup, labelEnd); @@ -147538,7 +152791,7 @@ static int multiSelectOrderBy( ** select as the next output row of the compound select. */ if( op==TK_ALL || op==TK_UNION ){ - VdbeNoopComment((v, "Output routine for B")); + VdbeNoopComment((v, "SUBR: out-B")); addrOutB = generateOutputSubroutine(pParse, p, &destB, pDest, regOutB, regPrev, pKeyDup, labelEnd); @@ -147551,10 +152804,12 @@ static int multiSelectOrderBy( if( op==TK_EXCEPT || op==TK_INTERSECT ){ addrEofA_noB = addrEofA = labelEnd; }else{ - VdbeNoopComment((v, "eof-A subroutine")); + VdbeNoopComment((v, "SUBR: eof-A")); addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); + VdbeComment((v, "out-B")); addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd); VdbeCoverage(v); + VdbeComment((v, "next-B")); sqlite3VdbeGoto(v, addrEofA); p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); } @@ -147566,17 +152821,20 @@ static int multiSelectOrderBy( addrEofB = addrEofA; if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow; }else{ - VdbeNoopComment((v, "eof-B subroutine")); + VdbeNoopComment((v, "SUBR: eof-B")); addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); + VdbeComment((v, "out-A")); sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd); VdbeCoverage(v); + VdbeComment((v, "next-A")); sqlite3VdbeGoto(v, addrEofB); } /* Generate code to handle the case of AB */ - VdbeNoopComment((v, "A-gt-B subroutine")); addrAgtB = sqlite3VdbeCurrentAddr(v); if( op==TK_ALL || op==TK_UNION ){ sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); + VdbeComment((v, "out-B")); + sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); + VdbeComment((v, "next-B")); + sqlite3VdbeGoto(v, labelCmpr); + }else{ + addrAgtB++; /* Just do next-B. Might as well use the next-B call + ** in the next code block */ } - sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); - sqlite3VdbeGoto(v, labelCmpr); /* This code runs once to initialize everything. */ sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB); VdbeCoverage(v); + VdbeComment((v, "next-A")); + /* v--- Also the A>B case for EXCEPT and INTERSECT */ sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); + VdbeComment((v, "next-B")); /* Implement the main merge loop */ + if( aPermute!=0 ){ + sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY); + } sqlite3VdbeResolveLabel(v, labelCmpr); - sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY); sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy, (char*)pKeyMerge, P4_KEYINFO); - sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); - sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); VdbeCoverage(v); + if( aPermute!=0 ){ + sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); + } + sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); + VdbeCoverageIf(v, op==TK_ALL); + VdbeCoverageIf(v, op==TK_UNION); + VdbeCoverageIf(v, op==TK_EXCEPT); + VdbeCoverageIf(v, op==TK_INTERSECT); /* Jump to the this point in order to terminate the query. */ @@ -147650,7 +152920,7 @@ static int multiSelectOrderBy( ** ## About "isOuterJoin": ** ** The isOuterJoin column indicates that the replacement will occur into a -** position in the parent that NULL-able due to an OUTER JOIN. Either the +** position in the parent that is NULL-able due to an OUTER JOIN. Either the ** target slot in the parent is the right operand of a LEFT JOIN, or one of ** the left operands of a RIGHT JOIN. In either case, we need to potentially ** bypass the substituted expression with OP_IfNullRow. @@ -147680,6 +152950,7 @@ typedef struct SubstContext { int iTable; /* Replace references to this table */ int iNewTable; /* New table number */ int isOuterJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */ + int nSelDepth; /* Depth of sub-query recursion. Top==1 */ ExprList *pEList; /* Replacement expressions */ ExprList *pCList; /* Collation sequences for replacement expr */ } SubstContext; @@ -147755,38 +153026,41 @@ static Expr *substExpr( if( pSubst->isOuterJoin ){ ExprSetProperty(pNew, EP_CanBeNull); } - if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){ - sqlite3SetJoinExpr(pNew, pExpr->w.iJoin, - pExpr->flags & (EP_OuterON|EP_InnerON)); - } - sqlite3ExprDelete(db, pExpr); - pExpr = pNew; - if( pExpr->op==TK_TRUEFALSE ){ - pExpr->u.iValue = sqlite3ExprTruthValue(pExpr); - pExpr->op = TK_INTEGER; - ExprSetProperty(pExpr, EP_IntValue); + if( pNew->op==TK_TRUEFALSE ){ + pNew->u.iValue = sqlite3ExprTruthValue(pNew); + pNew->op = TK_INTEGER; + ExprSetProperty(pNew, EP_IntValue); } /* Ensure that the expression now has an implicit collation sequence, ** just as it did when it was a column of a view or sub-query. */ { - CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pExpr); + CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pNew); CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse, pSubst->pCList->a[iColumn].pExpr ); - if( pNat!=pColl || (pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE) ){ - pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr, + if( pNat!=pColl || (pNew->op!=TK_COLUMN && pNew->op!=TK_COLLATE) ){ + pNew = sqlite3ExprAddCollateString(pSubst->pParse, pNew, (pColl ? pColl->zName : "BINARY") ); } } - ExprClearProperty(pExpr, EP_Collate); + ExprClearProperty(pNew, EP_Collate); + if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){ + sqlite3SetJoinExpr(pNew, pExpr->w.iJoin, + pExpr->flags & (EP_OuterON|EP_InnerON)); + } + sqlite3ExprDelete(db, pExpr); + pExpr = pNew; } } }else{ if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){ pExpr->iTable = pSubst->iNewTable; } + if( pExpr->op==TK_AGG_FUNCTION && pExpr->op2>=pSubst->nSelDepth ){ + pExpr->op2--; + } pExpr->pLeft = substExpr(pSubst, pExpr->pLeft); pExpr->pRight = substExpr(pSubst, pExpr->pRight); if( ExprUseXSelect(pExpr) ){ @@ -147824,6 +153098,7 @@ static void substSelect( SrcItem *pItem; int i; if( !p ) return; + pSubst->nSelDepth++; do{ substExprList(pSubst, p->pEList); substExprList(pSubst, p->pGroupBy); @@ -147841,6 +153116,7 @@ static void substSelect( } } }while( doPrior && (p = p->pPrior)!=0 ); + pSubst->nSelDepth--; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ @@ -148056,9 +153332,9 @@ static int compoundHasDifferentAffinities(Select *p){ ** from 2015-02-09.) ** ** (3) If the subquery is the right operand of a LEFT JOIN then -** (3a) the subquery may not be a join and -** (3b) the FROM clause of the subquery may not contain a virtual -** table and +** (3a) the subquery may not be a join +** (**) Was (3b): "the FROM clause of the subquery may not contain +** a virtual table" ** (**) Was: "The outer query may not have a GROUP BY." This case ** is now managed correctly ** (3d) the outer query may not be DISTINCT. @@ -148274,7 +153550,7 @@ static int flattenSubquery( */ if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){ if( pSubSrc->nSrc>1 /* (3a) */ - || IsVirtual(pSubSrc->a[0].pSTab) /* (3b) */ + /**** || IsVirtual(pSubSrc->a[0].pSTab) (3b)-omitted */ || (p->selFlags & SF_Distinct)!=0 /* (3d) */ || (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */ ){ @@ -148452,7 +153728,7 @@ static int flattenSubquery( ** complete, since there may still exist Expr.pTab entries that ** refer to the subquery even after flattening. Ticket #3346. ** - ** pSubitem->pTab is always non-NULL by test restrictions and tests above. + ** pSubitem->pSTab is always non-NULL by test restrictions and tests above. */ if( ALWAYS(pSubitem->pSTab!=0) ){ Table *pTabToDel = pSubitem->pSTab; @@ -148482,17 +153758,12 @@ static int flattenSubquery( pSub = pSub1; for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){ int nSubSrc; - u8 jointype = 0; - u8 ltorj = pSrc->a[iFrom].fg.jointype & JT_LTORJ; + u8 jointype = pSubitem->fg.jointype; assert( pSub!=0 ); pSubSrc = pSub->pSrc; /* FROM clause of subquery */ nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */ pSrc = pParent->pSrc; /* FROM clause of the outer query */ - if( pParent==p ){ - jointype = pSubitem->fg.jointype; /* First time through the loop */ - } - /* The subquery uses a single slot of the FROM clause of the outer ** query. If the subquery has more than one element in its FROM clause, ** then expand the outer query to make space for it to hold all elements @@ -148512,11 +153783,13 @@ static int flattenSubquery( pSrc = sqlite3SrcListEnlarge(pParse, pSrc, nSubSrc-1,iFrom+1); if( pSrc==0 ) break; pParent->pSrc = pSrc; + pSubitem = &pSrc->a[iFrom]; } /* Transfer the FROM clause terms from the subquery into the ** outer query. */ + iNewParent = pSubSrc->a[0].iCursor; for(i=0; ia[i+iFrom]; assert( pItem->fg.isTabFunc==0 ); @@ -148525,14 +153798,12 @@ static int flattenSubquery( || pItem->u4.zDatabase==0 ); if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing); *pItem = pSubSrc->a[i]; - pItem->fg.jointype |= ltorj; - iNewParent = pSubSrc->a[i].iCursor; + pItem->fg.jointype |= (jointype & JT_LTORJ); memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); } - pSrc->a[iFrom].fg.jointype &= JT_LTORJ; - pSrc->a[iFrom].fg.jointype |= jointype | ltorj; + pSubitem->fg.jointype |= jointype; - /* Now begin substituting subquery result set expressions for + /* Begin substituting subquery result set expressions for ** references to the iParent in the outer query. ** ** Example: @@ -148544,7 +153815,7 @@ static int flattenSubquery( ** We look at every expression in the outer query and every place we see ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". */ - if( pSub->pOrderBy && (pParent->selFlags & SF_NoopOrderBy)==0 ){ + if( pSub->pOrderBy ){ /* At this point, any non-zero iOrderByCol values indicate that the ** ORDER BY column expression is identical to the iOrderByCol'th ** expression returned by SELECT statement pSub. Since these values @@ -148552,9 +153823,9 @@ static int flattenSubquery( ** zero them before transferring the ORDER BY clause. ** ** Not doing this may cause an error if a subsequent call to this - ** function attempts to flatten a compound sub-query into pParent - ** (the only way this can happen is if the compound sub-query is - ** currently part of pSub->pSrc). See ticket [d11a6e908f]. */ + ** function attempts to flatten a compound sub-query into pParent. + ** See ticket [d11a6e908f]. + */ ExprList *pOrderBy = pSub->pOrderBy; for(i=0; inExpr; i++){ pOrderBy->a[i].u.x.iOrderByCol = 0; @@ -148566,6 +153837,7 @@ static int flattenSubquery( pWhere = pSub->pWhere; pSub->pWhere = 0; if( isOuterJoin>0 ){ + assert( pSubSrc->nSrc==1 ); sqlite3SetJoinExpr(pWhere, iNewParent, EP_OuterON); } if( pWhere ){ @@ -148581,6 +153853,7 @@ static int flattenSubquery( x.iTable = iParent; x.iNewTable = iNewParent; x.isOuterJoin = isOuterJoin; + x.nSelDepth = 0; x.pEList = pSub->pEList; x.pCList = findLeftmostExprlist(pSub); substSelect(&x, pParent, 0); @@ -148677,7 +153950,8 @@ static void constInsert( return; /* Already present. Return without doing anything. */ } } - if( sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ + assert( SQLITE_AFF_NONEbHasAffBlob = 1; } @@ -148752,7 +154026,8 @@ static int propagateConstantExprRewriteOne( if( pColumn==pExpr ) continue; if( pColumn->iTable!=pExpr->iTable ) continue; if( pColumn->iColumn!=pExpr->iColumn ) continue; - if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ + assert( SQLITE_AFF_NONEiCursor; x.iNewTable = pSrc->iCursor; x.isOuterJoin = 0; + x.nSelDepth = 0; x.pEList = pSubq->pEList; x.pCList = findLeftmostExprlist(pSubq); pNew = substExpr(&x, pNew); + assert( pNew!=0 || pParse->nErr!=0 ); + if( pParse->nErr==0 && pNew->op==TK_IN && ExprUseXSelect(pNew) ){ + assert( pNew->x.pSelect!=0 ); + pNew->x.pSelect->selFlags |= SF_ClonedRhsIn; + assert( pWhere!=0 ); + assert( pWhere->op==TK_IN ); + assert( ExprUseXSelect(pWhere) ); + assert( pWhere->x.pSelect!=0 ); + pWhere->x.pSelect->selFlags |= SF_ClonedRhsIn; + } #ifndef SQLITE_OMIT_WINDOWFUNC if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){ /* Restriction 6c has prevented push-down in this case */ @@ -149401,14 +154687,14 @@ SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){ ** SELECT * FROM (SELECT ... FROM t1 EXCEPT SELECT ... FROM t2) ** ORDER BY ... COLLATE ... ** -** This transformation is necessary because the multiSelectOrderBy() routine +** This transformation is necessary because the multiSelectByMerge() routine ** above that generates the code for a compound SELECT with an ORDER BY clause ** uses a merge algorithm that requires the same collating sequence on the ** result columns as on the ORDER BY clause. See ticket -** http://www.sqlite.org/src/info/6709574d2a +** http://sqlite.org/src/info/6709574d2a ** ** This transformation is only needed for EXCEPT, INTERSECT, and UNION. -** The UNION ALL operator works fine with multiSelectOrderBy() even when +** The UNION ALL operator works fine with multiSelectByMerge() even when ** there are COLLATE terms in the ORDER BY. */ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ @@ -149466,7 +154752,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ #ifndef SQLITE_OMIT_WINDOWFUNC p->pWinDefn = 0; #endif - p->selFlags &= ~SF_Compound; + p->selFlags &= ~(u32)SF_Compound; assert( (p->selFlags & SF_Converted)==0 ); p->selFlags |= SF_Converted; assert( pNew->pPrior!=0 ); @@ -149561,7 +154847,7 @@ SQLITE_PRIVATE With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ ** CTE expression, through routine checks to see if the reference is ** a recursive reference to the CTE. ** -** If pFrom matches a CTE according to either of these two above, pFrom->pTab +** If pFrom matches a CTE according to either of these two above, pFrom->pSTab ** and other fields are populated accordingly. ** ** Return 0 if no match is found. @@ -149882,7 +155168,7 @@ static int selectExpander(Walker *pWalker, Select *p){ pEList = p->pEList; if( pParse->pWith && (p->selFlags & SF_View) ){ if( p->pWith==0 ){ - p->pWith = (With*)sqlite3DbMallocZero(db, sizeof(With)); + p->pWith = (With*)sqlite3DbMallocZero(db, SZ_WITH(1) ); if( p->pWith==0 ){ return WRC_Abort; } @@ -149954,7 +155240,7 @@ static int selectExpander(Walker *pWalker, Select *p){ } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( ALWAYS(IsVirtual(pTab)) - && pFrom->fg.fromDDL + && (pFrom->fg.fromDDL || (pParse->prepFlags & SQLITE_PREPARE_FROM_DDL)) && ALWAYS(pTab->u.vtab.p!=0) && pTab->u.vtab.p->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0) ){ @@ -150599,6 +155885,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ if( pFunc->bOBPayload ){ /* extra columns for the function arguments */ assert( ExprUseXList(pFunc->pFExpr) ); + assert( pFunc->pFExpr->x.pList!=0 ); nExtra += pFunc->pFExpr->x.pList->nExpr; } if( pFunc->bUseSubtype ){ @@ -150669,7 +155956,7 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ } sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i)); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, (u8)nArg); + sqlite3VdbeChangeP5(v, (u16)nArg); sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, iTop); sqlite3ReleaseTempRange(pParse, regAgg, nArg); @@ -150832,7 +156119,7 @@ static void updateAccumulator( } sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i)); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, (u8)nArg); + sqlite3VdbeChangeP5(v, (u16)nArg); sqlite3ReleaseTempRange(pParse, regAgg, nArg); } if( addrNext ){ @@ -150906,7 +156193,7 @@ static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ && pExpr->pAggInfo==0 ){ sqlite3 *db = pWalker->pParse->db; - Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1"); + Expr *pNew = sqlite3ExprInt32(db, 1); if( pNew ){ Expr *pWhere = pS->pWhere; SWAP(Expr, *pNew, *pExpr); @@ -151021,6 +156308,7 @@ static void agginfoFree(sqlite3 *db, void *pArg){ ** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries ** * The outer query is a simple count(*) with no WHERE clause or other ** extraneous syntax. +** * None of the subqueries are DISTINCT (forumpost/a860f5fb2e 2025-03-10) ** ** Return TRUE if the optimization is undertaken. */ @@ -151053,7 +156341,11 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ if( pSub->pWhere ) return 0; /* No WHERE clause */ if( pSub->pLimit ) return 0; /* No LIMIT clause */ - if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ + if( pSub->selFlags & (SF_Aggregate|SF_Distinct) ){ + testcase( pSub->selFlags & SF_Aggregate ); + testcase( pSub->selFlags & SF_Distinct ); + return 0; /* Not an aggregate nor DISTINCT */ + } assert( pSub->pHaving==0 ); /* Due to the previous */ pSub = pSub->pPrior; /* Repeat over compound */ }while( pSub ); @@ -151065,14 +156357,14 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ pExpr = 0; pSub = sqlite3SubqueryDetach(db, pFrom); sqlite3SrcListDelete(db, p->pSrc); - p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc)); + p->pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1); while( pSub ){ Expr *pTerm; pPrior = pSub->pPrior; pSub->pPrior = 0; pSub->pNext = 0; pSub->selFlags |= SF_Aggregate; - pSub->selFlags &= ~SF_Compound; + pSub->selFlags &= ~(u32)SF_Compound; pSub->nSelectRow = 0; sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList); pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount; @@ -151087,7 +156379,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ pSub = pPrior; } p->pEList->a[0].pExpr = pExpr; - p->selFlags &= ~SF_Aggregate; + p->selFlags &= ~(u32)SF_Aggregate; #if TREETRACE_ENABLED if( sqlite3TreeTrace & 0x200 ){ @@ -151183,6 +156475,249 @@ static int fromClauseTermCanBeCoroutine( return 1; } +/* +** Argument pWhere is the WHERE clause belonging to SELECT statement p. This +** function attempts to transform expressions of the form: +** +** EXISTS (SELECT ...) +** +** into joins. For example, given +** +** CREATE TABLE sailors(sid INTEGER PRIMARY KEY, name TEXT); +** CREATE TABLE reserves(sid INT, day DATE, PRIMARY KEY(sid, day)); +** +** SELECT name FROM sailors AS S WHERE EXISTS ( +** SELECT * FROM reserves AS R WHERE S.sid = R.sid AND R.day = '2022-10-25' +** ); +** +** the SELECT statement may be transformed as follows: +** +** SELECT name FROM sailors AS S, reserves AS R +** WHERE S.sid = R.sid AND R.day = '2022-10-25'; +** +** **Approximately**. Really, we have to ensure that the FROM-clause term +** that was formerly inside the EXISTS is only executed once. This is handled +** by setting the SrcItem.fg.fromExists flag, which then causes code in +** the where.c file to exit the corresponding loop after the first successful +** match (if any). +*/ +static SQLITE_NOINLINE void existsToJoin( + Parse *pParse, /* Parsing context */ + Select *p, /* The SELECT statement being optimized */ + Expr *pWhere /* part of the WHERE clause currently being examined */ +){ + if( pParse->nErr==0 + && pWhere!=0 + && !ExprHasProperty(pWhere, EP_OuterON|EP_InnerON) + && ALWAYS(p->pSrc!=0) + && p->pSrc->nSrcpLimit==0 || p->pLimit->pRight==0) + ){ + if( pWhere->op==TK_AND ){ + Expr *pRight = pWhere->pRight; + existsToJoin(pParse, p, pWhere->pLeft); + existsToJoin(pParse, p, pRight); + } + else if( pWhere->op==TK_EXISTS ){ + Select *pSub = pWhere->x.pSelect; + Expr *pSubWhere = pSub->pWhere; + if( pSub->pSrc->nSrc==1 + && (pSub->selFlags & SF_Aggregate)==0 + && !pSub->pSrc->a[0].fg.isSubquery + && pSub->pLimit==0 + && pSub->pPrior==0 + ){ + /* Before combining the sub-select with the parent, renumber the + ** cursor used by the subselect. This is because the EXISTS expression + ** might be a copy of another EXISTS expression from somewhere + ** else in the tree, and in this case it is important that it use + ** a unique cursor number. */ + sqlite3 *db = pParse->db; + int *aCsrMap = sqlite3DbMallocZero(db, (pParse->nTab+2)*sizeof(int)); + if( aCsrMap==0 ) return; + aCsrMap[0] = (pParse->nTab+1); + renumberCursors(pParse, pSub, -1, aCsrMap); + sqlite3DbFree(db, aCsrMap); + + memset(pWhere, 0, sizeof(*pWhere)); + pWhere->op = TK_INTEGER; + pWhere->u.iValue = 1; + ExprSetProperty(pWhere, EP_IntValue); + assert( p->pWhere!=0 ); + pSub->pSrc->a[0].fg.fromExists = 1; + p->pSrc = sqlite3SrcListAppendList(pParse, p->pSrc, pSub->pSrc); + if( pSubWhere ){ + p->pWhere = sqlite3PExpr(pParse, TK_AND, p->pWhere, pSubWhere); + pSub->pWhere = 0; + } + pSub->pSrc = 0; + sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pSub); +#if TREETRACE_ENABLED + if( sqlite3TreeTrace & 0x100000 ){ + TREETRACE(0x100000,pParse,p, + ("After EXISTS-to-JOIN optimization:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + } + } + } +} + +/* +** Type used for Walker callbacks by selectCheckOnClauses(). +*/ +typedef struct CheckOnCtx CheckOnCtx; +struct CheckOnCtx { + SrcList *pSrc; /* SrcList for this context */ + int iJoin; /* Cursor numbers must be =< than this */ + int bFuncArg; /* True for table-function arg */ + CheckOnCtx *pParent; /* Parent context */ +}; + +/* +** True if the SrcList passed as the only argument contains at least +** one RIGHT or FULL JOIN. False otherwise. +*/ +#define hasRightJoin(pSrc) (((pSrc)->a[0].fg.jointype & JT_LTORJ)!=0) + +/* +** The xExpr callback for the search of invalid ON clause terms. +*/ +static int selectCheckOnClausesExpr(Walker *pWalker, Expr *pExpr){ + CheckOnCtx *pCtx = pWalker->u.pCheckOnCtx; + + /* Check if pExpr is root or near-root of an ON clause constraint that needs + ** to be checked to ensure that it does not refer to tables in its FROM + ** clause to the right of itself. i.e. it is either: + ** + ** + an ON clause on an OUTER join, or + ** + an ON clause on an INNER join within a FROM that features at + ** least one RIGHT or FULL join. + */ + if( (ExprHasProperty(pExpr, EP_OuterON)) + || (ExprHasProperty(pExpr, EP_InnerON) && hasRightJoin(pCtx->pSrc)) + ){ + /* If CheckOnCtx.iJoin is already set, then fall through and process + ** this expression node as normal. Or, if CheckOnCtx.iJoin is still 0, + ** set it to the cursor number of the RHS of the join to which this + ** ON expression was attached and then iterate through the entire + ** expression. */ + assert( pCtx->iJoin==0 || pCtx->iJoin==pExpr->w.iJoin ); + if( pCtx->iJoin==0 ){ + pCtx->iJoin = pExpr->w.iJoin; + sqlite3WalkExprNN(pWalker, pExpr); + pCtx->iJoin = 0; + return WRC_Prune; + } + } + + if( pExpr->op==TK_COLUMN ){ + /* A column expression. Find the SrcList (if any) to which it refers. + ** Then, if CheckOnCtx.iJoin indicates that this expression is part of an + ** ON clause from that SrcList (i.e. if iJoin is non-zero), check that it + ** does not refer to a table to the right of CheckOnCtx.iJoin. */ + do { + SrcList *pSrc = pCtx->pSrc; + int nSrc = pSrc->nSrc; + int iTab = pExpr->iTable; + int ii; + for(ii=0; iia[ii].iCursor!=iTab; ii++){} + if( iiiJoin && iTab>pCtx->iJoin ){ + sqlite3ErrorMsg(pWalker->pParse, + "%s references tables to its right", + (pCtx->bFuncArg ? "table-function argument" : "ON clause") + ); + return WRC_Abort; + } + break; + } + pCtx = pCtx->pParent; + }while( pCtx ); + } + return WRC_Continue; +} + +/* +** The xSelect callback for the search of invalid ON clause terms. +*/ +static int selectCheckOnClausesSelect(Walker *pWalker, Select *pSelect){ + CheckOnCtx *pCtx = pWalker->u.pCheckOnCtx; + if( pSelect->pSrc==pCtx->pSrc || pSelect->pSrc->nSrc==0 ){ + return WRC_Continue; + }else{ + CheckOnCtx sCtx; + memset(&sCtx, 0, sizeof(sCtx)); + sCtx.pSrc = pSelect->pSrc; + sCtx.pParent = pCtx; + pWalker->u.pCheckOnCtx = &sCtx; + sqlite3WalkSelect(pWalker, pSelect); + pWalker->u.pCheckOnCtx = pCtx; + pSelect->selFlags &= ~SF_OnToWhere; + return WRC_Prune; + } +} + +/* +** Check all ON clauses in pSelect to verify that they do not reference +** columns to the right. +*/ +SQLITE_PRIVATE void sqlite3SelectCheckOnClauses(Parse *pParse, Select *pSelect){ + Walker w; + CheckOnCtx sCtx; + int ii; + assert( pSelect->selFlags & SF_OnToWhere ); + assert( pSelect->pSrc!=0 && pSelect->pSrc->nSrc>=2 ); + memset(&w, 0, sizeof(w)); + w.pParse = pParse; + w.xExprCallback = selectCheckOnClausesExpr; + w.xSelectCallback = selectCheckOnClausesSelect; + w.u.pCheckOnCtx = &sCtx; + memset(&sCtx, 0, sizeof(sCtx)); + sCtx.pSrc = pSelect->pSrc; + sqlite3WalkExpr(&w, pSelect->pWhere); + pSelect->selFlags &= ~SF_OnToWhere; + + /* Check for any table-function args that are attached to virtual tables + ** on the RHS of an outer join. They are subject to the same constraints + ** as ON clauses. */ + sCtx.bFuncArg = 1; + for(ii=0; iipSrc->nSrc; ii++){ + SrcItem *pItem = &pSelect->pSrc->a[ii]; + if( pItem->fg.isTabFunc + && (pItem->fg.jointype & JT_OUTER) + ){ + sCtx.iJoin = pItem->iCursor; + sqlite3WalkExprList(&w, pItem->u1.pFuncArg); + } + } +} + +/* +** If p2 exists and p1 and p2 have the same number of terms, then change +** every term of p1 to have the same sort order as p2 and return true. +** +** If p2 is NULL or p1 and p2 are different lengths, then make no changes +** and return false. +** +** p1 must be non-NULL. +*/ +static int sqlite3CopySortOrder(ExprList *p1, ExprList *p2){ + assert( p1 ); + if( p2 && p1->nExpr==p2->nExpr ){ + int ii; + for(ii=0; iinExpr; ii++){ + u8 sortFlags; + sortFlags = p2->a[ii].fg.sortFlags & KEYINFO_ORDER_DESC; + p1->a[ii].fg.sortFlags = sortFlags; + } + return 1; + }else{ + return 0; + } +} + /* ** Generate byte-code for the SELECT statement given in the p argument. ** @@ -151278,8 +156813,7 @@ SQLITE_PRIVATE int sqlite3Select( assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue ); if( IgnorableDistinct(pDest) ){ - assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || - pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || + assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Discard || pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_DistFifo ); /* All of these destinations are also able to ignore the ORDER BY clause */ if( p->pOrderBy ){ @@ -151294,8 +156828,7 @@ SQLITE_PRIVATE int sqlite3Select( testcase( pParse->earlyCleanup ); p->pOrderBy = 0; } - p->selFlags &= ~SF_Distinct; - p->selFlags |= SF_NoopOrderBy; + p->selFlags &= ~(u32)SF_Distinct; } sqlite3SelectPrep(pParse, p, 0); if( pParse->nErr ){ @@ -151333,7 +156866,7 @@ SQLITE_PRIVATE int sqlite3Select( ** and leaving this flag set can cause errors if a compound sub-query ** in p->pSrc is flattened into this query and this function called ** again as part of compound SELECT processing. */ - p->selFlags &= ~SF_UFSrcCheck; + p->selFlags &= ~(u32)SF_UFSrcCheck; } if( pDest->eDest==SRT_Output ){ @@ -151551,6 +157084,13 @@ SQLITE_PRIVATE int sqlite3Select( } #endif + /* If there may be an "EXISTS (SELECT ...)" in the WHERE clause, attempt + ** to change it into a join. */ + if( pParse->bHasExists && OptimizationEnabled(db,SQLITE_ExistsToJoin) ){ + existsToJoin(pParse, p, p->pWhere); + pTabList = p->pSrc; + } + /* Do the WHERE-clause constant propagation optimization if this is ** a join. No need to spend time on this operation for non-join queries ** as the equivalent optimization will be handled by query planner in @@ -151665,7 +157205,7 @@ SQLITE_PRIVATE int sqlite3Select( #endif assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 ); }else{ - TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n")); + TREETRACE(0x4000,pParse,p,("WHERE-clause push-down not possible\n")); } /* Convert unused result columns of the subquery into simple NULL @@ -151816,13 +157356,14 @@ SQLITE_PRIVATE int sqlite3Select( ** BY and DISTINCT, and an index or separate temp-table for the other. */ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct - && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0 + && sqlite3CopySortOrder(pEList, sSort.pOrderBy) + && sqlite3ExprListCompare(pEList, sSort.pOrderBy, -1)==0 && OptimizationEnabled(db, SQLITE_GroupByOrder) #ifndef SQLITE_OMIT_WINDOWFUNC && p->pWin==0 #endif ){ - p->selFlags &= ~SF_Distinct; + p->selFlags &= ~(u32)SF_Distinct; pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0); if( pGroupBy ){ for(i=0; inExpr; i++){ @@ -151931,6 +157472,12 @@ SQLITE_PRIVATE int sqlite3Select( if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); + if( pDest->eDest<=SRT_DistQueue && pDest->eDest>=SRT_DistFifo ){ + /* TUNING: For a UNION CTE, because UNION is implies DISTINCT, + ** reduce the estimated output row count by 8 (LogEst 30). + ** Search for tag-20250414a to see other cases */ + p->nSelectRow -= 30; + } } if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); @@ -152024,21 +157571,10 @@ SQLITE_PRIVATE int sqlite3Select( ** but not actually sorted. Either way, record the fact that the ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp ** variable. */ - if( sSort.pOrderBy && pGroupBy->nExpr==sSort.pOrderBy->nExpr ){ - int ii; - /* The GROUP BY processing doesn't care whether rows are delivered in - ** ASC or DESC order - only that each group is returned contiguously. - ** So set the ASC/DESC flags in the GROUP BY to match those in the - ** ORDER BY to maximize the chances of rows being delivered in an - ** order that makes the ORDER BY redundant. */ - for(ii=0; iinExpr; ii++){ - u8 sortFlags; - sortFlags = sSort.pOrderBy->a[ii].fg.sortFlags & KEYINFO_ORDER_DESC; - pGroupBy->a[ii].fg.sortFlags = sortFlags; - } - if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){ - orderByGrp = 1; - } + if( sqlite3CopySortOrder(pGroupBy, sSort.pOrderBy) + && sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 + ){ + orderByGrp = 1; } }else{ assert( 0==sqlite3LogEst(1) ); @@ -152161,6 +157697,7 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag); VdbeComment((v, "clear abort flag")); sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1); + sqlite3ExprNullRegisterRange(pParse, iAMem, pGroupBy->nExpr); /* Begin a loop that will extract all source rows in GROUP BY order. ** This might involve two separate loops with an OP_Sort in between, or @@ -152304,6 +157841,10 @@ SQLITE_PRIVATE int sqlite3Select( if( iOrderByCol ){ Expr *pX = p->pEList->a[iOrderByCol-1].pExpr; Expr *pBase = sqlite3ExprSkipCollateAndLikely(pX); + while( ALWAYS(pBase!=0) && pBase->op==TK_IF_NULL_ROW ){ + pX = pBase->pLeft; + pBase = sqlite3ExprSkipCollateAndLikely(pX); + } if( ALWAYS(pBase!=0) && pBase->op!=TK_AGG_COLUMN && pBase->op!=TK_REGISTER @@ -152327,12 +157868,12 @@ SQLITE_PRIVATE int sqlite3Select( ** for the next GROUP BY batch. */ sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); - VdbeComment((v, "output one row")); + VdbeComment((v, "output one row of %d", p->selId)); sqlite3ExprCodeMove(pParse, iBMem, iAMem, pGroupBy->nExpr); sqlite3VdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd); VdbeCoverage(v); VdbeComment((v, "check abort flag")); sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); - VdbeComment((v, "reset accumulator")); + VdbeComment((v, "reset accumulator %d", p->selId)); /* Update the aggregate accumulators based on the content of ** the current row @@ -152340,7 +157881,7 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeJumpHere(v, addr1); updateAccumulator(pParse, iUseFlag, pAggInfo, eDist); sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag); - VdbeComment((v, "indicate data in accumulator")); + VdbeComment((v, "indicate data in accumulator %d", p->selId)); /* End of the loop */ @@ -152357,7 +157898,7 @@ SQLITE_PRIVATE int sqlite3Select( /* Output the final row of result */ sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); - VdbeComment((v, "output final row")); + VdbeComment((v, "output final row of %d", p->selId)); /* Jump over the subroutines */ @@ -152378,7 +157919,7 @@ SQLITE_PRIVATE int sqlite3Select( addrOutputRow = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v); - VdbeComment((v, "Groupby result generator entry point")); + VdbeComment((v, "Groupby result generator entry point %d", p->selId)); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); finalizeAggFunctions(pParse, pAggInfo); sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); @@ -152386,14 +157927,14 @@ SQLITE_PRIVATE int sqlite3Select( &sDistinct, pDest, addrOutputRow+1, addrSetAbort); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); - VdbeComment((v, "end groupby result generator")); + VdbeComment((v, "end groupby result generator %d", p->selId)); /* Generate a subroutine that will reset the group-by accumulator */ sqlite3VdbeResolveLabel(v, addrReset); resetAccumulator(pParse, pAggInfo); sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag); - VdbeComment((v, "indicate accumulator empty")); + VdbeComment((v, "indicate accumulator %d empty", p->selId)); sqlite3VdbeAddOp1(v, OP_Return, regReset); if( distFlag!=0 && eDist!=WHERE_DISTINCT_NOOP ){ @@ -152843,7 +158384,7 @@ SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerS sqlite3SelectDelete(db, pTmp->pSelect); sqlite3IdListDelete(db, pTmp->pIdList); sqlite3UpsertDelete(db, pTmp->pUpsert); - sqlite3SrcListDelete(db, pTmp->pFrom); + sqlite3SrcListDelete(db, pTmp->pSrc); sqlite3DbFree(db, pTmp->zSpan); sqlite3DbFree(db, pTmp); @@ -152887,7 +158428,8 @@ SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ assert( pParse->db->pVtabCtx==0 ); #endif assert( pParse->bReturning ); - assert( &(pParse->u1.pReturning->retTrig) == pTrig ); + assert( !pParse->isCreate ); + assert( &(pParse->u1.d.pReturning->retTrig) == pTrig ); pTrig->table = pTab->zName; pTrig->pTabSchema = pTab->pSchema; pTrig->pNext = pList; @@ -153031,11 +158573,16 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( } } + /* NB: The SQLITE_ALLOW_TRIGGERS_ON_SYSTEM_TABLES compile-time option is + ** experimental and unsupported. Do not use it unless understand the + ** implications and you cannot get by without this capability. */ +#if !defined(SQLITE_ALLOW_TRIGGERS_ON_SYSTEM_TABLES) /* Experimental */ /* Do not create a trigger on a system table */ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ sqlite3ErrorMsg(pParse, "cannot create trigger on system table"); goto trigger_cleanup; } +#endif /* INSTEAD of triggers are only for views and views only support INSTEAD ** of triggers. @@ -153147,6 +158694,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; zName = pTrig->zName; iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); + assert( iDb>=00 && iDbnDb ); pTrig->step_list = pStepList; while( pStepList ){ pStepList->pTrig = pTrig; @@ -153181,12 +158729,12 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( if( sqlite3ReadOnlyShadowTables(db) ){ TriggerStep *pStep; for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){ - if( pStep->zTarget!=0 - && sqlite3ShadowTableName(db, pStep->zTarget) + if( pStep->pSrc!=0 + && sqlite3ShadowTableName(db, pStep->pSrc->a[0].zName) ){ sqlite3ErrorMsg(pParse, "trigger \"%s\" may not write to shadow table \"%s\"", - pTrig->zName, pStep->zTarget); + pTrig->zName, pStep->pSrc->a[0].zName); goto triggerfinish_cleanup; } } @@ -153277,26 +158825,39 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep( static TriggerStep *triggerStepAllocate( Parse *pParse, /* Parser context */ u8 op, /* Trigger opcode */ - Token *pName, /* The target name */ + SrcList *pTabList, /* Target table */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ + Trigger *pNew = pParse->pNewTrigger; sqlite3 *db = pParse->db; - TriggerStep *pTriggerStep; + TriggerStep *pTriggerStep = 0; - if( pParse->nErr ) return 0; - pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1); - if( pTriggerStep ){ - char *z = (char*)&pTriggerStep[1]; - memcpy(z, pName->z, pName->n); - sqlite3Dequote(z); - pTriggerStep->zTarget = z; - pTriggerStep->op = op; - pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); - if( IN_RENAME_OBJECT ){ - sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName); + if( pParse->nErr==0 ){ + if( pNew + && pNew->pSchema!=db->aDb[1].pSchema + && pTabList->a[0].u4.zDatabase + ){ + sqlite3ErrorMsg(pParse, + "qualified table names are not allowed on INSERT, UPDATE, and DELETE " + "statements within triggers"); + }else{ + pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep)); + if( pTriggerStep ){ + pTriggerStep->pSrc = sqlite3SrcListDup(db, pTabList, EXPRDUP_REDUCE); + pTriggerStep->op = op; + pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); + if( pTriggerStep->pSrc && IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, + pTriggerStep->pSrc->a[0].zName, + pTabList->a[0].zName + ); + } + } } } + + sqlite3SrcListDelete(db, pTabList); return pTriggerStep; } @@ -153309,7 +158870,7 @@ static TriggerStep *triggerStepAllocate( */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( Parse *pParse, /* Parser */ - Token *pTableName, /* Name of the table into which we insert */ + SrcList *pTabList, /* Table to INSERT into */ IdList *pColumn, /* List of columns in pTableName to insert into */ Select *pSelect, /* A SELECT statement that supplies values */ u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ @@ -153322,7 +158883,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( assert(pSelect != 0 || db->mallocFailed); - pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd); + pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTabList, zStart, zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pSelect = pSelect; @@ -153354,7 +158915,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( Parse *pParse, /* Parser */ - Token *pTableName, /* Name of the table to be updated */ + SrcList *pTabList, /* Name of the table to be updated */ SrcList *pFrom, /* FROM clause for an UPDATE-FROM, or NULL */ ExprList *pEList, /* The SET clause: list of column and new values */ Expr *pWhere, /* The WHERE clause */ @@ -153365,21 +158926,36 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; - pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd); + pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTabList, zStart, zEnd); if( pTriggerStep ){ + SrcList *pFromDup = 0; if( IN_RENAME_OBJECT ){ pTriggerStep->pExprList = pEList; pTriggerStep->pWhere = pWhere; - pTriggerStep->pFrom = pFrom; + pFromDup = pFrom; pEList = 0; pWhere = 0; pFrom = 0; }else{ pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); - pTriggerStep->pFrom = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE); + pFromDup = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE); } pTriggerStep->orconf = orconf; + + if( pFromDup && !IN_RENAME_OBJECT){ + Select *pSub; + Token as = {0, 0}; + pSub = sqlite3SelectNew(pParse, 0, pFromDup, 0,0,0,0, SF_NestedFrom, 0); + pFromDup = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &as, pSub ,0); + } + if( pFromDup && pTriggerStep->pSrc ){ + pTriggerStep->pSrc = sqlite3SrcListAppendList( + pParse, pTriggerStep->pSrc, pFromDup + ); + }else{ + sqlite3SrcListDelete(db, pFromDup); + } } sqlite3ExprListDelete(db, pEList); sqlite3ExprDelete(db, pWhere); @@ -153394,7 +158970,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep( Parse *pParse, /* Parser */ - Token *pTableName, /* The table from which rows are deleted */ + SrcList *pTabList, /* The table from which rows are deleted */ Expr *pWhere, /* The WHERE clause */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ @@ -153402,7 +158978,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep( sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; - pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd); + pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTabList, zStart, zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pWhere = pWhere; @@ -153602,6 +159178,7 @@ static SQLITE_NOINLINE Trigger *triggersReallyExist( p = pList; if( (pParse->db->flags & SQLITE_EnableTrigger)==0 && pTab->pTrigger!=0 + && sqlite3SchemaToIndex(pParse->db, pTab->pTrigger->pSchema)!=1 ){ /* The SQLITE_DBCONFIG_ENABLE_TRIGGER setting is off. That means that ** only TEMP triggers are allowed. Truncate the pList so that it @@ -153664,52 +159241,6 @@ SQLITE_PRIVATE Trigger *sqlite3TriggersExist( return triggersReallyExist(pParse,pTab,op,pChanges,pMask); } -/* -** Convert the pStep->zTarget string into a SrcList and return a pointer -** to that SrcList. -** -** This routine adds a specific database name, if needed, to the target when -** forming the SrcList. This prevents a trigger in one database from -** referring to a target in another database. An exception is when the -** trigger is in TEMP in which case it can refer to any other database it -** wants. -*/ -SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc( - Parse *pParse, /* The parsing context */ - TriggerStep *pStep /* The trigger containing the target token */ -){ - sqlite3 *db = pParse->db; - SrcList *pSrc; /* SrcList to be returned */ - char *zName = sqlite3DbStrDup(db, pStep->zTarget); - pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); - assert( pSrc==0 || pSrc->nSrc==1 ); - assert( zName || pSrc==0 ); - if( pSrc ){ - Schema *pSchema = pStep->pTrig->pSchema; - pSrc->a[0].zName = zName; - if( pSchema!=db->aDb[1].pSchema ){ - assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 ); - pSrc->a[0].u4.pSchema = pSchema; - pSrc->a[0].fg.fixedSchema = 1; - } - if( pStep->pFrom ){ - SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0); - if( pDup && pDup->nSrc>1 && !IN_RENAME_OBJECT ){ - Select *pSubquery; - Token as; - pSubquery = sqlite3SelectNew(pParse,0,pDup,0,0,0,0,SF_NestedFrom,0); - as.n = 0; - as.z = 0; - pDup = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); - } - pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup); - } - }else{ - sqlite3DbFree(db, zName); - } - return pSrc; -} - /* ** Return true if the pExpr term from the RETURNING clause argument ** list is of the form "*". Raise an error if the terms if of the @@ -153855,7 +159386,11 @@ static void codeReturningTrigger( ExprList *pNew; Returning *pReturning; Select sSelect; - SrcList sFrom; + SrcList *pFrom; + union { + SrcList sSrc; + u8 fromSpace[SZ_SRCLIST_1]; + } uSrc; assert( v!=0 ); if( !pParse->bReturning ){ @@ -153864,19 +159399,21 @@ static void codeReturningTrigger( return; } assert( db->pParse==pParse ); - pReturning = pParse->u1.pReturning; + assert( !pParse->isCreate ); + pReturning = pParse->u1.d.pReturning; if( pTrigger != &(pReturning->retTrig) ){ /* This RETURNING trigger is for a different statement */ return; } memset(&sSelect, 0, sizeof(sSelect)); - memset(&sFrom, 0, sizeof(sFrom)); + memset(&uSrc, 0, sizeof(uSrc)); + pFrom = &uSrc.sSrc; sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); - sSelect.pSrc = &sFrom; - sFrom.nSrc = 1; - sFrom.a[0].pSTab = pTab; - sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */ - sFrom.a[0].iCursor = -1; + sSelect.pSrc = pFrom; + pFrom->nSrc = 1; + pFrom->a[0].pSTab = pTab; + pFrom->a[0].zName = pTab->zName; /* tag-20240424-1 */ + pFrom->a[0].iCursor = -1; sqlite3SelectPrep(pParse, &sSelect, 0); if( pParse->nErr==0 ){ assert( db->mallocFailed==0 ); @@ -153969,7 +159506,7 @@ static int codeTriggerProgram( switch( pStep->op ){ case TK_UPDATE: { sqlite3Update(pParse, - sqlite3TriggerStepSrc(pParse, pStep), + sqlite3SrcListDup(db, pStep->pSrc, 0), sqlite3ExprListDup(db, pStep->pExprList, 0), sqlite3ExprDup(db, pStep->pWhere, 0), pParse->eOrconf, 0, 0, 0 @@ -153979,7 +159516,7 @@ static int codeTriggerProgram( } case TK_INSERT: { sqlite3Insert(pParse, - sqlite3TriggerStepSrc(pParse, pStep), + sqlite3SrcListDup(db, pStep->pSrc, 0), sqlite3SelectDup(db, pStep->pSelect, 0), sqlite3IdListDup(db, pStep->pIdList), pParse->eOrconf, @@ -153990,7 +159527,7 @@ static int codeTriggerProgram( } case TK_DELETE: { sqlite3DeleteFrom(pParse, - sqlite3TriggerStepSrc(pParse, pStep), + sqlite3SrcListDup(db, pStep->pSrc, 0), sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0 ); sqlite3VdbeAddOp0(v, OP_ResetCount); @@ -154055,7 +159592,7 @@ static TriggerPrg *codeRowTrigger( Table *pTab, /* The table pTrigger is attached to */ int orconf /* ON CONFLICT policy to code trigger program with */ ){ - Parse *pTop = sqlite3ParseToplevel(pParse); + Parse *pTop; /* Top level Parse object */ sqlite3 *db = pParse->db; /* Database handle */ TriggerPrg *pPrg; /* Value to return */ Expr *pWhen = 0; /* Duplicate of trigger WHEN expression */ @@ -154064,10 +159601,24 @@ static TriggerPrg *codeRowTrigger( SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ int iEndTrigger = 0; /* Label to jump to if WHEN is false */ Parse sSubParse; /* Parse context for sub-vdbe */ + int nDepth; /* Trigger depth */ + + /* Ensure that triggers are not chained too deep. This test is linear + ** in the chaining depth, but sensible code ought not be chaining + ** triggers excessively, so that shouldn't be a problem. + */ + pTop = pParse; + for(nDepth=0; pTop->pOuterParse; pTop = pTop->pOuterParse, nDepth++){} + if( nDepth>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){ + sqlite3ErrorMsg(pParse, "triggers nested too deep"); + return 0; + } + pTop = sqlite3ParseToplevel(pParse); assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) ); assert( pTop->pVdbe ); + /* Allocate the TriggerPrg and SubProgram objects. To ensure that they ** are freed if an error occurs, link them into the Parse.pTriggerPrg ** list of the top-level Parse object sooner rather than later. */ @@ -154094,6 +159645,8 @@ static TriggerPrg *codeRowTrigger( sSubParse.eTriggerOp = pTrigger->op; sSubParse.nQueryLoop = pParse->nQueryLoop; sSubParse.prepFlags = pParse->prepFlags; + sSubParse.oldmask = 0; + sSubParse.newmask = 0; v = sqlite3GetVdbe(&sSubParse); if( v ){ @@ -154226,7 +159779,7 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect( ** invocation is disallowed if (a) the sub-program is really a trigger, ** not a foreign key action, and (b) the flag to enable recursive triggers ** is clear. */ - sqlite3VdbeChangeP5(v, (u8)bRecursive); + sqlite3VdbeChangeP5(v, (u16)bRecursive); } } @@ -154848,38 +160401,32 @@ SQLITE_PRIVATE void sqlite3Update( */ chngRowid = chngPk = 0; for(i=0; inExpr; i++){ - u8 hCol = sqlite3StrIHash(pChanges->a[i].zEName); /* If this is an UPDATE with a FROM clause, do not resolve expressions ** here. The call to sqlite3Select() below will do that. */ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){ goto update_cleanup; } - for(j=0; jnCol; j++){ - if( pTab->aCol[j].hName==hCol - && sqlite3StrICmp(pTab->aCol[j].zCnName, pChanges->a[i].zEName)==0 - ){ - if( j==pTab->iPKey ){ - chngRowid = 1; - pRowidExpr = pChanges->a[i].pExpr; - iRowidExpr = i; - }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ - chngPk = 1; - } + j = sqlite3ColumnIndex(pTab, pChanges->a[i].zEName); + if( j>=0 ){ + if( j==pTab->iPKey ){ + chngRowid = 1; + pRowidExpr = pChanges->a[i].pExpr; + iRowidExpr = i; + }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ + chngPk = 1; + } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){ - testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ); - testcase( pTab->aCol[j].colFlags & COLFLAG_STORED ); - sqlite3ErrorMsg(pParse, - "cannot UPDATE generated column \"%s\"", - pTab->aCol[j].zCnName); - goto update_cleanup; - } -#endif - aXRef[j] = i; - break; + else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){ + testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[j].colFlags & COLFLAG_STORED ); + sqlite3ErrorMsg(pParse, + "cannot UPDATE generated column \"%s\"", + pTab->aCol[j].zCnName); + goto update_cleanup; } - } - if( j>=pTab->nCol ){ +#endif + aXRef[j] = i; + }else{ if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){ j = -1; chngRowid = 1; @@ -156072,7 +161619,8 @@ SQLITE_PRIVATE void sqlite3UpsertDoUpdate( /* excluded.* columns of type REAL need to be converted to a hard real */ for(i=0; inCol; i++){ if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ - sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i); + int iStorage = pTop->regData + sqlite3TableColumnToStorage(pTab, i); + sqlite3VdbeAddOp1(v, OP_RealAffinity, iStorage); } } sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0), @@ -156202,7 +161750,7 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){ #else /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments ** to VACUUM are silently ignored. This is a back-out of a bug fix that - ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270). + ** occurred on 2016-08-19 (https://sqlite.org/src/info/083f9e6270). ** The buggy behavior is required for binary compatibility with some ** legacy applications. */ iDb = sqlite3FindDb(pParse->db, pNm); @@ -156281,7 +161829,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; saved_mTrace = db->mTrace; - db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; + db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_Comments + | SQLITE_AttachCreate | SQLITE_AttachWrite; db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum; db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_Defensive | SQLITE_CountRows); @@ -156315,9 +161864,20 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( pDb = &db->aDb[nDb]; assert( strcmp(pDb->zDbSName,zDbVacuum)==0 ); pTemp = pDb->pBt; + nRes = sqlite3BtreeGetRequestedReserve(pMain); + + /* A VACUUM cannot change the pagesize of an encrypted database. */ + if( db->nextPagesize ){ + extern void sqlite3mcCodecGetKey(sqlite3*, int, void**, int*); + int nKey; + char *zKey; + sqlite3mcCodecGetKey(db, iDb, (void**)&zKey, &nKey); + if( nKey ) db->nextPagesize = 0; + } if( pOut ){ sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp)); i64 sz = 0; + const char *zFilename; if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){ rc = SQLITE_ERROR; sqlite3SetString(pzErrMsg, db, "output file already exists"); @@ -156329,8 +161889,16 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( ** they are for the database being vacuumed, except that PAGER_CACHESPILL ** is always set. */ pgflags = db->aDb[iDb].safety_level | (db->flags & PAGER_FLAGS_MASK); + + /* If the VACUUM INTO target file is a URI filename and if the + ** "reserve=N" query parameter is present, reset the reserve to the + ** amount specified, if the amount is within range */ + zFilename = sqlite3BtreeGetFilename(pTemp); + if( ALWAYS(zFilename) ){ + int nNew = (int)sqlite3_uri_int64(zFilename, "reserve", nRes); + if( nNew>=0 && nNew<=255 ) nRes = nNew; + } } - nRes = sqlite3BtreeGetRequestedReserve(pMain); sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); @@ -156649,6 +162217,7 @@ SQLITE_API int sqlite3_drop_modules(sqlite3 *db, const char** azNames){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif + sqlite3_mutex_enter(db->mutex); for(pThis=sqliteHashFirst(&db->aModule); pThis; pThis=pNext){ Module *pMod = (Module*)sqliteHashData(pThis); pNext = sqliteHashNext(pThis); @@ -156659,6 +162228,7 @@ SQLITE_API int sqlite3_drop_modules(sqlite3 *db, const char** azNames){ } createModule(db, pMod->zName, 0, 0, 0); } + sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -156986,11 +162556,12 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ ** schema table. We just need to update that slot with all ** the information we've collected. ** - ** The VM register number pParse->regRowid holds the rowid of an + ** The VM register number pParse->u1.cr.regRowid holds the rowid of an ** entry in the sqlite_schema table that was created for this vtab ** by sqlite3StartTable(). */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( pParse->isCreate ); sqlite3NestedParse(pParse, "UPDATE %Q." LEGACY_SCHEMA_TABLE " " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " @@ -156999,7 +162570,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ pTab->zName, pTab->zName, zStmt, - pParse->regRowid + pParse->u1.cr.regRowid ); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); @@ -157337,7 +162908,9 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ z = (const unsigned char*)zCreateTable; for(i=0; aKeyword[i]; i++){ int tokenType = 0; - do{ z += sqlite3GetToken(z, &tokenType); }while( tokenType==TK_SPACE ); + do{ + z += sqlite3GetToken(z, &tokenType); + }while( tokenType==TK_SPACE || tokenType==TK_COMMENT ); if( tokenType!=aKeyword[i] ){ sqlite3ErrorWithMsg(db, SQLITE_ERROR, "syntax error"); return SQLITE_ERROR; @@ -157783,9 +163356,12 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); addModuleArgument(pParse, pTab, 0); addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); + db->nSchemaLock++; rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr); + db->nSchemaLock--; if( rc ){ sqlite3ErrorMsg(pParse, "%s", zErr); + pParse->rc = rc; sqlite3DbFree(db, zErr); sqlite3VtabEponymousTableClear(db, pMod); } @@ -157981,6 +163557,7 @@ struct WhereLevel { int iTabCur; /* The VDBE cursor used to access the table */ int iIdxCur; /* The VDBE cursor used to access pIdx */ int addrBrk; /* Jump here to break out of the loop */ + int addrHalt; /* Abort the query due to empty table or similar */ int addrNxt; /* Jump here to start the next IN combination */ int addrSkip; /* Jump here for next iteration of skip-scan */ int addrCont; /* Jump here to continue with the next loop cycle */ @@ -158068,8 +163645,10 @@ struct WhereLoop { /**** whereLoopXfer() copies fields above ***********************/ # define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot) u16 nLSlot; /* Number of slots allocated for aLTerm[] */ +#ifdef WHERETRACE_ENABLED LogEst rStarDelta; /* Cost delta due to star-schema heuristic. Not - ** initialized unless pWInfo->nOutStarDelta>0 */ + ** initialized unless pWInfo->bStarUsed */ +#endif WhereTerm **aLTerm; /* WhereTerms used */ WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */ WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */ @@ -158118,7 +163697,7 @@ struct WherePath { Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */ LogEst nRow; /* Estimated number of rows generated by this path */ LogEst rCost; /* Total cost of this path */ - LogEst rUnsorted; /* Total cost of this path ignoring sorting costs */ + LogEst rUnsort; /* Total cost of this path ignoring sorting costs */ i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */ WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */ }; @@ -158184,6 +163763,9 @@ struct WhereTerm { u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X " */ +#ifdef SQLITE_DEBUG + int iTerm; /* Which WhereTerm is this, for debug purposes */ +#endif union { struct { int leftColumn; /* Column number of X in "X " */ @@ -158391,9 +163973,13 @@ struct WhereInfo { unsigned bDeferredSeek :1; /* Uses OP_DeferredSeek */ unsigned untestedTerms :1; /* Not all WHERE terms resolved by outer loop */ unsigned bOrderedInnerLoop:1;/* True if only the inner-most loop is ordered */ - unsigned sorted :1; /* True if really sorted (not just grouped) */ - LogEst nOutStarDelta; /* Artifical nOut reduction for star-query */ + unsigned sorted :1; /* True if really sorted (not just grouped) */ + unsigned bStarDone :1; /* True if check for star-query is complete */ + unsigned bStarUsed :1; /* True if star-query heuristic is used */ LogEst nRowOut; /* Estimated number of output rows */ +#ifdef WHERETRACE_ENABLED + LogEst rTotalCost; /* Total cost of the solution */ +#endif int iTop; /* The very beginning of the WHERE loop */ int iEndWhere; /* End of the WHERE clause itself */ WhereLoop *pLoops; /* List of all WhereLoop objects */ @@ -158401,9 +163987,14 @@ struct WhereInfo { Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ WhereClause sWC; /* Decomposition of the WHERE clause */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ - WhereLevel a[1]; /* Information about each nest loop in WHERE */ + WhereLevel a[FLEXARRAY]; /* Information about each nest loop in WHERE */ }; +/* +** The size (in bytes) of a WhereInfo object that holds N WhereLevels. +*/ +#define SZ_WHEREINFO(N) ROUND8(offsetof(WhereInfo,a)+(N)*sizeof(WhereLevel)) + /* ** Private interfaces - callable only by other where.c routines. ** @@ -158439,9 +164030,17 @@ SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter( const WhereInfo *pWInfo, /* WHERE clause */ const WhereLevel *pLevel /* Bloom filter on this level */ ); +SQLITE_PRIVATE void sqlite3WhereAddExplainText( + Parse *pParse, /* Parse context */ + int addr, + SrcList *pTabList, /* Table list this loop refers to */ + WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ + u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ +); #else # define sqlite3WhereExplainOneScan(u,v,w,x) 0 # define sqlite3WhereExplainBloomFilter(u,v,w) 0 +# define sqlite3WhereAddExplainText(u,v,w,x,y) #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS SQLITE_PRIVATE void sqlite3WhereAddScanStatus( @@ -158643,38 +164242,37 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ } /* -** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN -** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG -** was defined at compile-time. If it is not a no-op, a single OP_Explain -** opcode is added to the output to describe the table scan strategy in pLevel. -** -** If an OP_Explain opcode is added to the VM, its address is returned. -** Otherwise, if no OP_Explain is coded, zero is returned. +** This function sets the P4 value of an existing OP_Explain opcode to +** text describing the loop in pLevel. If the OP_Explain opcode already has +** a P4 value, it is freed before it is overwritten. */ -SQLITE_PRIVATE int sqlite3WhereExplainOneScan( +SQLITE_PRIVATE void sqlite3WhereAddExplainText( Parse *pParse, /* Parse context */ + int addr, /* Address of OP_Explain opcode */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ - int ret = 0; #if !defined(SQLITE_DEBUG) if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) ) #endif { + VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe, addr); SrcItem *pItem = &pTabList->a[pLevel->iFrom]; - Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ +#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) char *zMsg; /* Text to add to EQP output */ +#endif StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ + if( db->mallocFailed ) return; + pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; - if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) @@ -158682,7 +164280,10 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); str.printfFlags = SQLITE_PRINTF_INTERNAL; - sqlite3_str_appendf(&str, "%s %S", isSearch ? "SEARCH" : "SCAN", pItem); + sqlite3_str_appendf(&str, "%s %S%s", + isSearch ? "SEARCH" : "SCAN", + pItem, + pItem->fg.fromExists ? " EXISTS" : ""); if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ const char *zFmt = 0; Index *pIdx; @@ -158698,7 +164299,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( zFmt = "AUTOMATIC PARTIAL COVERING INDEX"; }else if( flags & WHERE_AUTO_INDEX ){ zFmt = "AUTOMATIC COVERING INDEX"; - }else if( flags & WHERE_IDX_ONLY ){ + }else if( flags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){ zFmt = "COVERING INDEX %s"; }else{ zFmt = "INDEX %s"; @@ -158750,11 +164351,50 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( sqlite3_str_append(&str, " (~1 row)", 9); } #endif +#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) zMsg = sqlite3StrAccumFinish(&str); sqlite3ExplainBreakpoint("",zMsg); - ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), - pParse->addrExplain, pLoop->rRun, - zMsg, P4_DYNAMIC); +#endif + + assert( pOp->opcode==OP_Explain ); + assert( pOp->p4type==P4_DYNAMIC || pOp->p4.z==0 ); + sqlite3DbFree(db, pOp->p4.z); + pOp->p4type = P4_DYNAMIC; + pOp->p4.z = sqlite3StrAccumFinish(&str); + } +} + + +/* +** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN +** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG +** was defined at compile-time. If it is not a no-op, a single OP_Explain +** opcode is added to the output to describe the table scan strategy in pLevel. +** +** If an OP_Explain opcode is added to the VM, its address is returned. +** Otherwise, if no OP_Explain is coded, zero is returned. +*/ +SQLITE_PRIVATE int sqlite3WhereExplainOneScan( + Parse *pParse, /* Parse context */ + SrcList *pTabList, /* Table list this loop refers to */ + WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ + u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ +){ + int ret = 0; +#if !defined(SQLITE_DEBUG) + if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) ) +#endif + { + if( (pLevel->pWLoop->wsFlags & WHERE_MULTI_OR)==0 + && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 + ){ + Vdbe *v = pParse->pVdbe; + int addr = sqlite3VdbeCurrentAddr(v); + ret = sqlite3VdbeAddOp3( + v, OP_Explain, addr, pParse->addrExplain, pLevel->pWLoop->rRun + ); + sqlite3WhereAddExplainText(pParse, addr, pTabList, pLevel, wctrlFlags); + } } return ret; } @@ -158853,9 +164493,10 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( } }else{ int addr; + VdbeOp *pOp; assert( pSrclist->a[pLvl->iFrom].fg.isSubquery ); addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub; - VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1); + pOp = sqlite3VdbeGetOp(v, addr-1); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine ); assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr ); sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1); @@ -159035,7 +164676,7 @@ static void adjustOrderByCol(ExprList *pOrderBy, ExprList *pEList){ /* ** pX is an expression of the form: (vector) IN (SELECT ...) ** In other words, it is a vector IN operator with a SELECT clause on the -** LHS. But not all terms in the vector are indexable and the terms might +** RHS. But not all terms in the vector are indexable and the terms might ** not be in the correct order for indexing. ** ** This routine makes a copy of the input pX expression and then adjusts @@ -159091,7 +164732,9 @@ static Expr *removeUnindexableInClauseTerms( int iField; assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 ); iField = pLoop->aLTerm[i]->u.x.iField - 1; - if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */ + if( NEVER(pOrigRhs->a[iField].pExpr==0) ){ + continue; /* Duplicate PK column */ + } pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr); pOrigRhs->a[iField].pExpr = 0; if( pRhs ) pRhs->a[pRhs->nExpr-1].u.x.iOrderByCol = iField+1; @@ -159108,6 +164751,7 @@ static Expr *removeUnindexableInClauseTerms( pNew->pLeft->x.pList = pLhs; } pSelect->pEList = pRhs; + pSelect->selId = ++pParse->nSelect; /* Req'd for SubrtnSig validity */ if( pLhs && pLhs->nExpr==1 ){ /* Take care here not to generate a TK_VECTOR containing only a ** single value. Since the parser never creates such a vector, some @@ -159187,7 +164831,7 @@ static SQLITE_NOINLINE void codeINTerm( return; } } - for(i=iEq;inLTerm; i++){ + for(i=iEq; inLTerm; i++){ assert( pLoop->aLTerm[i]!=0 ); if( pLoop->aLTerm[i]->pExpr==pX ) nEq++; } @@ -159196,22 +164840,13 @@ static SQLITE_NOINLINE void codeINTerm( if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab); }else{ - Expr *pExpr = pTerm->pExpr; - if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){ - sqlite3 *db = pParse->db; - pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX); - if( !db->mallocFailed ){ - aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq); - eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab); - pExpr->iTable = iTab; - } - sqlite3ExprDelete(db, pX); - }else{ - int n = sqlite3ExprVectorSize(pX->pLeft); - aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n)); - eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab); + sqlite3 *db = pParse->db; + Expr *pXMod = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX); + if( !db->mallocFailed ){ + aiMap = (int*)sqlite3DbMallocZero(db, sizeof(int)*nEq); + eType = sqlite3FindInIndex(pParse, pXMod, IN_INDEX_LOOP, 0, aiMap, &iTab); } - pX = pExpr; + sqlite3ExprDelete(db, pXMod); } if( eType==IN_INDEX_INDEX_DESC ){ @@ -159241,7 +164876,7 @@ static SQLITE_NOINLINE void codeINTerm( if( pIn ){ int iMap = 0; /* Index in aiMap[] */ pIn += i; - for(i=iEq;inLTerm; i++){ + for(i=iEq; inLTerm; i++){ if( pLoop->aLTerm[i]->pExpr==pX ){ int iOut = iTarget + i - iEq; if( eType==IN_INDEX_ROWID ){ @@ -159892,6 +165527,7 @@ static SQLITE_NOINLINE void filterPullDown( int addrNxt, /* Jump here to bypass inner loops */ Bitmask notReady /* Loops that are not ready */ ){ + int saved_addrBrk; while( ++iLevel < pWInfo->nLevel ){ WhereLevel *pLevel = &pWInfo->a[iLevel]; WhereLoop *pLoop = pLevel->pWLoop; @@ -159900,7 +165536,7 @@ static SQLITE_NOINLINE void filterPullDown( /* ,--- Because sqlite3ConstructBloomFilter() has will not have set ** vvvvv--' pLevel->regFilter if this were true. */ if( NEVER(pLoop->prereq & notReady) ) continue; - assert( pLevel->addrBrk==0 ); + saved_addrBrk = pLevel->addrBrk; pLevel->addrBrk = addrNxt; if( pLoop->wsFlags & WHERE_IPK ){ WhereTerm *pTerm = pLoop->aLTerm[0]; @@ -159930,7 +165566,7 @@ static SQLITE_NOINLINE void filterPullDown( VdbeCoverage(pParse->pVdbe); } pLevel->regFilter = 0; - pLevel->addrBrk = 0; + pLevel->addrBrk = saved_addrBrk; } } @@ -159977,7 +165613,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( sqlite3 *db; /* Database connection */ SrcItem *pTabItem; /* FROM clause term being coded */ int addrBrk; /* Jump here to break out of the loop */ - int addrHalt; /* addrBrk for the outermost loop */ int addrCont; /* Jump here to continue with next cycle */ int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ int iReleaseReg = 0; /* Temp register to free before returning */ @@ -160021,7 +165656,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** there are no IN operators in the constraints, the "addrNxt" label ** is the same as "addrBrk". */ - addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse); + addrBrk = pLevel->addrNxt = pLevel->addrBrk; addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(pParse); /* If this is the right table of a LEFT OUTER JOIN, allocate and @@ -160037,14 +165672,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( VdbeComment((v, "init LEFT JOIN match flag")); } - /* Compute a safe address to jump to if we discover that the table for - ** this loop is empty and can never contribute content. */ - for(j=iLevel; j>0; j--){ - if( pWInfo->a[j].iLeftJoin ) break; - if( pWInfo->a[j].pRJ ) break; - } - addrHalt = pWInfo->a[j].addrBrk; - /* Special case of a FROM clause subquery implemented as a co-routine */ if( pTabItem->fg.viaCoroutine ){ int regYield; @@ -160078,7 +165705,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( SMASKBIT32(j) & pLoop->u.vtab.mHandleIn ){ int iTab = pParse->nTab++; int iCache = ++pParse->nMem; - sqlite3CodeRhsOfIN(pParse, pTerm->pExpr, iTab); + sqlite3CodeRhsOfIN(pParse, pTerm->pExpr, iTab, 0); sqlite3VdbeAddOp3(v, OP_VInitIn, iTab, iTarget, iCache); }else{ codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); @@ -160100,6 +165727,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); + /* The instruction immediately prior to OP_VFilter must be an OP_Integer + ** that sets the "argc" value for xVFilter. This is necessary for + ** resolveP2() to work correctly. See tag-20250207a. */ sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pLoop->u.vtab.idxStr, pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC); @@ -160280,7 +165910,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( VdbeCoverageIf(v, pX->op==TK_GE); sqlite3ReleaseTempReg(pParse, rTemp); }else{ - sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt); + sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, pLevel->addrHalt); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); } @@ -160320,36 +165950,36 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); } }else if( pLoop->wsFlags & WHERE_INDEXED ){ - /* Case 4: A scan using an index. + /* Case 4: Search using an index. ** - ** The WHERE clause may contain zero or more equality - ** terms ("==" or "IN" operators) that refer to the N - ** left-most columns of the index. It may also contain - ** inequality constraints (>, <, >= or <=) on the indexed - ** column that immediately follows the N equalities. Only - ** the right-most column can be an inequality - the rest must - ** use the "==" and "IN" operators. For example, if the - ** index is on (x,y,z), then the following clauses are all - ** optimized: + ** The WHERE clause may contain zero or more equality + ** terms ("==" or "IN" or "IS" operators) that refer to the N + ** left-most columns of the index. It may also contain + ** inequality constraints (>, <, >= or <=) on the indexed + ** column that immediately follows the N equalities. Only + ** the right-most column can be an inequality - the rest must + ** use the "==", "IN", or "IS" operators. For example, if the + ** index is on (x,y,z), then the following clauses are all + ** optimized: ** - ** x=5 - ** x=5 AND y=10 - ** x=5 AND y<10 - ** x=5 AND y>5 AND y<10 - ** x=5 AND y=5 AND z<=10 + ** x=5 + ** x=5 AND y=10 + ** x=5 AND y<10 + ** x=5 AND y>5 AND y<10 + ** x=5 AND y=5 AND z<=10 ** - ** The z<10 term of the following cannot be used, only - ** the x=5 term: + ** The z<10 term of the following cannot be used, only + ** the x=5 term: ** - ** x=5 AND z<10 + ** x=5 AND z<10 ** - ** N may be zero if there are inequality constraints. - ** If there are no inequality constraints, then N is at - ** least one. + ** N may be zero if there are inequality constraints. + ** If there are no inequality constraints, then N is at + ** least one. ** - ** This case is also used when there are no WHERE clause - ** constraints but an index is selected anyway, in order - ** to force the output order to conform to an ORDER BY. + ** This case is also used when there are no WHERE clause + ** constraints but an index is selected anyway, in order + ** to force the output order to conform to an ORDER BY. */ static const u8 aStartOp[] = { 0, @@ -160690,12 +166320,13 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( pLevel->iLeftJoin==0 ){ /* If a partial index is driving the loop, try to eliminate WHERE clause ** terms from the query that must be true due to the WHERE clause of - ** the partial index. + ** the partial index. This optimization does not work on an outer join, + ** as shown by: ** - ** 2019-11-02 ticket 623eff57e76d45f6: This optimization does not work - ** for a LEFT JOIN. + ** 2019-11-02 ticket 623eff57e76d45f6 (LEFT JOIN) + ** 2025-05-29 forum post 7dee41d32506c4ae (RIGHT JOIN) */ - if( pIdx->pPartIdxWhere ){ + if( pIdx->pPartIdxWhere && pLevel->pRJ==0 ){ whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC); } }else{ @@ -160798,12 +166429,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** by this loop in the a[0] slot and all notReady tables in a[1..] slots. ** This becomes the SrcList in the recursive call to sqlite3WhereBegin(). */ - if( pWInfo->nLevel>1 ){ + if( pWInfo->nLevel>1 || pTabItem->fg.fromExists ){ int nNotReady; /* The number of notReady tables */ SrcItem *origSrc; /* Original list of tables */ nNotReady = pWInfo->nLevel - iLevel - 1; - pOrTab = sqlite3DbMallocRawNN(db, - sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); + pOrTab = sqlite3DbMallocRawNN(db, SZ_SRCLIST(nNotReady+1)); if( pOrTab==0 ) return notReady; pOrTab->nAlloc = (u8)(nNotReady + 1); pOrTab->nSrc = pOrTab->nAlloc; @@ -160812,6 +166442,13 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( for(k=1; k<=nNotReady; k++){ memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k])); } + + /* Clear the fromExists flag on the OR-optimized table entry so that + ** the calls to sqlite3WhereEnd() do not code early-exits after the + ** first row is visited. The early exit applies to this table's + ** overall loop - including the multiple OR branches and any WHERE + ** conditions not passed to the sub-loops - not to the sub-loops. */ + pOrTab->a[0].fg.fromExists = 0; }else{ pOrTab = pWInfo->pTabList; } @@ -160854,7 +166491,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** ** This optimization also only applies if the (x1 OR x2 OR ...) term ** is not contained in the ON clause of a LEFT JOIN. - ** See ticket http://www.sqlite.org/src/info/f2369304e4 + ** See ticket http://sqlite.org/src/info/f2369304e4 ** ** 2022-02-04: Do not push down slices of a row-value comparison. ** In other words, "w" or "y" may not be a slice of a vector. Otherwise, @@ -161055,7 +166692,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( assert( pLevel->op==OP_Return ); pLevel->p2 = sqlite3VdbeCurrentAddr(v); - if( pWInfo->nLevel>1 ){ sqlite3DbFreeNN(db, pOrTab); } + if( pWInfo->pTabList!=pOrTab ){ sqlite3DbFreeNN(db, pOrTab); } if( !untestedTerms ) disableTerm(pLevel, pTerm); }else #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ @@ -161075,7 +166712,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( codeCursorHint(pTabItem, pWInfo, pLevel, 0); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; - pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrHalt); + pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev],iCur,pLevel->addrHalt); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; @@ -161212,6 +166849,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( WO_EQ|WO_IN|WO_IS, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; + if( ExprHasProperty(pAlt->pExpr, EP_Collate) ) continue; if( (pAlt->eOperator & WO_IN) && ExprUseXSelect(pAlt->pExpr) && (pAlt->pExpr->x.pSelect->pEList->nExpr>1) @@ -161346,7 +166984,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( WhereInfo *pSubWInfo; WhereLoop *pLoop = pLevel->pWLoop; SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; - SrcList sFrom; + SrcList *pFrom; + union { + SrcList sSrc; + u8 fromSpace[SZ_SRCLIST_1]; + } uSrc; Bitmask mAll = 0; int k; @@ -161390,13 +167032,23 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( sqlite3ExprDup(pParse->db, pTerm->pExpr, 0)); } } - sFrom.nSrc = 1; - sFrom.nAlloc = 1; - memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem)); - sFrom.a[0].fg.jointype = 0; + if( pLevel->iIdxCur ){ + /* pSubWhere may contain expressions that read from an index on the + ** table on the RHS of the right join. All such expressions first test + ** if the index is pointing at a NULL row, and if so, read from the + ** table cursor instead. So ensure that the index cursor really is + ** pointing at a NULL row here, so that no values are read from it during + ** the scan of the RHS of the RIGHT join below. */ + sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur); + } + pFrom = &uSrc.sSrc; + pFrom->nSrc = 1; + pFrom->nAlloc = 1; + memcpy(&pFrom->a[0], pTabItem, sizeof(SrcItem)); + pFrom->a[0].fg.jointype = 0; assert( pParse->withinRJSubrtn < 100 ); pParse->withinRJSubrtn++; - pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0, + pSubWInfo = sqlite3WhereBegin(pParse, pFrom, pSubWhere, 0, 0, 0, WHERE_RIGHT_JOIN, 0); if( pSubWInfo ){ int iCur = pLevel->iTabCur; @@ -161655,12 +167307,12 @@ static int isLikeOrGlob( z = (u8*)pRight->u.zToken; } if( z ){ - /* Count the number of prefix bytes prior to the first wildcard. - ** or U+fffd character. If the underlying database has a UTF16LE - ** encoding, then only consider ASCII characters. Note that the - ** encoding of z[] is UTF8 - we are dealing with only UTF8 here in - ** this code, but the database engine itself might be processing - ** content using a different encoding. */ + /* Count the number of prefix bytes prior to the first wildcard, + ** U+fffd character, or malformed utf-8. If the underlying database + ** has a UTF16LE encoding, then only consider ASCII characters. Note that + ** the encoding of z[] is UTF8 - we are dealing with only UTF8 here in this + ** code, but the database engine itself might be processing content using a + ** different encoding. */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; @@ -161668,7 +167320,9 @@ static int isLikeOrGlob( cnt++; }else if( c>=0x80 ){ const u8 *z2 = z+cnt-1; - if( sqlite3Utf8Read(&z2)==0xfffd || ENC(db)==SQLITE_UTF16LE ){ + if( c==0xff || sqlite3Utf8Read(&z2)==0xfffd /* bad utf-8 */ + || ENC(db)==SQLITE_UTF16LE + ){ cnt--; break; }else{ @@ -161727,13 +167381,14 @@ static int isLikeOrGlob( ){ int isNum; double rDummy; - isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + assert( zNew[iTo]==0 ); + isNum = sqlite3AtoF(zNew, &rDummy); if( isNum<=0 ){ if( iTo==1 && zNew[0]=='-' ){ isNum = +1; }else{ zNew[iTo-1]++; - isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + isNum = sqlite3AtoF(zNew, &rDummy); zNew[iTo-1]--; } } @@ -161776,6 +167431,34 @@ static int isLikeOrGlob( } #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ +/* +** If pExpr is one of "like", "glob", "match", or "regexp", then +** return the corresponding SQLITE_INDEX_CONSTRAINT_xxxx value. +** If not, return 0. +** +** pExpr is guaranteed to be a TK_FUNCTION. +*/ +SQLITE_PRIVATE int sqlite3ExprIsLikeOperator(const Expr *pExpr){ + static const struct { + const char *zOp; + unsigned char eOp; + } aOp[] = { + { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, + { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, + { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, + { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } + }; + int i; + assert( pExpr->op==TK_FUNCTION ); + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + for(i=0; iu.zToken, aOp[i].zOp)==0 ){ + return aOp[i].eOp; + } + } + return 0; +} + #ifndef SQLITE_OMIT_VIRTUALTABLE /* @@ -161812,15 +167495,6 @@ static int isAuxiliaryVtabOperator( Expr **ppRight /* Expression to left of MATCH/op2 */ ){ if( pExpr->op==TK_FUNCTION ){ - static const struct Op2 { - const char *zOp; - unsigned char eOp2; - } aOp[] = { - { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, - { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, - { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, - { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } - }; ExprList *pList; Expr *pCol; /* Column reference */ int i; @@ -161840,16 +167514,11 @@ static int isAuxiliaryVtabOperator( */ pCol = pList->a[1].pExpr; assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) ); - if( ExprIsVtab(pCol) ){ - for(i=0; iu.zToken, aOp[i].zOp)==0 ){ - *peOp2 = aOp[i].eOp2; - *ppRight = pList->a[0].pExpr; - *ppLeft = pCol; - return 1; - } - } + if( ExprIsVtab(pCol) && (i = sqlite3ExprIsLikeOperator(pExpr))!=0 ){ + *peOp2 = i; + *ppRight = pList->a[0].pExpr; + *ppLeft = pCol; + return 1; } /* We can also match against the first column of overloaded @@ -161934,7 +167603,10 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){ pWC->a[iChild].iParent = iParent; pWC->a[iChild].truthProb = pWC->a[iParent].truthProb; + assert( pWC->a[iParent].nChild < UMXV(pWC->a[0].nChild) ); pWC->a[iParent].nChild++; + testcase( pWC->a[iParent].nChild == UMXV(pWC->a[0].nChild) ); + } /* @@ -161983,16 +167655,22 @@ static void whereCombineDisjuncts( Expr *pNew; /* New virtual expression */ int op; /* Operator for the combined expression */ int idxNew; /* Index in pWC of the next virtual term */ + Expr *pA, *pB; /* Expressions associated with pOne and pTwo */ if( (pOne->wtFlags | pTwo->wtFlags) & TERM_VNULL ) return; if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return; - assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 ); - assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 ); - if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; - if( sqlite3ExprCompare(0,pOne->pExpr->pRight, pTwo->pExpr->pRight,-1) )return; + pA = pOne->pExpr; + pB = pTwo->pExpr; + assert( pA->pLeft!=0 && pA->pRight!=0 ); + assert( pB->pLeft!=0 && pB->pRight!=0 ); + if( sqlite3ExprCompare(0,pA->pLeft, pB->pLeft, -1) ) return; + if( sqlite3ExprCompare(0,pA->pRight, pB->pRight,-1) ) return; + if( ExprHasProperty(pA,EP_Commuted)!=ExprHasProperty(pB,EP_Commuted) ){ + return; + } /* If we reach this point, it means the two subterms can be combined */ if( (eOp & (eOp-1))!=0 ){ if( eOp & (WO_LT|WO_LE) ){ @@ -162003,7 +167681,7 @@ static void whereCombineDisjuncts( } } db = pWC->pWInfo->pParse->db; - pNew = sqlite3ExprDup(db, pOne->pExpr, 0); + pNew = sqlite3ExprDup(db, pA, 0); if( pNew==0 ) return; for(op=TK_EQ; eOp!=(WO_EQ<<(op-TK_EQ)); op++){ assert( opop = op; @@ -162365,30 +168043,38 @@ static void exprAnalyzeOrTerm( ** 1. The SQLITE_Transitive optimization must be enabled ** 2. Must be either an == or an IS operator ** 3. Not originating in the ON clause of an OUTER JOIN -** 4. The affinities of A and B must be compatible -** 5a. Both operands use the same collating sequence OR -** 5b. The overall collating sequence is BINARY +** 4. The operator is not IS or else the query does not contain RIGHT JOIN +** 5. The affinities of A and B must be compatible +** 6. Both operands use the same collating sequence, and they must not +** use explicit COLLATE clauses. ** If this routine returns TRUE, that means that the RHS can be substituted ** for the LHS anyplace else in the WHERE clause where the LHS column occurs. ** This is an optimization. No harm comes from returning 0. But if 1 is ** returned when it should not be, then incorrect answers might result. */ -static int termIsEquivalence(Parse *pParse, Expr *pExpr){ +static int termIsEquivalence(Parse *pParse, Expr *pExpr, SrcList *pSrc){ char aff1, aff2; - CollSeq *pColl; - if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; - if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; - if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; + if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; /* (1) */ + if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; /* (2) */ + if( ExprHasProperty(pExpr, EP_OuterON|EP_Collate) ) return 0; /* (3) */ + assert( pSrc!=0 ); + if( pExpr->op==TK_IS + && pSrc->nSrc>=2 + && (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 + ){ + return 0; /* (4) */ + } aff1 = sqlite3ExprAffinity(pExpr->pLeft); aff2 = sqlite3ExprAffinity(pExpr->pRight); if( aff1!=aff2 && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) ){ - return 0; + return 0; /* (5) */ } - pColl = sqlite3ExprCompareCollSeq(pParse, pExpr); - if( sqlite3IsBinary(pColl) ) return 1; - return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight); + if( !sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight) ){ + return 0; /* (6) */ + } + return 1; } /* @@ -162546,6 +168232,9 @@ static void exprAnalyze( } assert( pWC->nTerm > idxTerm ); pTerm = &pWC->a[idxTerm]; +#ifdef SQLITE_DEBUG + pTerm->iTerm = idxTerm; +#endif pMaskSet = &pWInfo->sMaskSet; pExpr = pTerm->pExpr; assert( pExpr!=0 ); /* Because malloc() has not failed */ @@ -162589,21 +168278,7 @@ static void exprAnalyze( prereqAll |= x; extraRight = x-1; /* ON clause terms may not be used with an index ** on left table of a LEFT JOIN. Ticket #3015 */ - if( (prereqAll>>1)>=x ){ - sqlite3ErrorMsg(pParse, "ON clause references tables to its right"); - return; - } }else if( (prereqAll>>1)>=x ){ - /* The ON clause of an INNER JOIN references a table to its right. - ** Most other SQL database engines raise an error. But SQLite versions - ** 3.0 through 3.38 just put the ON clause constraint into the WHERE - ** clause and carried on. Beginning with 3.39, raise an error only - ** if there is a RIGHT or FULL JOIN in the query. This makes SQLite - ** more like other systems, and also preserves legacy. */ - if( ALWAYS(pSrc->nSrc>0) && (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){ - sqlite3ErrorMsg(pParse, "ON clause references tables to its right"); - return; - } ExprClearProperty(pExpr, EP_InnerON); } } @@ -162653,8 +168328,8 @@ static void exprAnalyze( if( op==TK_IS ) pNew->wtFlags |= TERM_IS; pTerm = &pWC->a[idxTerm]; pTerm->wtFlags |= TERM_COPIED; - - if( termIsEquivalence(pParse, pDup) ){ + assert( pWInfo->pTabList!=0 ); + if( termIsEquivalence(pParse, pDup, pWInfo->pTabList) ){ pTerm->eOperator |= WO_EQUIV; eExtraOp = WO_EQUIV; } @@ -162708,6 +168383,7 @@ static void exprAnalyze( pList = pExpr->x.pList; assert( pList!=0 ); assert( pList->nExpr==2 ); + assert( pWC->a[idxTerm].nChild==0 ); for(i=0; i<2; i++){ Expr *pNewExpr; int idxNew; @@ -162728,7 +168404,7 @@ static void exprAnalyze( /* Analyze a term that is composed of two or more subterms connected by ** an OR operator. */ - else if( pExpr->op==TK_OR ){ + else if( pExpr->op==TK_OR && !ExprHasProperty(pExpr, EP_Collate) ){ assert( pWC->op==TK_AND ); exprAnalyzeOrTerm(pSrc, pWC, idxTerm); pTerm = &pWC->a[idxTerm]; @@ -162820,9 +168496,8 @@ static void exprAnalyze( } if( !db->mallocFailed ){ - u8 c, *pC; /* Last character before the first wildcard */ + u8 *pC; /* Last character before the first wildcard */ pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1]; - c = *pC; if( noCase ){ /* The point is to increment the last character before the first ** wildcard. But if we increment '@', that will push it into the @@ -162830,10 +168505,17 @@ static void exprAnalyze( ** inequality. To avoid this, make sure to also run the full ** LIKE on all candidate expressions by clearing the isComplete flag */ - if( c=='A'-1 ) isComplete = 0; - c = sqlite3UpperToLower[c]; + if( *pC=='A'-1 ) isComplete = 0; + *pC = sqlite3UpperToLower[*pC]; + } + + /* Increment the value of the last utf8 character in the prefix. */ + while( *pC==0xBF && pC>(u8*)pStr2->u.zToken ){ + *pC = 0x80; + pC--; } - *pC = c + 1; + assert( *pC!=0xFF ); /* isLikeOrGlob() guarantees this */ + (*pC)++; } zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY; pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); @@ -162912,8 +168594,11 @@ static void exprAnalyze( && pExpr->x.pSelect->pWin==0 #endif && pWC->op==TK_AND + && pExpr->x.pSelect->pEList->nExpr <= UMXV(pTerm->nChild) + /* ^-- See bug 2026-06-04T10:00:49Z */ ){ int i; + assert( pTerm->nChild==0 ); for(i=0; ipLeft); i++){ int idxNew; idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL|TERM_SLICE); @@ -162954,7 +168639,7 @@ static void exprAnalyze( idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); pNewTerm = &pWC->a[idxNew]; - pNewTerm->prereqRight = prereqExpr; + pNewTerm->prereqRight = prereqExpr | extraRight; pNewTerm->leftCursor = pLeft->iTable; pNewTerm->u.x.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_AUX; @@ -163036,13 +168721,11 @@ static void whereAddLimitExpr( int iVal = 0; if( sqlite3ExprIsInteger(pExpr, &iVal, pParse) && iVal>=0 ){ - Expr *pVal = sqlite3Expr(db, TK_INTEGER, 0); + Expr *pVal = sqlite3ExprInt32(db, iVal); if( pVal==0 ) return; - ExprSetProperty(pVal, EP_IntValue); - pVal->u.iValue = iVal; pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal); }else{ - Expr *pVal = sqlite3Expr(db, TK_REGISTER, 0); + Expr *pVal = sqlite3ExprAlloc(db, TK_REGISTER, 0, 0); if( pVal==0 ) return; pVal->iTable = iReg; pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal); @@ -163065,7 +168748,7 @@ static void whereAddLimitExpr( ** ** 1. The SELECT statement has a LIMIT clause, and ** 2. The SELECT statement is not an aggregate or DISTINCT query, and -** 3. The SELECT statement has exactly one object in its from clause, and +** 3. The SELECT statement has exactly one object in its FROM clause, and ** that object is a virtual table, and ** 4. There are no terms in the WHERE clause that will not be passed ** to the virtual table xBestIndex method. @@ -163102,8 +168785,22 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Selec ** (leftCursor==iCsr) test below. */ continue; } - if( pWC->a[ii].leftCursor!=iCsr ) return; - if( pWC->a[ii].prereqRight!=0 ) return; + if( pWC->a[ii].leftCursor==iCsr && pWC->a[ii].prereqRight==0 ) continue; + + /* If this term has a parent with exactly one child, and the parent will + ** be passed through to xBestIndex, then this term can be ignored. */ + if( pWC->a[ii].iParent>=0 ){ + WhereTerm *pParent = &pWC->a[ pWC->a[ii].iParent ]; + if( pParent->leftCursor==iCsr + && pParent->prereqRight==0 + && pParent->nChild==1 + ){ + continue; + } + } + + /* This term will not be passed through. Do not add a LIMIT clause. */ + return; } /* Check condition (5). Return early if it is not met. */ @@ -163376,11 +169073,16 @@ struct HiddenIndexInfo { int eDistinct; /* Value to return from sqlite3_vtab_distinct() */ u32 mIn; /* Mask of terms that are IN (...) */ u32 mHandleIn; /* Terms that vtab will handle as IN (...) */ - sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST - ** because extra space is allocated to hold up - ** to nTerm such values */ + sqlite3_value *aRhs[FLEXARRAY]; /* RHS values for constraints. MUST BE LAST + ** Extra space is allocated to hold up + ** to nTerm such values */ }; +/* Size (in bytes) of a HiddenIndeInfo object sufficient to hold as +** many as N constraints */ +#define SZ_HIDDENINDEXINFO(N) \ + (offsetof(HiddenIndexInfo,aRhs) + (N)*sizeof(sqlite3_value*)) + /* Forward declaration of methods */ static int whereLoopResize(sqlite3*, WhereLoop*, int); @@ -163762,11 +169464,11 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ pScan->pWC = pWC; pScan->k = k+1; #ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace & 0x20000 ){ + if( (sqlite3WhereTrace & 0x20000)!=0 && pScan->nEquiv>1 ){ int ii; - sqlite3DebugPrintf("SCAN-TERM %p: nEquiv=%d", - pTerm, pScan->nEquiv); - for(ii=0; iinEquiv; ii++){ + sqlite3DebugPrintf("EQUIVALENT TO {%d:%d} (due to TERM-%d):", + pScan->aiCur[0], pScan->aiColumn[0], pTerm->iTerm); + for(ii=1; iinEquiv; ii++){ sqlite3DebugPrintf(" {%d:%d}", pScan->aiCur[ii], pScan->aiColumn[ii]); } @@ -164180,7 +169882,7 @@ static int constraintCompatibleWithOuterJoin( return 0; } if( (pSrc->fg.jointype & (JT_LEFT|JT_RIGHT))!=0 - && ExprHasProperty(pTerm->pExpr, EP_InnerON) + && NEVER(ExprHasProperty(pTerm->pExpr, EP_InnerON)) ){ return 0; } @@ -164201,6 +169903,11 @@ static int constraintCompatibleWithOuterJoin( ** more than 20, then return false. ** ** 3. If no disqualifying conditions above are found, return true. +** +** 2025-01-03: I experimented with a new rule that returns false if the +** the datatype of the column is "BOOLEAN". This did not improve +** performance on any queries at hand, but it did burn CPU cycles, so the +** idea was not committed. */ static SQLITE_NOINLINE int columnIsGoodIndexCandidate( const Table *pTab, @@ -164285,7 +169992,7 @@ static void explainAutomaticIndex( sqlite3_str *pStr = sqlite3_str_new(pParse->db); sqlite3_str_appendf(pStr,"CREATE AUTOMATIC INDEX ON %s(", pTab->zName); assert( pIdx->nColumn>1 ); - assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID ); + assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID || !HasRowid(pTab) ); for(ii=0; ii<(pIdx->nColumn-1); ii++){ const char *zName = 0; int iCol = pIdx->aiColumn[ii]; @@ -164416,6 +170123,19 @@ static SQLITE_NOINLINE void constructAutomaticIndex( }else{ extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); } + if( !HasRowid(pTable) ){ + /* For WITHOUT ROWID tables, ensure that all PRIMARY KEY columns are + ** either in the idxCols mask or in the extraCols mask */ + for(i=0; inCol; i++){ + if( (pTable->aCol[i].colFlags & COLFLAG_PRIMKEY)==0 ) continue; + if( i>=BMS-1 ){ + extraCols |= MASKBIT(BMS-1); + break; + } + if( idxCols & MASKBIT(i) ) continue; + extraCols |= MASKBIT(i); + } + } mxBitCol = MIN(BMS-1,pTable->nCol); testcase( pTable->nCol==BMS-1 ); testcase( pTable->nCol==BMS-2 ); @@ -164427,7 +170147,10 @@ static SQLITE_NOINLINE void constructAutomaticIndex( } /* Construct the Index object to describe this index */ - pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed); + assert( nKeyCol <= pTable->nCol + MAX(0, pTable->nCol - BMS + 1) ); + /* ^-- This guarantees that the number of index columns will fit in the u16 */ + pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+HasRowid(pTable), + 0, &zNotUsed); if( pIdx==0 ) goto end_auto_index_create; pLoop->u.btree.pIndex = pIdx; pIdx->zName = "auto-index"; @@ -164483,8 +170206,10 @@ static SQLITE_NOINLINE void constructAutomaticIndex( } } assert( n==nKeyCol ); - pIdx->aiColumn[n] = XN_ROWID; - pIdx->azColl[n] = sqlite3StrBINARY; + if( HasRowid(pTable) ){ + pIdx->aiColumn[n] = XN_ROWID; + pIdx->azColl[n] = sqlite3StrBINARY; + } /* Create the automatic index */ explainAutomaticIndex(pParse, pIdx, pPartial!=0, &addrExp); @@ -164514,7 +170239,9 @@ static SQLITE_NOINLINE void constructAutomaticIndex( VdbeCoverage(v); VdbeComment((v, "next row of %s", pSrc->pSTab->zName)); }else{ - addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); + assert( pLevel->addrHalt ); + addrTop = sqlite3VdbeAddOp2(v, OP_Rewind,pLevel->iTabCur,pLevel->addrHalt); + VdbeCoverage(v); } if( pPartial ){ iContinue = sqlite3VdbeMakeLabel(pParse); @@ -164542,11 +170269,14 @@ static SQLITE_NOINLINE void constructAutomaticIndex( pSrc->u4.pSubq->regResult, pLevel->iIdxCur); sqlite3VdbeGoto(v, addrTop); pSrc->fg.viaCoroutine = 0; + sqlite3VdbeJumpHere(v, addrTop); }else{ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); + if( (pSrc->fg.jointype & JT_LEFT)!=0 ){ + sqlite3VdbeJumpHere(v, addrTop); + } } - sqlite3VdbeJumpHere(v, addrTop); sqlite3ReleaseTempReg(pParse, regRecord); /* Jump here when skipping the initialization */ @@ -164822,11 +170552,14 @@ static sqlite3_index_info *allocateIndexInfo( break; } if( i==n ){ + int bSortByGroup = (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)!=0; nOrderBy = n; if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) && !pSrc->fg.rowidUsed ){ - eDistinct = 2 + ((pWInfo->wctrlFlags & WHERE_SORTBYGROUP)!=0); + eDistinct = 2 + bSortByGroup; }else if( pWInfo->wctrlFlags & WHERE_GROUPBY ){ - eDistinct = 1; + eDistinct = 1 - bSortByGroup; + }else if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ + eDistinct = 3; } } } @@ -164835,8 +170568,8 @@ static sqlite3_index_info *allocateIndexInfo( */ pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo) + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm - + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) - + sizeof(sqlite3_value*)*nTerm ); + + sizeof(*pIdxOrderBy)*nOrderBy + + SZ_HIDDENINDEXINFO(nTerm) ); if( pIdxInfo==0 ){ sqlite3ErrorMsg(pParse, "out of memory"); return 0; @@ -165673,7 +171406,7 @@ static int whereInScanEst( #endif /* SQLITE_ENABLE_STAT4 */ -#ifdef WHERETRACE_ENABLED +#if defined(WHERETRACE_ENABLED) || defined(SQLITE_DEBUG) /* ** Print the content of a WhereTerm object */ @@ -165698,6 +171431,7 @@ SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){ }else{ sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor); } + iTerm = pTerm->iTerm = MAX(iTerm,pTerm->iTerm); sqlite3DebugPrintf( "TERM-%-3d %p %s %-12s op=%03x wtFlags=%04x", iTerm, pTerm, zType, zLeft, pTerm->eOperator, pTerm->wtFlags); @@ -165717,6 +171451,9 @@ SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){ sqlite3TreeViewExpr(0, pTerm->pExpr, 0); } } +SQLITE_PRIVATE void sqlite3ShowWhereTerm(WhereTerm *pTerm){ + sqlite3WhereTermPrint(pTerm, 0); +} #endif #ifdef WHERETRACE_ENABLED @@ -165748,17 +171485,24 @@ SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){ ** 1.002.001 t2.t2xy 2 f 010241 N 2 cost 0,56,31 */ SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){ + WhereInfo *pWInfo; if( pWC ){ - WhereInfo *pWInfo = pWC->pWInfo; - int nb = 1+(pWInfo->pTabList->nSrc+3)/4; - SrcItem *pItem = pWInfo->pTabList->a + p->iTab; - Table *pTab = pItem->pSTab; - Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; + int nb; + SrcItem *pItem; + Table *pTab; + Bitmask mAll; + + pWInfo = pWC->pWInfo; + nb = 1+(pWInfo->pTabList->nSrc+3)/4; + pItem = pWInfo->pTabList->a + p->iTab; + pTab = pItem->pSTab; + mAll = (((Bitmask)1)<<(nb*4)) - 1; sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); sqlite3DebugPrintf(" %12s", pItem->zAlias ? pItem->zAlias : pTab->zName); }else{ + pWInfo = 0; sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d", p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab); } @@ -165790,7 +171534,12 @@ SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause }else{ sqlite3DebugPrintf(" f %06x N %d", p->wsFlags, p->nLTerm); } - sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); + if( pWInfo && pWInfo->bStarUsed && p->rStarDelta!=0 ){ + sqlite3DebugPrintf(" cost %d,%d,%d delta=%d\n", + p->rSetup, p->rRun, p->nOut, p->rStarDelta); + }else{ + sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); + } if( p->nLTerm && (sqlite3WhereTrace & 0x4000)!=0 ){ int i; for(i=0; inLTerm; i++){ @@ -166226,6 +171975,67 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ return rc; } +/* +** Callback for estLikePatternLength(). +** +** If this node is a string literal that is longer pWalker->sz, then set +** pWalker->sz to the byte length of that string literal. +** +** pWalker->eCode indicates how to count characters: +** +** eCode==0 Count as a GLOB pattern +** eCode==1 Count as a LIKE pattern +*/ +static int exprNodePatternLengthEst(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_STRING ){ + int sz = 0; /* Pattern size in bytes */ + u8 *z = (u8*)pExpr->u.zToken; /* The pattern */ + u8 c; /* Next character of the pattern */ + u8 c1, c2, c3; /* Wildcards */ + if( pWalker->eCode ){ + c1 = '%'; + c2 = '_'; + c3 = 0; + }else{ + c1 = '*'; + c2 = '?'; + c3 = '['; + } + while( (c = *(z++))!=0 ){ + if( c==c3 ){ + if( *z ) z++; + while( *z && *z!=']' ) z++; + }else if( c!=c1 && c!=c2 ){ + sz++; + } + } + if( sz>pWalker->u.sz ) pWalker->u.sz = sz; + } + return WRC_Continue; +} + +/* +** Return the length of the longest string literal in the given +** expression. +** +** eCode indicates how to count characters: +** +** eCode==0 Count as a GLOB pattern +** eCode==1 Count as a LIKE pattern +*/ +static int estLikePatternLength(Expr *p, u16 eCode){ + Walker w; + w.u.sz = 0; + w.eCode = eCode; + w.xExprCallback = exprNodePatternLengthEst; + w.xSelectCallback = sqlite3SelectWalkFail; +#ifdef SQLITE_DEBUG + w.xSelectCallback2 = sqlite3SelectWalkAssert2; +#endif + sqlite3WalkExpr(&w, p); + return w.u.sz; +} + /* ** Adjust the WhereLoop.nOut value downward to account for terms of the ** WHERE clause that reference the loop but which are not used by an @@ -166254,6 +172064,13 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ** "x" column is boolean or else -1 or 0 or 1 is a common default value ** on the "x" column and so in that case only cap the output row estimate ** at 1/2 instead of 1/4. +** +** Heuristic 3: If there is a LIKE or GLOB (or REGEXP or MATCH) operator +** with a large constant pattern, then reduce the size of the search +** space according to the length of the pattern, under the theory that +** longer patterns are less likely to match. This heuristic was added +** to give better output-row count estimates when preparing queries for +** the Join-Order Benchmarks. See forum thread 2026-01-30T09:57:54z */ static void whereLoopOutputAdjust( WhereClause *pWC, /* The WHERE clause */ @@ -166303,13 +172120,14 @@ static void whereLoopOutputAdjust( }else{ /* In the absence of explicit truth probabilities, use heuristics to ** guess a reasonable truth probability. */ + Expr *pOpExpr = pTerm->pExpr; pLoop->nOut--; if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && (pTerm->wtFlags & TERM_HIGHTRUTH)==0 /* tag-20200224-1 */ ){ - Expr *pRight = pTerm->pExpr->pRight; + Expr *pRight = pOpExpr->pRight; int k = 0; - testcase( pTerm->pExpr->op==TK_IS ); + testcase( pOpExpr->op==TK_IS ); if( sqlite3ExprIsInteger(pRight, &k, 0) && k>=(-1) && k<=1 ){ k = 10; }else{ @@ -166319,6 +172137,23 @@ static void whereLoopOutputAdjust( pTerm->wtFlags |= TERM_HEURTRUTH; iReduce = k; } + }else + if( ExprHasProperty(pOpExpr, EP_InfixFunc) + && pOpExpr->op==TK_FUNCTION + ){ + int eOp; + assert( ExprUseXList(pOpExpr) ); + assert( pOpExpr->x.pList->nExpr>=2 ); + eOp = sqlite3ExprIsLikeOperator(pOpExpr); + if( ALWAYS(eOp>0) ){ + int szPattern; + Expr *pRHS = pOpExpr->x.pList->a[0].pExpr; + eOp = eOp==SQLITE_INDEX_CONSTRAINT_LIKE; + szPattern = estLikePatternLength(pRHS, eOp); + if( szPattern>0 ){ + pLoop->nOut -= szPattern*2; + } + } } } } @@ -166390,6 +172225,7 @@ static int whereRangeVectorLen( idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn); if( aff!=idxaff ) break; + if( ExprHasProperty(pTerm->pExpr, EP_Commuted) ) SWAP(Expr*, pRhs, pLhs); pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); if( pColl==0 ) break; if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break; @@ -166462,11 +172298,8 @@ static int whereLoopAddBtreeIndex( assert( pNew->u.btree.nBtm==0 ); opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; } - if( pProbe->bUnordered || pProbe->bLowQual ){ - if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); - if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){ - opMask &= ~(WO_EQ|WO_IN|WO_IS); - } + if( pProbe->bUnordered ){ + opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); } assert( pNew->u.btree.nEqnColumn ); @@ -166539,6 +172372,7 @@ static int whereLoopAddBtreeIndex( if( ExprUseXSelect(pExpr) ){ /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ int i; + int bRedundant = 0; nIn = 46; assert( 46==sqlite3LogEst(25) ); /* The expression may actually be of the form (x, y) IN (SELECT...). @@ -166547,7 +172381,20 @@ static int whereLoopAddBtreeIndex( ** for each such term. The following loop checks that pTerm is the ** first such term in use, and sets nIn back to 0 if it is not. */ for(i=0; inLTerm-1; i++){ - if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0; + if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ){ + nIn = 0; + if( pNew->aLTerm[i]->u.x.iField == pTerm->u.x.iField ){ + /* Detect when two or more columns of an index match the same + ** column of a vector IN operater, and avoid adding the column + ** to the WhereLoop more than once. See tag-20250707-01 + ** in test/rowvalue.test */ + bRedundant = 1; + } + } + } + if( bRedundant ){ + pNew->nLTerm--; + continue; } }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ @@ -166768,6 +172615,7 @@ static int whereLoopAddBtreeIndex( pNew->rRun += nInMul + nIn; pNew->nOut += nInMul + nIn; whereLoopOutputAdjust(pBuilder->pWC, pNew, rSize); + if( pSrc->fg.fromExists ) pNew->nOut = 0; rc = whereLoopInsert(pBuilder, pNew); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ @@ -166779,7 +172627,7 @@ static int whereLoopAddBtreeIndex( if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEqnColumn && (pNew->u.btree.nEqnKeyCol || - pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY) + pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY) ){ if( pNew->u.btree.nEq>3 ){ sqlite3ProgressCheck(pParse); @@ -166818,6 +172666,7 @@ static int whereLoopAddBtreeIndex( && pProbe->hasStat1!=0 && OptimizationEnabled(db, SQLITE_SkipScan) && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ + && pSrc->fg.fromExists==0 && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK ){ LogEst nIter; @@ -166902,13 +172751,13 @@ static int whereUsablePartialIndex( if( !whereUsablePartialIndex(iTab,jointype,pWC,pWhere->pLeft) ) return 0; pWhere = pWhere->pRight; } - if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0; for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){ Expr *pExpr; pExpr = pTerm->pExpr; if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab) && ((jointype & JT_OUTER)==0 || ExprHasProperty(pExpr, EP_OuterON)) && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) + && !sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, -1) && (pTerm->wtFlags & TERM_VNULL)==0 ){ return 1; @@ -167257,7 +173106,6 @@ static int whereLoopAddBtree( && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ - && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ && !pSrc->fg.isCorrelated /* Not a correlated subquery */ && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ && (pSrc->fg.jointype & JT_RIGHT)==0 /* Not the right tab of a RIGHT JOIN */ @@ -167323,6 +173171,7 @@ static int whereLoopAddBtree( pNew->u.btree.nEq = 0; pNew->u.btree.nBtm = 0; pNew->u.btree.nTop = 0; + pNew->u.btree.nDistinctCol = 0; pNew->nSkip = 0; pNew->nLTerm = 0; pNew->iSortIdx = 0; @@ -167362,7 +173211,14 @@ static int whereLoopAddBtree( whereLoopOutputAdjust(pWC, pNew, rSize); if( pSrc->fg.isSubquery ){ if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE; - pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy; + /* Do not set btree.pOrderBy for a recursive CTE. In this case + ** the ORDER BY clause does not determine the overall order that + ** rows are emitted from the CTE in. */ + if( (pSrc->u4.pSubq->pSelect->selFlags & SF_Recursive)==0 ){ + pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy; + } + }else if( pSrc->fg.fromExists ){ + pNew->nOut = 0; } rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; @@ -167405,7 +173261,7 @@ static int whereLoopAddBtree( && (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700)) ){ WHERETRACE(0x200, - ("-> %s a covering index according to bitmasks\n", + ("-> %s is a covering index according to bitmasks\n", pProbe->zName, m==0 ? "is" : "is not")); pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; } @@ -167465,6 +173321,7 @@ static int whereLoopAddBtree( ** positioned to the correct row during the right-join no-match ** loop. */ }else{ + if( pSrc->fg.fromExists ) pNew->nOut = 0; rc = whereLoopInsert(pBuilder, pNew); } pNew->nOut = rSize; @@ -168127,7 +173984,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ sqlite3 *db = pWInfo->pParse->db; int rc = SQLITE_OK; int bFirstPastRJ = 0; - int hasRightJoin = 0; + int hasRightCrossJoin = 0; WhereLoop *pNew; @@ -168154,15 +174011,34 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ ** prevents the right operand of a RIGHT JOIN from being swapped with ** other elements even further to the right. ** - ** The JT_LTORJ case and the hasRightJoin flag work together to - ** prevent FROM-clause terms from moving from the right side of - ** a LEFT JOIN over to the left side of that join if the LEFT JOIN - ** is itself on the left side of a RIGHT JOIN. + ** The hasRightCrossJoin flag prevent FROM-clause terms from moving + ** from the right side of a LEFT JOIN or CROSS JOIN over to the + ** left side of that same join. This is a required restriction in + ** the case of LEFT JOIN - an incorrect answer may results if it is + ** not enforced. This restriction is not required for CROSS JOIN. + ** It is provided merely as a means of controlling join order, under + ** the theory that no real-world queries that care about performance + ** actually use the CROSS JOIN syntax. */ - if( pItem->fg.jointype & JT_LTORJ ) hasRightJoin = 1; + if( pItem->fg.jointype & (JT_LTORJ|JT_CROSS) ){ + testcase( pItem->fg.jointype & JT_LTORJ ); + testcase( pItem->fg.jointype & JT_CROSS ); + hasRightCrossJoin = 1; + } mPrereq |= mPrior; bFirstPastRJ = (pItem->fg.jointype & JT_RIGHT)!=0; - }else if( !hasRightJoin ){ + }else if( pItem->fg.fromExists ){ + /* joins that result from the EXISTS-to-JOIN optimization should not + ** be moved to the left of any of their dependencies */ + WhereClause *pWC = &pWInfo->sWC; + WhereTerm *pTerm; + int i; + for(i=pWC->nBase, pTerm=pWC->a; i>0; i--, pTerm++){ + if( (pNew->maskSelf & pTerm->prereqAll)!=0 ){ + mPrereq |= (pTerm->prereqAll & (pNew->maskSelf-1)); + } + } + }else if( !hasRightCrossJoin ){ mPrereq = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -168385,14 +174261,14 @@ static i8 wherePathSatisfiesOrderBy( pLoop = pLast; } if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ - if( pLoop->u.vtab.isOrdered - && ((wctrlFlags&(WHERE_DISTINCTBY|WHERE_SORTBYGROUP))!=WHERE_DISTINCTBY) - ){ + if( pLoop->u.vtab.isOrdered && pWInfo->pOrderBy==pOrderBy ){ obSat = obDone; + }else{ + /* No further ORDER BY terms may be matched. So this call should + ** return >=0, not -1. Clear isOrderDistinct to ensure it does so. */ + isOrderDistinct = 0; } break; - }else if( wctrlFlags & WHERE_DISTINCTBY ){ - pLoop->u.btree.nDistinctCol = 0; } iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; @@ -168760,68 +174636,226 @@ static LogEst whereSortingCost( ** 18 for star queries ** 12 otherwise ** -** For the purposes of SQLite, a star-query is defined as a query -** with a large central table that is joined against four or more -** smaller tables. The central table is called the "fact" table. -** The smaller tables that get joined are "dimension tables". +** For the purposes of this heuristic, a star-query is defined as a query +** with a central "fact" table that is joined against multiple +** "dimension" tables, subject to the following constraints: +** +** (aa) Only a five-way or larger join is considered for this +** optimization. If there are fewer than four terms in the FROM +** clause, this heuristic does not apply. +** +** (bb) The join between the fact table and the dimension tables must +** be an INNER join. CROSS and OUTER JOINs do not qualify. +** +** (cc) A table must have 3 or more dimension tables in order to be +** considered a fact table. (Was 4 prior to 2026-02-10.) +** +** (dd) A table that is a self-join cannot be a dimension table. +** Dimension tables are joined against fact tables. ** ** SIDE EFFECT: (and really the whole point of this subroutine) ** -** If pWInfo describes a star-query, then the cost on WhereLoops for the -** fact table is reduced. This heuristic helps keep fact tables in -** outer loops. Without this heuristic, paths with fact tables in outer -** loops tend to get pruned by the mxChoice limit on the number of paths, -** resulting in poor query plans. The total amount of heuristic cost -** adjustment is stored in pWInfo->nOutStarDelta and the cost adjustment -** for each WhereLoop is stored in its rStarDelta field. +** If pWInfo describes a star-query, then the cost for SCANs of dimension +** WhereLoops is increased to be slightly larger than the cost of a SCAN +** in the fact table. Only SCAN costs are increased. SEARCH costs are +** unchanged. This heuristic helps keep fact tables in outer loops. Without +** this heuristic, paths with fact tables in outer loops tend to get pruned +** by the mxChoice limit on the number of paths, resulting in poor query +** plans. See the starschema1.test test module for examples of queries +** that need this heuristic to find good query plans. +** +** This heuristic can be completely disabled, so that no query is +** considered a star-query, using SQLITE_TESTCTRL_OPTIMIZATION to +** disable the SQLITE_StarQuery optimization. In the CLI, the command +** to do that is: ".testctrl opt -starquery". +** +** HISTORICAL NOTES: +** +** This optimization was first added on 2024-05-09 by check-in 38db9b5c83d. +** The original optimization reduced the cost and output size estimate for +** fact tables to help them move to outer loops. But months later (as people +** started upgrading) performance regression reports started caming in, +** including: +** +** forum post b18ef983e68d06d1 (2024-12-21) +** forum post 0025389d0860af82 (2025-01-14) +** forum post d87570a145599033 (2025-01-17) +** +** To address these, the criteria for a star-query was tightened to exclude +** cases where the fact and dimensions are separated by an outer join, and +** the affect of star-schema detection was changed to increase the rRun cost +** on just full table scans of dimension tables, rather than reducing costs +** in the all access methods of the fact table. */ -static int computeMxChoice(WhereInfo *pWInfo, LogEst nRowEst){ +static int computeMxChoice(WhereInfo *pWInfo){ int nLoop = pWInfo->nLevel; /* Number of terms in the join */ - if( nRowEst==0 && nLoop>=5 ){ - /* Check to see if we are dealing with a star schema and if so, reduce - ** the cost of fact tables relative to dimension tables, as a heuristic - ** to help keep the fact tables in outer loops. + WhereLoop *pWLoop; /* For looping over WhereLoops */ + +#ifdef SQLITE_DEBUG + /* The star-query detection code below makes use of the following + ** properties of the WhereLoop list, so verify them before + ** continuing: + ** (1) .maskSelf is the bitmask corresponding to .iTab + ** (2) The WhereLoop list is in ascending .iTab order + */ + for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ + assert( pWLoop->maskSelf==MASKBIT(pWLoop->iTab) ); + assert( pWLoop->pNextLoop==0 || pWLoop->iTab<=pWLoop->pNextLoop->iTab ); + } +#endif /* SQLITE_DEBUG */ + + if( nLoop>=4 /* Constraint (aa) */ + && !pWInfo->bStarDone + && OptimizationEnabled(pWInfo->pParse->db, SQLITE_StarQuery) + ){ + SrcItem *aFromTabs; /* All terms of the FROM clause */ + int iFromIdx; /* Term of FROM clause is the candidate fact-table */ + Bitmask m; /* Bitmask for candidate fact-table */ + Bitmask mSelfJoin = 0; /* Tables that cannot be dimension tables */ + WhereLoop *pStart; /* Where to start searching for dimension-tables */ + + pWInfo->bStarDone = 1; /* Only do this computation once */ + + /* Look for fact tables with three or more dimensions where the + ** dimension tables are not separately from the fact tables by an outer + ** or cross join. Adjust cost weights if found. */ - int iLoop; /* Counter over join terms */ - Bitmask m; /* Bitmask for current loop */ - assert( pWInfo->nOutStarDelta==0 ); - for(iLoop=0, m=1; iLoopbStarUsed ); + aFromTabs = pWInfo->pTabList->a; + pStart = pWInfo->pLoops; + for(iFromIdx=0, m=1; iFromIdxpLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ - if( (pWLoop->prereq & m)!=0 && (pWLoop->maskSelf & mSeen)==0 ){ - nDep++; - mSeen |= pWLoop->maskSelf; + SrcItem *pFactTab; /* The candidate fact table */ + + pFactTab = aFromTabs + iFromIdx; + if( (pFactTab->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ + /* If the candidate fact-table is the right table of an outer join + ** restrict the search for dimension-tables to be tables to the right + ** of the fact-table. Constraint (bb) */ + if( iFromIdx+3 > nLoop ){ + break; /* ^-- Impossible to reach nDep>=2 - Constraint (cc) */ + } + while( pStart && pStart->iTab<=iFromIdx ){ + pStart = pStart->pNextLoop; } } - if( nDep<=3 ) continue; - rDelta = 15*(nDep-3); -#ifdef WHERETRACE_ENABLED /* 0x4 */ - if( sqlite3WhereTrace&0x4 ){ - SrcItem *pItem = pWInfo->pTabList->a + iLoop; - sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n", - pItem->zAlias ? pItem->zAlias : pItem->pSTab->zName, - nDep, rDelta); + for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ + if( (aFromTabs[pWLoop->iTab].fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ + break; /* Constraint (bb) */ + } + if( (pWLoop->prereq & m)!=0 /* pWInfo depends on iFromIdx */ + && (pWLoop->maskSelf & mSeen)==0 /* pWInfo not already a dependency */ + && (pWLoop->maskSelf & mSelfJoin)==0 /* Not a self-join */ + ){ + if( aFromTabs[pWLoop->iTab].pSTab==pFactTab->pSTab ){ + mSelfJoin |= m; + }else{ + nDep++; + mSeen |= pWLoop->maskSelf; + } + } } -#endif - if( pWInfo->nOutStarDelta==0 ){ + if( nDep<=2 ){ + continue; /* Constraint (cc) */ + } + + /* If we reach this point, it means that pFactTab is a fact table + ** with four or more dimensions connected by inner joins. Proceed + ** to make cost adjustments. */ + +#ifdef WHERETRACE_ENABLED + /* Make sure rStarDelta values are initialized */ + if( !pWInfo->bStarUsed ){ for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ pWLoop->rStarDelta = 0; } } - pWInfo->nOutStarDelta += rDelta; +#endif +#ifdef WHERETRACE_ENABLED /* 0x80000 */ + if( sqlite3WhereTrace & 0x80000 ){ + Bitmask mShow = mSeen; + sqlite3DebugPrintf("Fact table %s(%d), dimensions:", + pFactTab->zAlias ? pFactTab->zAlias : pFactTab->pSTab->zName, + iFromIdx); + for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ + if( mShow & pWLoop->maskSelf ){ + SrcItem *pDim = aFromTabs + pWLoop->iTab; + mShow &= ~pWLoop->maskSelf; + sqlite3DebugPrintf(" %s(%d)", + pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, pWLoop->iTab); + } + } + sqlite3DebugPrintf("\n"); + } +#endif + pWInfo->bStarUsed = 1; + + /* Compute the maximum cost of any WhereLoop for the + ** fact table plus one epsilon */ + mxRun = LOGEST_MIN; + for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ + if( pWLoop->iTabiTab>iFromIdx ) break; + if( pWLoop->rRun>mxRun ) mxRun = pWLoop->rRun; + } + if( ALWAYS(mxRunpNextLoop){ + if( (pWLoop->maskSelf & mSeen)==0 ) continue; + if( pWLoop->nLTerm ) continue; + if( pWLoop->rRuniTab; + sqlite3DebugPrintf( + "Increase SCAN cost of %s to %d\n", + pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, mxRun + ); + } + pWLoop->rStarDelta = mxRun - pWLoop->rRun; +#endif /* WHERETRACE_ENABLED */ + pWLoop->rRun = mxRun; + } + } + } +#ifdef WHERETRACE_ENABLED /* 0x80000 */ + if( (sqlite3WhereTrace & 0x80000)!=0 && pWInfo->bStarUsed ){ + sqlite3DebugPrintf("WhereLoops changed by star-query heuristic:\n"); for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ - if( pWLoop->maskSelf==m ){ - pWLoop->rRun -= rDelta; - pWLoop->nOut -= rDelta; - pWLoop->rStarDelta = rDelta; + if( pWLoop->rStarDelta ){ + sqlite3WhereLoopPrint(pWLoop, &pWInfo->sWC); } } } +#endif } - return pWInfo->nOutStarDelta>0 ? 18 : 12; + return pWInfo->bStarUsed ? 18 : 12; +} + +/* +** Two WhereLoop objects, pCandidate and pBaseline, are known to have the +** same cost. Look deep into each to see if pCandidate is even slightly +** better than pBaseline. Return false if it is, if pCandidate is is preferred. +** Return true if pBaseline is preferred or if we cannot tell the difference. +** +** Result Meaning +** -------- ---------------------------------------------------------- +** true We cannot tell the difference in pCandidate and pBaseline +** false pCandidate seems like a better choice than pBaseline +*/ +static SQLITE_NOINLINE int whereLoopIsNoBetter( + const WhereLoop *pCandidate, + const WhereLoop *pBaseline +){ + if( (pCandidate->wsFlags & WHERE_INDEXED)==0 ) return 1; + if( (pBaseline->wsFlags & WHERE_INDEXED)==0 ) return 1; + if( pCandidate->u.btree.pIndex->szIdxRow < + pBaseline->u.btree.pIndex->szIdxRow ) return 0; + return 1; } /* @@ -168845,7 +174879,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ int mxI = 0; /* Index of next entry to replace */ int nOrderBy; /* Number of ORDER BY clause terms */ LogEst mxCost = 0; /* Maximum cost of a set of paths */ - LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */ + LogEst mxUnsort = 0; /* Maximum unsorted cost of a set of path */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ WherePath *aTo; /* The nTo best paths at the current level */ @@ -168874,8 +174908,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ mxChoice = 1; }else if( nLoop==2 ){ mxChoice = 5; + }else if( pParse->nErr ){ + mxChoice = 1; }else{ - mxChoice = computeMxChoice(pWInfo, nRowEst); + mxChoice = computeMxChoice(pWInfo); } assert( nLoop<=pWInfo->pTabList->nSrc ); @@ -168942,7 +174978,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ LogEst nOut; /* Rows visited by (pFrom+pWLoop) */ LogEst rCost; /* Cost of path (pFrom+pWLoop) */ - LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */ + LogEst rUnsort; /* Unsorted cost of (pFrom+pWLoop) */ i8 isOrdered; /* isOrdered for (pFrom+pWLoop) */ Bitmask maskNew; /* Mask of src visited by (..) */ Bitmask revMask; /* Mask of rev-order loops for (..) */ @@ -168960,11 +174996,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ /* At this point, pWLoop is a candidate to be the next loop. ** Compute its cost */ - rUnsorted = pWLoop->rRun + pFrom->nRow; + rUnsort = pWLoop->rRun + pFrom->nRow; if( pWLoop->rSetup ){ - rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup, rUnsorted); + rUnsort = sqlite3LogEstAdd(pWLoop->rSetup, rUnsort); } - rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted); + rUnsort = sqlite3LogEstAdd(rUnsort, pFrom->rUnsort); nOut = pFrom->nRow + pWLoop->nOut; maskNew = pFrom->maskLoop | pWLoop->maskSelf; isOrdered = pFrom->isOrdered; @@ -168986,23 +175022,30 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ ** extra encouragement to the query planner to select a plan ** where the rows emerge in the correct order without any sorting ** required. */ - rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 3; + rCost = sqlite3LogEstAdd(rUnsort, aSortCost[isOrdered]) + 3; WHERETRACE(0x002, ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n", aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy, - rUnsorted, rCost)); + rUnsort, rCost)); }else{ - rCost = rUnsorted; - rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */ + rCost = rUnsort; + rUnsort -= 2; /* TUNING: Slight bias in favor of no-sort plans */ } /* Check to see if pWLoop should be added to the set of ** mxChoice best-so-far paths. ** ** First look for an existing path among best-so-far paths - ** that covers the same set of loops and has the same isOrdered - ** setting as the current path candidate. + ** that: + ** (1) covers the same set of loops, and + ** (2) has a compatible isOrdered value. + ** + ** "Compatible isOrdered value" means either + ** (A) both have isOrdered==-1, or + ** (B) both have isOrder>=0, or + ** (C) ordering does not matter because this is the last round + ** of the solver. ** ** The term "((pTo->isOrdered^isOrdered)&0x80)==0" is equivalent ** to (pTo->isOrdered==(-1))==(isOrdered==(-1))" for the range @@ -169011,7 +175054,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ testcase( nTo==0 ); for(jj=0, pTo=aTo; jjmaskLoop==maskNew - && ((pTo->isOrdered^isOrdered)&0x80)==0 + && ( ((pTo->isOrdered^isOrdered)&0x80)==0 || iLoop==nLoop-1 ) ){ testcase( jj==nTo-1 ); break; @@ -169020,7 +175063,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ if( jj>=nTo ){ /* None of the existing best-so-far paths match the candidate. */ if( nTo>=mxChoice - && (rCost>mxCost || (rCost==mxCost && rUnsorted>=mxUnsorted)) + && (rCost>mxCost || (rCost==mxCost && rUnsort>=mxUnsort)) ){ /* The current candidate is no better than any of the mxChoice ** paths currently in the best-so-far buffer. So discard @@ -169028,7 +175071,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort, isOrdered>=0 ? isOrdered+'0' : '?'); } #endif @@ -169047,7 +175090,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf("New %s cost=%-3d,%3d,%3d order=%c\n", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort, isOrdered>=0 ? isOrdered+'0' : '?'); } #endif @@ -169058,24 +175101,23 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ ** pTo or if the candidate should be skipped. ** ** The conditional is an expanded vector comparison equivalent to: - ** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted) + ** (pTo->rCost,pTo->nRow,pTo->rUnsort) <= (rCost,nOut,rUnsort) */ - if( pTo->rCostrCost==rCost - && (pTo->nRownRow==nOut && pTo->rUnsorted<=rUnsorted) - ) - ) + if( (pTo->rCostrCost==rCost && pTo->nRowrCost==rCost && pTo->nRow==nOut && pTo->rUnsortrCost==rCost && pTo->nRow==nOut && pTo->rUnsort==rUnsort + && whereLoopIsNoBetter(pWLoop, pTo->aLoop[iLoop]) ) ){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Skip %s cost=%-3d,%3d,%3d order=%c", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort, isOrdered>=0 ? isOrdered+'0' : '?'); sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + pTo->rUnsort, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif /* Discard the candidate path from further consideration */ @@ -169089,11 +175131,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( "Update %s cost=%-3d,%3d,%3d order=%c", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsort, isOrdered>=0 ? isOrdered+'0' : '?'); sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + pTo->rUnsort, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif } @@ -169102,20 +175144,20 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pTo->revLoop = revMask; pTo->nRow = nOut; pTo->rCost = rCost; - pTo->rUnsorted = rUnsorted; + pTo->rUnsort = rUnsort; pTo->isOrdered = isOrdered; memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop); pTo->aLoop[iLoop] = pWLoop; if( nTo>=mxChoice ){ mxI = 0; mxCost = aTo[0].rCost; - mxUnsorted = aTo[0].nRow; + mxUnsort = aTo[0].nRow; for(jj=1, pTo=&aTo[1]; jjrCost>mxCost - || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted) + || (pTo->rCost==mxCost && pTo->rUnsort>mxUnsort) ){ mxCost = pTo->rCost; - mxUnsorted = pTo->rUnsorted; + mxUnsort = pTo->rUnsort; mxI = jj; } } @@ -169127,8 +175169,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ if( sqlite3WhereTrace & 0x02 ){ LogEst rMin, rFloor = 0; int nDone = 0; + int nProgress; sqlite3DebugPrintf("---- after round %d ----\n", iLoop); - while( nDonerCost>rFloor && pTo->rCostrCost; @@ -169144,10 +175188,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ sqlite3DebugPrintf("\n"); } nDone++; + nProgress++; } } rFloor = rMin; - } + }while( nDone0 ); } #endif @@ -169164,11 +175209,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ return SQLITE_ERROR; } - /* Find the lowest cost path. pFrom will be left pointing to that path */ + /* Only one path is available, which is the best path */ + assert( nFrom==1 ); pFrom = aFrom; - for(ii=1; iirCost>aFrom[ii].rCost ) pFrom = &aFrom[ii]; - } + assert( pWInfo->nLevel==nLoop ); /* Load the lowest cost path into pWInfo */ for(iLoop=0; iLoopnRowOut = pFrom->nRow + pWInfo->nOutStarDelta; + pWInfo->nRowOut = pFrom->nRow; +#ifdef WHERETRACE_ENABLED + pWInfo->rTotalCost = pFrom->rCost; +#endif /* Free temporary memory and return success */ sqlite3StackFreeNN(pParse->db, pSpace); @@ -169298,7 +175345,10 @@ static SQLITE_NOINLINE void whereInterstageHeuristic(WhereInfo *pWInfo){ for(i=0; inLevel; i++){ WhereLoop *p = pWInfo->a[i].pWLoop; if( p==0 ) break; - if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ) continue; + if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ + /* Treat a vtab scan as similar to a full-table scan */ + break; + } if( (p->wsFlags & (WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_IN))!=0 ){ u8 iTab = p->iTab; WhereLoop *pLoop; @@ -169563,7 +175613,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( } if( hasRightJoin && ExprHasProperty(pTerm->pExpr, EP_InnerON) - && pTerm->pExpr->w.iJoin==pItem->iCursor + && NEVER(pTerm->pExpr->w.iJoin==pItem->iCursor) ){ break; /* restriction (5) */ } @@ -169577,6 +175627,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){ pTerm->wtFlags |= TERM_CODED; + pTerm->prereqAll = 0; } } if( i!=pWInfo->nLevel-1 ){ @@ -169639,7 +175690,6 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( } } nSearch += pLoop->nOut; - if( pWInfo->nOutStarDelta ) nSearch += pLoop->rStarDelta; } } @@ -169883,10 +175933,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. */ - nByteWInfo = ROUND8P(sizeof(WhereInfo)); - if( nTabList>1 ){ - nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel)); - } + nByteWInfo = SZ_WHEREINFO(nTabList); pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop)); if( db->mallocFailed ){ sqlite3DbFree(db, pWInfo); @@ -170103,7 +176150,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } /* TUNING: Assume that a DISTINCT clause on a subquery reduces - ** the output size by a factor of 8 (LogEst -30). + ** the output size by a factor of 8 (LogEst -30). Search for + ** tag-20250414a to see other cases. */ if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){ WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n", @@ -170122,7 +176170,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( assert( db->mallocFailed==0 ); #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ - sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); + sqlite3DebugPrintf("---- Solution cost=%d, nRow=%d", + pWInfo->rTotalCost, pWInfo->nRowOut); if( pWInfo->nOBSat>0 ){ sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask); } @@ -170238,6 +176287,14 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( pTab = pTabItem->pSTab; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pLoop = pLevel->pWLoop; + pLevel->addrBrk = sqlite3VdbeMakeLabel(pParse); + if( ii==0 || (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){ + pLevel->addrHalt = pLevel->addrBrk; + }else if( pWInfo->a[ii-1].pRJ ){ + pLevel->addrHalt = pWInfo->a[ii-1].addrBrk; + }else{ + pLevel->addrHalt = pWInfo->a[ii-1].addrHalt; + } if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){ /* Do nothing */ }else @@ -170289,6 +176346,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, pTabItem->iCursor, 0, 0, (const u8*)&pTabItem->colUsed, P4_INT64); #endif + if( ii>=2 + && (pTabItem[0].fg.jointype & (JT_LTORJ|JT_LEFT))==0 + && pLevel->addrHalt==pWInfo->a[0].addrHalt + ){ + sqlite3VdbeAddOp2(v, OP_IfEmpty, pTabItem->iCursor, pWInfo->iBreak); + VdbeCoverage(v); + } }else{ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); } @@ -170483,6 +176547,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( ){ if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return; sqlite3VdbePrintOp(0, pc, pOp); + sqlite3ShowWhereTerm(0); /* So compiler won't complain about unused func */ } #endif @@ -170500,6 +176565,9 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3 *db = pParse->db; int iEnd = sqlite3VdbeCurrentAddr(v); int nRJ = 0; +#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT + int addrSeek = 0; +#endif /* Generate loop termination code. */ @@ -170512,7 +176580,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ ** the RIGHT JOIN table */ WhereRightJoin *pRJ = pLevel->pRJ; sqlite3VdbeResolveLabel(v, pLevel->addrCont); - pLevel->addrCont = 0; + /* Replace addrCont with a new label that will never be used, just so + ** the subsequent call to resolve pLevel->addrCont will have something + ** to resolve. */ + pLevel->addrCont = sqlite3VdbeMakeLabel(pParse); pRJ->endSubrtn = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn, 1); VdbeCoverage(v); @@ -170521,7 +176592,6 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ pLoop = pLevel->pWLoop; if( pLevel->op!=OP_Noop ){ #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT - int addrSeek = 0; Index *pIdx; int n; if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED @@ -170533,6 +176603,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ ){ int r1 = pParse->nMem+1; int j, op; + int addrIfNull = 0; /* Init to avoid false-positive compiler warning */ + if( pLevel->iLeftJoin ){ + addrIfNull = sqlite3VdbeAddOp2(v, OP_IfNullRow, pLevel->iIdxCur, r1); + } for(j=0; jiIdxCur, j, r1+j); } @@ -170542,10 +176616,20 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ VdbeCoverageIf(v, op==OP_SeekLT); VdbeCoverageIf(v, op==OP_SeekGT); sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2); + if( pLevel->iLeftJoin ){ + sqlite3VdbeJumpHere(v, addrIfNull); + } } #endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */ - /* The common case: Advance to the next row */ - if( pLevel->addrCont ) sqlite3VdbeResolveLabel(v, pLevel->addrCont); + } + if( pTabList->a[pLevel->iFrom].fg.fromExists ){ + /* This is an EXISTS-to-JOIN optimization loop. If this loop sees a + ** successful row, it should break out of itself. */ + sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk); + VdbeComment((v, "EXISTS break %d", i)); + } + sqlite3VdbeResolveLabel(v, pLevel->addrCont); + if( pLevel->op!=OP_Noop ){ sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3); sqlite3VdbeChangeP5(v, pLevel->p5); VdbeCoverage(v); @@ -170558,10 +176642,11 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ VdbeCoverage(v); } #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT - if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek); + if( addrSeek ){ + sqlite3VdbeJumpHere(v, addrSeek); + addrSeek = 0; + } #endif - }else if( pLevel->addrCont ){ - sqlite3VdbeResolveLabel(v, pLevel->addrCont); } if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; @@ -170782,14 +176867,28 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ pOp->p2 = x; pOp->p1 = pLevel->iIdxCur; OpcodeRewriteTrace(db, k, pOp); - }else{ - /* Unable to translate the table reference into an index - ** reference. Verify that this is harmless - that the - ** table being referenced really is open. - */ + }else if( pLoop->wsFlags & (WHERE_IDX_ONLY|WHERE_EXPRIDX) ){ if( pLoop->wsFlags & WHERE_IDX_ONLY ){ + /* An error. pLoop is supposed to be a covering index loop, + ** and yet the VM code refers to a column of the table that + ** is not part of the index. */ sqlite3ErrorMsg(pParse, "internal query planner error"); pParse->rc = SQLITE_INTERNAL; + }else{ + /* The WHERE_EXPRIDX flag is set by the planner when it is likely + ** that pLoop is a covering index loop, but it is not possible + ** to be 100% sure. In this case, any OP_Explain opcode + ** corresponding to this loop describes the index as a "COVERING + ** INDEX". But, pOp proves that pLoop is not actually a covering + ** index loop. So clear the WHERE_EXPRIDX flag and rewrite the + ** text that accompanies the OP_Explain opcode, if any. */ + pLoop->wsFlags &= ~WHERE_EXPRIDX; + sqlite3WhereAddExplainText(pParse, + pLevel->addrBody-1, + pTabList, + pLevel, + pWInfo->wctrlFlags + ); } } }else if( pOp->opcode==OP_Rowid ){ @@ -171049,7 +177148,7 @@ static void nth_valueStepFunc( break; case SQLITE_FLOAT: { double fVal = sqlite3_value_double(apArg[1]); - if( ((i64)fVal)!=fVal ) goto error_out; + if( sqlite3RealToI64(fVal)!=fVal ) goto error_out; iVal = (i64)fVal; break; } @@ -171544,7 +177643,7 @@ SQLITE_PRIVATE void sqlite3WindowUpdate( pWin->eEnd = aUp[i].eEnd; pWin->eExclude = 0; if( pWin->eStart==TK_FOLLOWING ){ - pWin->pStart = sqlite3Expr(db, TK_INTEGER, "1"); + pWin->pStart = sqlite3ExprInt32(db, 1); } break; } @@ -171822,7 +177921,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ p->pWhere = 0; p->pGroupBy = 0; p->pHaving = 0; - p->selFlags &= ~SF_Aggregate; + p->selFlags &= ~(u32)SF_Aggregate; p->selFlags |= SF_WinRewrite; /* Create the ORDER BY clause for the sub-select. This is the concatenation @@ -171889,9 +177988,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ ** keep everything legal in this case. */ if( pSublist==0 ){ - pSublist = sqlite3ExprListAppend(pParse, 0, - sqlite3Expr(db, TK_INTEGER, "0") - ); + pSublist = sqlite3ExprListAppend(pParse, 0, sqlite3ExprInt32(db, 0)); } pSub = sqlite3SelectNew( @@ -172497,6 +178594,7 @@ static void windowAggStep( int regArg; int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin); int i; + int addrIf = 0; assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED ); @@ -172513,6 +178611,18 @@ static void windowAggStep( } regArg = reg; + if( pWin->pFilter ){ + int regTmp; + assert( ExprUseXList(pWin->pOwner) ); + assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr ); + assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 ); + regTmp = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); + addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); + VdbeCoverage(v); + sqlite3ReleaseTempReg(pParse, regTmp); + } + if( pMWin->regStartRowid==0 && (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && (pWin->eStart!=TK_UNBOUNDED) @@ -172532,25 +178642,13 @@ static void windowAggStep( } sqlite3VdbeJumpHere(v, addrIsNull); }else if( pWin->regApp ){ + assert( pWin->pFilter==0 ); assert( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ); assert( bInverse==0 || bInverse==1 ); sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1); }else if( pFunc->xSFunc!=noopStepFunc ){ - int addrIf = 0; - if( pWin->pFilter ){ - int regTmp; - assert( ExprUseXList(pWin->pOwner) ); - assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr ); - assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 ); - regTmp = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); - addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); - VdbeCoverage(v); - sqlite3ReleaseTempReg(pParse, regTmp); - } - if( pWin->bExprArgs ){ int iOp = sqlite3VdbeCurrentAddr(v); int iEnd; @@ -172577,12 +178675,13 @@ static void windowAggStep( sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep, bInverse, regArg, pWin->regAccum); sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, (u8)nArg); + sqlite3VdbeChangeP5(v, (u16)nArg); if( pWin->bExprArgs ){ sqlite3ReleaseTempRange(pParse, regArg, nArg); } - if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } + + if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } } @@ -173378,7 +179477,7 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){ ** ** ROWS BETWEEN FOLLOWING AND FOLLOWING ** -** ... loop started by sqlite3WhereBegin() ... +** ... loop started by sqlite3WhereBegin() ... ** if( new partition ){ ** Gosub flush ** } @@ -173896,6 +179995,12 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, 0, 1); }else{ assert( pMWin->eEnd==TK_FOLLOWING ); + /* assert( regStart>=0 ); + ** regEnd = regEnd - regStart; + ** regStart = 0; */ + sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regEnd); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regStart); + addrStart = sqlite3VdbeCurrentAddr(v); addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 1); addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1); @@ -173960,6 +180065,11 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( /* #include "sqliteInt.h" */ +/* +** Verify that the pParse->isCreate field is set +*/ +#define ASSERT_IS_CREATE assert(pParse->isCreate) + /* ** Disable all error recovery processing in the parser push-down ** automaton. @@ -174009,6 +180119,13 @@ struct TrigEvent { int a; IdList * b; }; struct FrameBound { int eType; Expr *pExpr; }; +/* +** Generate a syntax error +*/ +static void parserSyntaxError(Parse *pParse, Token *p){ + sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", p); +} + /* ** Disable lookaside memory allocation for objects that might be ** shared across database connections. @@ -174016,6 +180133,10 @@ struct FrameBound { int eType; Expr *pExpr; }; static void disableLookaside(Parse *pParse){ sqlite3 *db = pParse->db; pParse->disableLookaside++; +#ifdef SQLITE_DEBUG + pParse->isCreate = 1; +#endif + memset(&pParse->u1.cr, 0, sizeof(pParse->u1.cr)); DisableLookaside; } @@ -174091,8 +180212,23 @@ static void updateDeleteLimitError( ** sqlite3_realloc() that includes a call to sqlite3FaultSim() to facilitate ** testing. */ - static void *parserStackRealloc(void *pOld, sqlite3_uint64 newSize){ - return sqlite3FaultSim(700) ? 0 : sqlite3_realloc(pOld, newSize); + static void *parserStackRealloc( + void *pOld, /* Prior allocation */ + sqlite3_uint64 newSize, /* Requested new alloation size */ + Parse *pParse /* Parsing context */ + ){ + void *p = sqlite3FaultSim(700) ? 0 : sqlite3_realloc(pOld, newSize); + if( p==0 ) sqlite3OomFault(pParse->db); + return p; + } + static void parserStackFree(void *pOld, Parse *pParse){ + (void)pParse; + sqlite3_free(pOld); + } + + /* Return an integer that is the maximum allowed stack size */ + static int parserStackSizeLimit(Parse *pParse){ + return pParse->db->aLimit[SQLITE_LIMIT_PARSER_DEPTH]; } @@ -174131,15 +180267,46 @@ static void updateDeleteLimitError( } - /* A routine to convert a binary TK_IS or TK_ISNOT expression into a - ** unary TK_ISNULL or TK_NOTNULL expression. */ - static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ - sqlite3 *db = pParse->db; - if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){ - pA->op = (u8)op; - sqlite3ExprDelete(db, pA->pRight); - pA->pRight = 0; + /* Create a TK_ISNULL or TK_NOTNULL expression, perhaps optimized to + ** to TK_TRUEFALSE, if possible */ + static Expr *sqlite3PExprIsNull( + Parse *pParse, /* Parsing context */ + int op, /* TK_ISNULL or TK_NOTNULL */ + Expr *pLeft /* Operand */ + ){ + Expr *p = pLeft; + assert( op==TK_ISNULL || op==TK_NOTNULL ); + assert( pLeft!=0 ); + while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ + p = p->pLeft; + assert( p!=0 ); + } + switch( p->op ){ + case TK_INTEGER: + case TK_STRING: + case TK_FLOAT: + case TK_BLOB: + sqlite3ExprDeferredDelete(pParse, pLeft); + return sqlite3ExprInt32(pParse->db, op==TK_NOTNULL); + default: + break; + } + return sqlite3PExpr(pParse, op, pLeft, 0); + } + + /* Create a TK_IS or TK_ISNOT operator, perhaps optimized to + ** TK_ISNULL or TK_NOTNULL or TK_TRUEFALSE. */ + static Expr *sqlite3PExprIs( + Parse *pParse, /* Parsing context */ + int op, /* TK_IS or TK_ISNOT */ + Expr *pLeft, /* Left operand */ + Expr *pRight /* Right operand */ + ){ + if( pRight && pRight->op==TK_NULL ){ + sqlite3ExprDeferredDelete(pParse, pRight); + return sqlite3PExprIsNull(pParse, op==TK_IS ? TK_ISNULL : TK_NOTNULL, pLeft); } + return sqlite3PExpr(pParse, op, pLeft, pRight); } /* Add a single new term to an ExprList that is used to store a @@ -174356,7 +180523,8 @@ static void updateDeleteLimitError( #define TK_ERROR 182 #define TK_QNUMBER 183 #define TK_SPACE 184 -#define TK_ILLEGAL 185 +#define TK_COMMENT 185 +#define TK_ILLEGAL 186 #endif /**************** End token definitions ***************************************/ @@ -174448,35 +180616,44 @@ typedef union { Select* yy555; } YYMINORTYPE; #ifndef YYSTACKDEPTH -#define YYSTACKDEPTH 100 +#define YYSTACKDEPTH 50 #endif #define sqlite3ParserARG_SDECL #define sqlite3ParserARG_PDECL #define sqlite3ParserARG_PARAM #define sqlite3ParserARG_FETCH #define sqlite3ParserARG_STORE +#undef YYREALLOC #define YYREALLOC parserStackRealloc -#define YYFREE sqlite3_free +#undef YYFREE +#define YYFREE parserStackFree +#undef YYDYNSTACK #define YYDYNSTACK 1 +#undef YYSIZELIMIT +#define YYSIZELIMIT parserStackSizeLimit +#define sqlite3ParserCTX(P) ((P)->pParse) #define sqlite3ParserCTX_SDECL Parse *pParse; #define sqlite3ParserCTX_PDECL ,Parse *pParse #define sqlite3ParserCTX_PARAM ,pParse #define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse; #define sqlite3ParserCTX_STORE yypParser->pParse=pParse; +#undef YYERRORSYMBOL +#undef YYERRSYMDT +#undef YYFALLBACK #define YYFALLBACK 1 -#define YYNSTATE 583 -#define YYNRULE 409 -#define YYNRULE_WITH_ACTION 344 -#define YYNTOKEN 186 -#define YY_MAX_SHIFT 582 -#define YY_MIN_SHIFTREDUCE 845 -#define YY_MAX_SHIFTREDUCE 1253 -#define YY_ERROR_ACTION 1254 -#define YY_ACCEPT_ACTION 1255 -#define YY_NO_ACTION 1256 -#define YY_MIN_REDUCE 1257 -#define YY_MAX_REDUCE 1665 -#define YY_MIN_DSTRCTR 205 +#define YYNSTATE 600 +#define YYNRULE 412 +#define YYNRULE_WITH_ACTION 348 +#define YYNTOKEN 187 +#define YY_MAX_SHIFT 599 +#define YY_MIN_SHIFTREDUCE 867 +#define YY_MAX_SHIFTREDUCE 1278 +#define YY_ERROR_ACTION 1279 +#define YY_ACCEPT_ACTION 1280 +#define YY_NO_ACTION 1281 +#define YY_MIN_REDUCE 1282 +#define YY_MAX_REDUCE 1693 +#define YY_MIN_DSTRCTR 206 #define YY_MAX_DSTRCTR 319 /************* End control #defines *******************************************/ #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) @@ -174560,643 +180737,680 @@ typedef union { ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (2207) +#define YY_ACTTAB_COUNT (2379) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 130, 127, 234, 282, 282, 1328, 576, 1307, 460, 289, - /* 10 */ 289, 576, 1622, 381, 576, 1328, 573, 576, 562, 413, - /* 20 */ 1300, 1542, 573, 481, 562, 524, 460, 459, 558, 82, - /* 30 */ 82, 983, 294, 375, 51, 51, 498, 61, 61, 984, - /* 40 */ 82, 82, 1577, 137, 138, 91, 7, 1228, 1228, 1063, - /* 50 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 413, - /* 60 */ 288, 288, 182, 288, 288, 481, 536, 288, 288, 130, - /* 70 */ 127, 234, 432, 573, 525, 562, 573, 557, 562, 1290, - /* 80 */ 573, 421, 562, 137, 138, 91, 559, 1228, 1228, 1063, - /* 90 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 296, - /* 100 */ 460, 398, 1249, 134, 134, 134, 134, 133, 133, 132, - /* 110 */ 132, 132, 131, 128, 451, 44, 1050, 1050, 1064, 1067, - /* 120 */ 1255, 1, 1, 582, 2, 1259, 581, 1174, 1259, 1174, - /* 130 */ 321, 413, 155, 321, 1584, 155, 379, 112, 498, 1341, - /* 140 */ 456, 299, 1341, 134, 134, 134, 134, 133, 133, 132, - /* 150 */ 132, 132, 131, 128, 451, 137, 138, 91, 1105, 1228, - /* 160 */ 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, - /* 170 */ 136, 1204, 320, 567, 288, 288, 283, 288, 288, 523, - /* 180 */ 523, 1250, 139, 1541, 7, 214, 503, 573, 1169, 562, - /* 190 */ 573, 1054, 562, 136, 136, 136, 136, 129, 401, 547, - /* 200 */ 487, 1169, 245, 1568, 1169, 245, 133, 133, 132, 132, - /* 210 */ 132, 131, 128, 451, 261, 134, 134, 134, 134, 133, - /* 220 */ 133, 132, 132, 132, 131, 128, 451, 451, 1204, 1205, - /* 230 */ 1204, 130, 127, 234, 455, 413, 182, 455, 130, 127, - /* 240 */ 234, 134, 134, 134, 134, 133, 133, 132, 132, 132, - /* 250 */ 131, 128, 451, 136, 136, 136, 136, 538, 576, 137, - /* 260 */ 138, 91, 261, 1228, 1228, 1063, 1066, 1053, 1053, 135, - /* 270 */ 135, 136, 136, 136, 136, 44, 472, 346, 1204, 472, - /* 280 */ 346, 51, 51, 418, 93, 157, 134, 134, 134, 134, - /* 290 */ 133, 133, 132, 132, 132, 131, 128, 451, 166, 363, - /* 300 */ 298, 134, 134, 134, 134, 133, 133, 132, 132, 132, - /* 310 */ 131, 128, 451, 1293, 461, 1570, 423, 377, 275, 134, - /* 320 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128, - /* 330 */ 451, 418, 320, 567, 1292, 1204, 1205, 1204, 257, 413, - /* 340 */ 483, 511, 508, 507, 94, 132, 132, 132, 131, 128, - /* 350 */ 451, 506, 1204, 548, 548, 388, 576, 384, 7, 413, - /* 360 */ 550, 229, 522, 137, 138, 91, 530, 1228, 1228, 1063, - /* 370 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 51, - /* 380 */ 51, 1582, 380, 137, 138, 91, 331, 1228, 1228, 1063, - /* 390 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 320, - /* 400 */ 567, 288, 288, 320, 567, 1602, 582, 2, 1259, 1204, - /* 410 */ 1205, 1204, 1628, 321, 573, 155, 562, 576, 1511, 264, - /* 420 */ 231, 520, 1341, 134, 134, 134, 134, 133, 133, 132, - /* 430 */ 132, 132, 131, 128, 451, 519, 1511, 1513, 1333, 1333, - /* 440 */ 82, 82, 498, 134, 134, 134, 134, 133, 133, 132, - /* 450 */ 132, 132, 131, 128, 451, 1435, 257, 288, 288, 511, - /* 460 */ 508, 507, 944, 1568, 413, 1019, 1204, 943, 360, 506, - /* 470 */ 573, 1598, 562, 44, 575, 551, 551, 557, 1107, 1582, - /* 480 */ 544, 576, 1107, 40, 417, 245, 531, 1505, 137, 138, - /* 490 */ 91, 219, 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, - /* 500 */ 136, 136, 136, 136, 81, 81, 1281, 1204, 413, 553, - /* 510 */ 1511, 48, 512, 448, 447, 493, 578, 455, 578, 344, - /* 520 */ 45, 1204, 1233, 1204, 1205, 1204, 428, 1235, 158, 882, - /* 530 */ 320, 567, 137, 138, 91, 1234, 1228, 1228, 1063, 1066, - /* 540 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 134, 134, - /* 550 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 451, - /* 560 */ 1236, 576, 1236, 329, 1204, 1205, 1204, 387, 492, 403, - /* 570 */ 1040, 382, 489, 123, 568, 1569, 4, 377, 1204, 1205, - /* 580 */ 1204, 570, 570, 570, 82, 82, 882, 1029, 1331, 1331, - /* 590 */ 571, 1028, 134, 134, 134, 134, 133, 133, 132, 132, - /* 600 */ 132, 131, 128, 451, 288, 288, 1281, 1204, 576, 423, - /* 610 */ 576, 1568, 413, 423, 452, 378, 886, 573, 1279, 562, - /* 620 */ 46, 557, 532, 1028, 1028, 1030, 565, 130, 127, 234, - /* 630 */ 556, 82, 82, 82, 82, 479, 137, 138, 91, 462, - /* 640 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136, - /* 650 */ 136, 136, 1188, 487, 1506, 1040, 413, 6, 1204, 50, - /* 660 */ 879, 121, 121, 948, 1204, 1205, 1204, 358, 557, 122, - /* 670 */ 316, 452, 577, 452, 535, 1204, 1028, 439, 303, 212, - /* 680 */ 137, 138, 91, 213, 1228, 1228, 1063, 1066, 1053, 1053, - /* 690 */ 135, 135, 136, 136, 136, 136, 134, 134, 134, 134, - /* 700 */ 133, 133, 132, 132, 132, 131, 128, 451, 1028, 1028, - /* 710 */ 1030, 1031, 35, 288, 288, 1204, 1205, 1204, 1040, 1339, - /* 720 */ 533, 123, 568, 1569, 4, 377, 573, 1019, 562, 353, - /* 730 */ 1277, 356, 1204, 1205, 1204, 1029, 488, 1188, 571, 1028, - /* 740 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 750 */ 128, 451, 576, 343, 288, 288, 449, 449, 449, 971, - /* 760 */ 413, 1627, 452, 911, 1187, 288, 288, 573, 464, 562, - /* 770 */ 238, 1028, 1028, 1030, 565, 82, 82, 498, 573, 411, - /* 780 */ 562, 344, 467, 332, 137, 138, 91, 197, 1228, 1228, - /* 790 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, - /* 800 */ 1188, 528, 1169, 1040, 413, 1110, 1110, 495, 1041, 121, - /* 810 */ 121, 1204, 317, 540, 862, 1169, 1244, 122, 1169, 452, - /* 820 */ 577, 452, 1340, 198, 1028, 1204, 481, 526, 137, 138, - /* 830 */ 91, 560, 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, - /* 840 */ 136, 136, 136, 136, 134, 134, 134, 134, 133, 133, - /* 850 */ 132, 132, 132, 131, 128, 451, 1028, 1028, 1030, 1031, - /* 860 */ 35, 1204, 288, 288, 1204, 477, 288, 288, 1204, 1205, - /* 870 */ 1204, 539, 481, 437, 470, 573, 1451, 562, 364, 573, - /* 880 */ 1153, 562, 1204, 1205, 1204, 1188, 5, 576, 134, 134, - /* 890 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 451, - /* 900 */ 221, 214, 302, 96, 1149, 1657, 232, 1657, 413, 392, - /* 910 */ 19, 19, 1024, 949, 406, 373, 1595, 1085, 1204, 1205, - /* 920 */ 1204, 1204, 1205, 1204, 1204, 426, 1149, 1658, 413, 1658, - /* 930 */ 1659, 399, 137, 138, 91, 3, 1228, 1228, 1063, 1066, - /* 940 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 304, 1311, - /* 950 */ 514, 1204, 137, 138, 91, 1498, 1228, 1228, 1063, 1066, - /* 960 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 434, 131, - /* 970 */ 128, 451, 375, 1204, 274, 291, 372, 517, 367, 516, - /* 980 */ 262, 1204, 1205, 1204, 1147, 227, 363, 448, 447, 1435, - /* 990 */ 1568, 1310, 134, 134, 134, 134, 133, 133, 132, 132, - /* 1000 */ 132, 131, 128, 451, 1568, 576, 1147, 487, 1204, 1205, - /* 1010 */ 1204, 442, 134, 134, 134, 134, 133, 133, 132, 132, - /* 1020 */ 132, 131, 128, 451, 386, 576, 485, 576, 19, 19, - /* 1030 */ 1204, 1205, 1204, 1345, 1236, 970, 1236, 574, 47, 936, - /* 1040 */ 936, 473, 413, 431, 1552, 573, 1125, 562, 19, 19, - /* 1050 */ 19, 19, 49, 336, 850, 851, 852, 111, 1368, 315, - /* 1060 */ 429, 576, 413, 433, 341, 306, 137, 138, 91, 115, - /* 1070 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136, - /* 1080 */ 136, 136, 576, 1309, 82, 82, 137, 138, 91, 529, - /* 1090 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136, - /* 1100 */ 136, 136, 1569, 222, 377, 19, 19, 305, 1126, 1169, - /* 1110 */ 398, 1148, 22, 22, 498, 333, 1569, 335, 377, 576, - /* 1120 */ 438, 445, 1169, 1127, 486, 1169, 134, 134, 134, 134, - /* 1130 */ 133, 133, 132, 132, 132, 131, 128, 451, 1128, 576, - /* 1140 */ 902, 576, 145, 145, 6, 576, 134, 134, 134, 134, - /* 1150 */ 133, 133, 132, 132, 132, 131, 128, 451, 214, 1336, - /* 1160 */ 922, 576, 19, 19, 19, 19, 1282, 419, 19, 19, - /* 1170 */ 923, 412, 515, 141, 576, 1169, 413, 206, 465, 207, - /* 1180 */ 903, 215, 1575, 552, 147, 147, 7, 227, 1169, 411, - /* 1190 */ 1250, 1169, 120, 307, 117, 307, 413, 66, 66, 334, - /* 1200 */ 137, 138, 91, 119, 1228, 1228, 1063, 1066, 1053, 1053, - /* 1210 */ 135, 135, 136, 136, 136, 136, 413, 285, 209, 969, - /* 1220 */ 137, 138, 91, 471, 1228, 1228, 1063, 1066, 1053, 1053, - /* 1230 */ 135, 135, 136, 136, 136, 136, 435, 10, 1450, 267, - /* 1240 */ 137, 126, 91, 1435, 1228, 1228, 1063, 1066, 1053, 1053, - /* 1250 */ 135, 135, 136, 136, 136, 136, 1435, 1435, 410, 409, - /* 1260 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 1270 */ 128, 451, 576, 969, 576, 1224, 498, 373, 1595, 1554, - /* 1280 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 1290 */ 128, 451, 532, 457, 576, 82, 82, 82, 82, 111, - /* 1300 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 1310 */ 128, 451, 109, 233, 430, 1576, 546, 67, 67, 7, - /* 1320 */ 413, 351, 550, 1550, 260, 259, 258, 494, 443, 569, - /* 1330 */ 419, 983, 446, 1224, 450, 545, 1207, 576, 969, 984, - /* 1340 */ 413, 475, 1449, 1574, 1180, 138, 91, 7, 1228, 1228, - /* 1350 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, - /* 1360 */ 21, 21, 267, 576, 300, 1126, 91, 233, 1228, 1228, - /* 1370 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, - /* 1380 */ 1127, 373, 1595, 161, 1573, 16, 53, 53, 7, 108, - /* 1390 */ 533, 38, 969, 125, 1207, 1128, 1180, 576, 1224, 123, - /* 1400 */ 568, 893, 4, 324, 134, 134, 134, 134, 133, 133, - /* 1410 */ 132, 132, 132, 131, 128, 451, 571, 564, 534, 576, - /* 1420 */ 68, 68, 576, 39, 134, 134, 134, 134, 133, 133, - /* 1430 */ 132, 132, 132, 131, 128, 451, 576, 160, 1571, 1223, - /* 1440 */ 452, 576, 54, 54, 576, 69, 69, 576, 1366, 576, - /* 1450 */ 420, 184, 565, 463, 297, 576, 1224, 463, 297, 70, - /* 1460 */ 70, 576, 44, 474, 71, 71, 576, 72, 72, 576, - /* 1470 */ 73, 73, 55, 55, 411, 874, 242, 576, 56, 56, - /* 1480 */ 576, 1040, 576, 478, 57, 57, 576, 121, 121, 59, - /* 1490 */ 59, 23, 60, 60, 411, 122, 319, 452, 577, 452, - /* 1500 */ 74, 74, 1028, 75, 75, 76, 76, 411, 290, 20, - /* 1510 */ 20, 108, 287, 231, 553, 123, 568, 325, 4, 320, - /* 1520 */ 567, 97, 218, 944, 1144, 328, 400, 576, 943, 576, - /* 1530 */ 1380, 424, 571, 874, 1028, 1028, 1030, 1031, 35, 293, - /* 1540 */ 534, 576, 1104, 576, 1104, 9, 576, 342, 576, 111, - /* 1550 */ 77, 77, 143, 143, 576, 205, 452, 222, 1379, 889, - /* 1560 */ 576, 901, 900, 1188, 144, 144, 78, 78, 565, 62, - /* 1570 */ 62, 79, 79, 323, 1021, 576, 266, 63, 63, 908, - /* 1580 */ 909, 1589, 542, 80, 80, 576, 371, 541, 123, 568, - /* 1590 */ 480, 4, 266, 482, 244, 266, 370, 1040, 64, 64, - /* 1600 */ 576, 466, 576, 121, 121, 571, 1557, 576, 170, 170, - /* 1610 */ 576, 122, 576, 452, 577, 452, 576, 889, 1028, 576, - /* 1620 */ 165, 576, 111, 171, 171, 87, 87, 337, 1616, 452, - /* 1630 */ 65, 65, 1530, 83, 83, 146, 146, 986, 987, 84, - /* 1640 */ 84, 565, 168, 168, 148, 148, 1092, 347, 1032, 111, - /* 1650 */ 1028, 1028, 1030, 1031, 35, 542, 1103, 576, 1103, 576, - /* 1660 */ 543, 123, 568, 504, 4, 263, 576, 361, 1529, 111, - /* 1670 */ 1040, 1088, 576, 263, 576, 490, 121, 121, 571, 1188, - /* 1680 */ 142, 142, 169, 169, 122, 576, 452, 577, 452, 162, - /* 1690 */ 162, 1028, 576, 563, 576, 152, 152, 151, 151, 348, - /* 1700 */ 1376, 974, 452, 266, 1092, 942, 1032, 125, 149, 149, - /* 1710 */ 939, 576, 125, 576, 565, 150, 150, 86, 86, 872, - /* 1720 */ 352, 159, 576, 1028, 1028, 1030, 1031, 35, 542, 941, - /* 1730 */ 576, 125, 355, 541, 88, 88, 85, 85, 357, 359, - /* 1740 */ 1324, 1308, 366, 1040, 376, 52, 52, 499, 1389, 121, - /* 1750 */ 121, 1434, 1188, 58, 58, 1362, 1374, 122, 1439, 452, - /* 1760 */ 577, 452, 1289, 167, 1028, 1280, 280, 1268, 1267, 1269, - /* 1770 */ 1609, 1359, 312, 313, 12, 314, 397, 1421, 224, 1416, - /* 1780 */ 295, 237, 1409, 339, 340, 1426, 301, 345, 484, 228, - /* 1790 */ 1371, 1307, 1372, 1370, 1425, 404, 1028, 1028, 1030, 1031, - /* 1800 */ 35, 1601, 1192, 454, 509, 369, 292, 1502, 210, 1501, - /* 1810 */ 1369, 396, 396, 395, 277, 393, 211, 566, 859, 1612, - /* 1820 */ 1244, 123, 568, 391, 4, 1188, 223, 270, 1549, 1547, - /* 1830 */ 1241, 239, 186, 327, 422, 96, 195, 220, 571, 235, - /* 1840 */ 180, 326, 188, 468, 190, 1507, 191, 192, 92, 193, - /* 1850 */ 469, 95, 1422, 13, 502, 247, 1430, 109, 199, 402, - /* 1860 */ 476, 405, 452, 1496, 1428, 1427, 14, 491, 251, 102, - /* 1870 */ 497, 1518, 241, 281, 565, 253, 203, 354, 500, 254, - /* 1880 */ 175, 1270, 407, 43, 350, 518, 1327, 436, 255, 1326, - /* 1890 */ 1325, 1318, 104, 893, 1626, 229, 408, 440, 1625, 441, - /* 1900 */ 240, 310, 1296, 1040, 311, 1317, 527, 1594, 1297, 121, - /* 1910 */ 121, 368, 1295, 1624, 268, 269, 1580, 122, 1579, 452, - /* 1920 */ 577, 452, 374, 444, 1028, 1394, 1393, 140, 553, 90, - /* 1930 */ 568, 11, 4, 1483, 383, 414, 385, 110, 116, 216, - /* 1940 */ 320, 567, 1350, 555, 42, 318, 571, 537, 1349, 389, - /* 1950 */ 390, 579, 1198, 276, 279, 278, 1028, 1028, 1030, 1031, - /* 1960 */ 35, 580, 415, 1265, 458, 1260, 416, 185, 1534, 172, - /* 1970 */ 452, 1535, 173, 156, 308, 846, 1533, 1532, 453, 217, - /* 1980 */ 225, 89, 565, 174, 322, 1188, 226, 236, 1102, 154, - /* 1990 */ 1100, 330, 176, 187, 1223, 189, 925, 338, 243, 1116, - /* 2000 */ 246, 194, 177, 178, 425, 427, 98, 99, 196, 100, - /* 2010 */ 101, 1040, 179, 1119, 248, 1115, 249, 121, 121, 24, - /* 2020 */ 163, 250, 349, 1108, 266, 122, 1238, 452, 577, 452, - /* 2030 */ 1192, 454, 1028, 200, 292, 496, 252, 201, 861, 396, - /* 2040 */ 396, 395, 277, 393, 15, 501, 859, 370, 292, 256, - /* 2050 */ 202, 554, 505, 396, 396, 395, 277, 393, 103, 239, - /* 2060 */ 859, 327, 25, 26, 1028, 1028, 1030, 1031, 35, 326, - /* 2070 */ 362, 510, 891, 239, 365, 327, 513, 904, 105, 309, - /* 2080 */ 164, 181, 27, 326, 106, 521, 107, 1185, 1069, 1155, - /* 2090 */ 17, 1154, 284, 1188, 286, 978, 265, 204, 125, 1171, - /* 2100 */ 241, 230, 972, 1175, 28, 1160, 29, 1179, 175, 1173, - /* 2110 */ 30, 43, 31, 1178, 241, 32, 41, 549, 8, 33, - /* 2120 */ 208, 111, 175, 1083, 1070, 43, 113, 1068, 240, 114, - /* 2130 */ 1072, 34, 1073, 561, 1124, 118, 271, 36, 18, 1194, - /* 2140 */ 1033, 873, 240, 935, 124, 37, 272, 273, 1617, 572, - /* 2150 */ 183, 153, 394, 1193, 1256, 1256, 1256, 1256, 1256, 1256, - /* 2160 */ 1256, 1256, 1256, 414, 1256, 1256, 1256, 1256, 320, 567, - /* 2170 */ 1256, 1256, 1256, 1256, 1256, 1256, 1256, 414, 1256, 1256, - /* 2180 */ 1256, 1256, 320, 567, 1256, 1256, 1256, 1256, 1256, 1256, - /* 2190 */ 1256, 1256, 458, 1256, 1256, 1256, 1256, 1256, 1256, 1256, - /* 2200 */ 1256, 1256, 1256, 1256, 1256, 1256, 458, + /* 0 */ 134, 131, 238, 290, 290, 1353, 593, 1332, 478, 1606, + /* 10 */ 593, 1315, 593, 7, 593, 1353, 590, 593, 579, 424, + /* 20 */ 1566, 134, 131, 238, 1318, 541, 478, 477, 575, 84, + /* 30 */ 84, 1005, 303, 84, 84, 51, 51, 63, 63, 1006, + /* 40 */ 84, 84, 498, 141, 142, 93, 442, 1254, 1254, 1085, + /* 50 */ 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, 424, + /* 60 */ 296, 296, 498, 296, 296, 567, 553, 296, 296, 1306, + /* 70 */ 574, 1358, 1358, 590, 542, 579, 590, 574, 579, 548, + /* 80 */ 590, 1304, 579, 141, 142, 93, 576, 1254, 1254, 1085, + /* 90 */ 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, 399, + /* 100 */ 478, 395, 6, 138, 138, 138, 138, 137, 137, 136, + /* 110 */ 136, 136, 135, 132, 463, 44, 342, 593, 305, 1127, + /* 120 */ 1280, 1, 1, 599, 2, 1284, 598, 1200, 1284, 1200, + /* 130 */ 330, 424, 158, 330, 1613, 158, 390, 116, 308, 1366, + /* 140 */ 51, 51, 1366, 138, 138, 138, 138, 137, 137, 136, + /* 150 */ 136, 136, 135, 132, 463, 141, 142, 93, 515, 1254, + /* 160 */ 1254, 1085, 1088, 1075, 1075, 139, 139, 140, 140, 140, + /* 170 */ 140, 1230, 329, 584, 296, 296, 212, 296, 296, 568, + /* 180 */ 568, 488, 143, 1072, 1072, 1086, 1089, 590, 1195, 579, + /* 190 */ 590, 340, 579, 140, 140, 140, 140, 133, 392, 564, + /* 200 */ 536, 1195, 250, 425, 1195, 250, 137, 137, 136, 136, + /* 210 */ 136, 135, 132, 463, 291, 138, 138, 138, 138, 137, + /* 220 */ 137, 136, 136, 136, 135, 132, 463, 966, 1230, 1231, + /* 230 */ 1230, 412, 965, 467, 412, 424, 467, 489, 357, 1611, + /* 240 */ 391, 138, 138, 138, 138, 137, 137, 136, 136, 136, + /* 250 */ 135, 132, 463, 463, 134, 131, 238, 555, 1076, 141, + /* 260 */ 142, 93, 593, 1254, 1254, 1085, 1088, 1075, 1075, 139, + /* 270 */ 139, 140, 140, 140, 140, 1317, 134, 131, 238, 424, + /* 280 */ 549, 1597, 1531, 333, 97, 83, 83, 140, 140, 140, + /* 290 */ 140, 138, 138, 138, 138, 137, 137, 136, 136, 136, + /* 300 */ 135, 132, 463, 141, 142, 93, 1657, 1254, 1254, 1085, + /* 310 */ 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, 138, + /* 320 */ 138, 138, 138, 137, 137, 136, 136, 136, 135, 132, + /* 330 */ 463, 591, 1230, 958, 958, 138, 138, 138, 138, 137, + /* 340 */ 137, 136, 136, 136, 135, 132, 463, 44, 398, 547, + /* 350 */ 1306, 136, 136, 136, 135, 132, 463, 386, 593, 442, + /* 360 */ 595, 145, 595, 138, 138, 138, 138, 137, 137, 136, + /* 370 */ 136, 136, 135, 132, 463, 500, 1230, 112, 550, 460, + /* 380 */ 459, 51, 51, 424, 296, 296, 479, 334, 1259, 1230, + /* 390 */ 1231, 1230, 1599, 1261, 388, 312, 444, 590, 246, 579, + /* 400 */ 546, 1260, 271, 235, 329, 584, 551, 141, 142, 93, + /* 410 */ 429, 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, 140, + /* 420 */ 140, 140, 140, 22, 22, 1230, 1262, 424, 1262, 216, + /* 430 */ 296, 296, 98, 1230, 1231, 1230, 264, 884, 45, 528, + /* 440 */ 525, 524, 1041, 590, 1269, 579, 421, 420, 393, 523, + /* 450 */ 44, 141, 142, 93, 498, 1254, 1254, 1085, 1088, 1075, + /* 460 */ 1075, 139, 139, 140, 140, 140, 140, 138, 138, 138, + /* 470 */ 138, 137, 137, 136, 136, 136, 135, 132, 463, 593, + /* 480 */ 1611, 561, 1230, 1231, 1230, 23, 264, 515, 200, 528, + /* 490 */ 525, 524, 127, 585, 509, 4, 355, 487, 506, 523, + /* 500 */ 593, 498, 84, 84, 134, 131, 238, 329, 584, 588, + /* 510 */ 1627, 138, 138, 138, 138, 137, 137, 136, 136, 136, + /* 520 */ 135, 132, 463, 19, 19, 435, 1230, 1460, 297, 297, + /* 530 */ 311, 424, 1565, 464, 1631, 599, 2, 1284, 437, 574, + /* 540 */ 1107, 590, 330, 579, 158, 582, 489, 357, 573, 593, + /* 550 */ 592, 1366, 409, 1274, 1230, 141, 142, 93, 1364, 1254, + /* 560 */ 1254, 1085, 1088, 1075, 1075, 139, 139, 140, 140, 140, + /* 570 */ 140, 389, 84, 84, 1062, 567, 1230, 313, 1523, 593, + /* 580 */ 125, 125, 970, 1230, 1231, 1230, 296, 296, 126, 46, + /* 590 */ 464, 594, 464, 296, 296, 1050, 1230, 218, 439, 590, + /* 600 */ 1604, 579, 84, 84, 7, 403, 590, 515, 579, 325, + /* 610 */ 417, 1230, 1231, 1230, 250, 138, 138, 138, 138, 137, + /* 620 */ 137, 136, 136, 136, 135, 132, 463, 1050, 1050, 1052, + /* 630 */ 1053, 35, 1275, 1230, 1231, 1230, 424, 1370, 993, 574, + /* 640 */ 371, 414, 274, 412, 1597, 467, 1302, 552, 451, 590, + /* 650 */ 543, 579, 1530, 1230, 1231, 1230, 1214, 201, 409, 1174, + /* 660 */ 141, 142, 93, 223, 1254, 1254, 1085, 1088, 1075, 1075, + /* 670 */ 139, 139, 140, 140, 140, 140, 296, 296, 1250, 593, + /* 680 */ 424, 296, 296, 236, 529, 296, 296, 515, 100, 590, + /* 690 */ 1600, 579, 48, 1605, 590, 1230, 579, 7, 590, 577, + /* 700 */ 579, 904, 84, 84, 141, 142, 93, 496, 1254, 1254, + /* 710 */ 1085, 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, + /* 720 */ 138, 138, 138, 138, 137, 137, 136, 136, 136, 135, + /* 730 */ 132, 463, 1365, 1230, 296, 296, 1250, 115, 1275, 326, + /* 740 */ 233, 539, 1062, 40, 282, 127, 585, 590, 4, 579, + /* 750 */ 329, 584, 1230, 1231, 1230, 1598, 593, 388, 904, 1051, + /* 760 */ 1356, 1356, 588, 1050, 138, 138, 138, 138, 137, 137, + /* 770 */ 136, 136, 136, 135, 132, 463, 185, 593, 1230, 19, + /* 780 */ 19, 1230, 971, 1597, 424, 1651, 464, 129, 908, 1195, + /* 790 */ 1230, 1231, 1230, 1325, 443, 1050, 1050, 1052, 582, 1603, + /* 800 */ 149, 149, 1195, 7, 5, 1195, 1687, 410, 141, 142, + /* 810 */ 93, 1536, 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, + /* 820 */ 140, 140, 140, 140, 1214, 397, 593, 1062, 424, 1536, + /* 830 */ 1538, 50, 901, 125, 125, 1230, 1231, 1230, 1230, 1231, + /* 840 */ 1230, 126, 1230, 464, 594, 464, 515, 1230, 1050, 84, + /* 850 */ 84, 3, 141, 142, 93, 924, 1254, 1254, 1085, 1088, + /* 860 */ 1075, 1075, 139, 139, 140, 140, 140, 140, 138, 138, + /* 870 */ 138, 138, 137, 137, 136, 136, 136, 135, 132, 463, + /* 880 */ 1050, 1050, 1052, 1053, 35, 442, 457, 532, 433, 1230, + /* 890 */ 1062, 1361, 540, 540, 1598, 925, 388, 7, 1129, 1230, + /* 900 */ 1231, 1230, 1129, 1536, 1230, 1231, 1230, 1051, 570, 1214, + /* 910 */ 593, 1050, 138, 138, 138, 138, 137, 137, 136, 136, + /* 920 */ 136, 135, 132, 463, 6, 185, 1195, 1230, 231, 593, + /* 930 */ 382, 992, 424, 151, 151, 510, 1213, 557, 482, 1195, + /* 940 */ 381, 160, 1195, 1050, 1050, 1052, 1230, 1231, 1230, 422, + /* 950 */ 593, 447, 84, 84, 593, 217, 141, 142, 93, 593, + /* 960 */ 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, 140, 140, + /* 970 */ 140, 140, 1214, 19, 19, 593, 424, 19, 19, 442, + /* 980 */ 1063, 442, 19, 19, 1230, 1231, 1230, 515, 445, 458, + /* 990 */ 1597, 386, 315, 1175, 1685, 556, 1685, 450, 84, 84, + /* 1000 */ 141, 142, 93, 505, 1254, 1254, 1085, 1088, 1075, 1075, + /* 1010 */ 139, 139, 140, 140, 140, 140, 138, 138, 138, 138, + /* 1020 */ 137, 137, 136, 136, 136, 135, 132, 463, 442, 1147, + /* 1030 */ 454, 1597, 362, 1041, 593, 462, 1460, 1233, 47, 1393, + /* 1040 */ 324, 565, 565, 115, 1148, 449, 7, 460, 459, 307, + /* 1050 */ 375, 354, 593, 113, 593, 329, 584, 19, 19, 1149, + /* 1060 */ 138, 138, 138, 138, 137, 137, 136, 136, 136, 135, + /* 1070 */ 132, 463, 209, 1173, 563, 19, 19, 19, 19, 49, + /* 1080 */ 424, 944, 1175, 1686, 1046, 1686, 218, 355, 484, 343, + /* 1090 */ 210, 945, 569, 562, 1262, 1233, 1262, 490, 314, 423, + /* 1100 */ 424, 1598, 1206, 388, 141, 142, 93, 440, 1254, 1254, + /* 1110 */ 1085, 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, + /* 1120 */ 352, 316, 531, 316, 141, 142, 93, 549, 1254, 1254, + /* 1130 */ 1085, 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, + /* 1140 */ 446, 10, 1598, 274, 388, 915, 281, 299, 383, 534, + /* 1150 */ 378, 533, 269, 593, 1206, 587, 587, 587, 374, 293, + /* 1160 */ 1579, 991, 1173, 302, 138, 138, 138, 138, 137, 137, + /* 1170 */ 136, 136, 136, 135, 132, 463, 53, 53, 520, 1250, + /* 1180 */ 593, 1147, 1576, 431, 138, 138, 138, 138, 137, 137, + /* 1190 */ 136, 136, 136, 135, 132, 463, 1148, 301, 593, 1577, + /* 1200 */ 593, 1307, 431, 54, 54, 593, 268, 593, 461, 461, + /* 1210 */ 461, 1149, 347, 492, 424, 135, 132, 463, 1146, 1195, + /* 1220 */ 474, 68, 68, 69, 69, 550, 332, 287, 21, 21, + /* 1230 */ 55, 55, 1195, 581, 424, 1195, 309, 1250, 141, 142, + /* 1240 */ 93, 119, 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, + /* 1250 */ 140, 140, 140, 140, 593, 237, 480, 1476, 141, 142, + /* 1260 */ 93, 593, 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, + /* 1270 */ 140, 140, 140, 140, 344, 430, 346, 70, 70, 494, + /* 1280 */ 991, 1132, 1132, 512, 56, 56, 1269, 593, 268, 593, + /* 1290 */ 369, 374, 593, 481, 215, 384, 1624, 481, 138, 138, + /* 1300 */ 138, 138, 137, 137, 136, 136, 136, 135, 132, 463, + /* 1310 */ 71, 71, 72, 72, 225, 73, 73, 593, 138, 138, + /* 1320 */ 138, 138, 137, 137, 136, 136, 136, 135, 132, 463, + /* 1330 */ 586, 431, 593, 872, 873, 874, 593, 911, 593, 1602, + /* 1340 */ 74, 74, 593, 7, 1460, 242, 593, 306, 424, 1578, + /* 1350 */ 472, 306, 364, 219, 367, 75, 75, 430, 345, 57, + /* 1360 */ 57, 58, 58, 432, 187, 59, 59, 593, 424, 61, + /* 1370 */ 61, 1475, 141, 142, 93, 123, 1254, 1254, 1085, 1088, + /* 1380 */ 1075, 1075, 139, 139, 140, 140, 140, 140, 424, 570, + /* 1390 */ 62, 62, 141, 142, 93, 911, 1254, 1254, 1085, 1088, + /* 1400 */ 1075, 1075, 139, 139, 140, 140, 140, 140, 161, 384, + /* 1410 */ 1624, 1474, 141, 130, 93, 441, 1254, 1254, 1085, 1088, + /* 1420 */ 1075, 1075, 139, 139, 140, 140, 140, 140, 267, 266, + /* 1430 */ 265, 1460, 138, 138, 138, 138, 137, 137, 136, 136, + /* 1440 */ 136, 135, 132, 463, 593, 1336, 593, 1269, 1460, 384, + /* 1450 */ 1624, 231, 138, 138, 138, 138, 137, 137, 136, 136, + /* 1460 */ 136, 135, 132, 463, 593, 163, 593, 76, 76, 77, + /* 1470 */ 77, 593, 138, 138, 138, 138, 137, 137, 136, 136, + /* 1480 */ 136, 135, 132, 463, 475, 593, 483, 78, 78, 20, + /* 1490 */ 20, 1249, 424, 491, 79, 79, 495, 422, 295, 235, + /* 1500 */ 1574, 38, 511, 896, 422, 335, 240, 422, 147, 147, + /* 1510 */ 112, 593, 424, 593, 101, 222, 991, 142, 93, 455, + /* 1520 */ 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, 140, 140, + /* 1530 */ 140, 140, 593, 39, 148, 148, 80, 80, 93, 551, + /* 1540 */ 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, 140, 140, + /* 1550 */ 140, 140, 328, 923, 922, 64, 64, 502, 1656, 1005, + /* 1560 */ 933, 896, 124, 422, 121, 254, 593, 1006, 593, 226, + /* 1570 */ 593, 127, 585, 164, 4, 16, 138, 138, 138, 138, + /* 1580 */ 137, 137, 136, 136, 136, 135, 132, 463, 588, 81, + /* 1590 */ 81, 65, 65, 82, 82, 593, 138, 138, 138, 138, + /* 1600 */ 137, 137, 136, 136, 136, 135, 132, 463, 593, 226, + /* 1610 */ 237, 966, 464, 593, 298, 593, 965, 593, 66, 66, + /* 1620 */ 593, 1170, 593, 411, 582, 353, 469, 115, 593, 471, + /* 1630 */ 169, 173, 173, 593, 44, 991, 174, 174, 89, 89, + /* 1640 */ 67, 67, 593, 85, 85, 150, 150, 1114, 1043, 593, + /* 1650 */ 273, 86, 86, 1062, 593, 503, 171, 171, 593, 125, + /* 1660 */ 125, 497, 593, 273, 336, 152, 152, 126, 1335, 464, + /* 1670 */ 594, 464, 146, 146, 1050, 593, 545, 172, 172, 593, + /* 1680 */ 1054, 165, 165, 256, 339, 156, 156, 127, 585, 1586, + /* 1690 */ 4, 329, 584, 499, 358, 273, 115, 348, 155, 155, + /* 1700 */ 930, 931, 153, 153, 588, 1114, 1050, 1050, 1052, 1053, + /* 1710 */ 35, 1554, 521, 593, 270, 1008, 1009, 9, 593, 372, + /* 1720 */ 593, 115, 593, 168, 593, 115, 593, 1110, 464, 270, + /* 1730 */ 996, 964, 273, 129, 1645, 1214, 154, 154, 1054, 1404, + /* 1740 */ 582, 88, 88, 90, 90, 87, 87, 52, 52, 60, + /* 1750 */ 60, 1405, 504, 537, 559, 1179, 961, 507, 129, 558, + /* 1760 */ 127, 585, 1126, 4, 1126, 1125, 894, 1125, 162, 1062, + /* 1770 */ 963, 359, 129, 1401, 363, 125, 125, 588, 366, 368, + /* 1780 */ 370, 1349, 1334, 126, 1333, 464, 594, 464, 377, 387, + /* 1790 */ 1050, 1391, 1414, 1618, 1459, 1387, 1399, 208, 580, 1464, + /* 1800 */ 1314, 464, 243, 516, 1305, 1293, 1384, 1292, 1294, 1638, + /* 1810 */ 288, 170, 228, 582, 12, 408, 321, 322, 241, 323, + /* 1820 */ 245, 1446, 1050, 1050, 1052, 1053, 35, 559, 304, 350, + /* 1830 */ 351, 501, 560, 127, 585, 1441, 4, 1451, 1434, 310, + /* 1840 */ 1450, 526, 1062, 1332, 415, 380, 232, 1527, 125, 125, + /* 1850 */ 588, 1214, 1396, 356, 1526, 583, 126, 1397, 464, 594, + /* 1860 */ 464, 1641, 535, 1050, 1581, 1395, 1269, 1583, 1582, 213, + /* 1870 */ 402, 277, 214, 227, 464, 1573, 239, 1571, 1266, 1394, + /* 1880 */ 434, 198, 100, 224, 96, 183, 582, 191, 485, 193, + /* 1890 */ 486, 194, 195, 196, 519, 1050, 1050, 1052, 1053, 35, + /* 1900 */ 559, 113, 252, 413, 1447, 558, 493, 13, 1455, 416, + /* 1910 */ 1453, 1452, 14, 202, 1521, 1062, 1532, 508, 258, 106, + /* 1920 */ 514, 125, 125, 99, 1214, 1543, 289, 260, 206, 126, + /* 1930 */ 365, 464, 594, 464, 361, 517, 1050, 261, 448, 1295, + /* 1940 */ 262, 418, 1352, 1351, 108, 1350, 1655, 1654, 1343, 915, + /* 1950 */ 419, 1322, 233, 452, 319, 379, 1321, 453, 1623, 320, + /* 1960 */ 1320, 275, 1653, 544, 276, 1609, 1608, 1342, 1050, 1050, + /* 1970 */ 1052, 1053, 35, 1630, 1218, 466, 385, 456, 300, 1419, + /* 1980 */ 144, 1418, 570, 407, 407, 406, 284, 404, 11, 1508, + /* 1990 */ 881, 396, 120, 127, 585, 394, 4, 1214, 327, 114, + /* 2000 */ 1375, 1374, 220, 247, 400, 338, 401, 554, 42, 1224, + /* 2010 */ 588, 596, 283, 337, 285, 286, 188, 597, 1290, 1285, + /* 2020 */ 175, 1558, 176, 1559, 1557, 1556, 159, 317, 229, 177, + /* 2030 */ 868, 230, 91, 465, 464, 221, 331, 468, 1165, 470, + /* 2040 */ 473, 94, 244, 95, 249, 189, 582, 1124, 1122, 341, + /* 2050 */ 427, 190, 178, 1249, 179, 43, 192, 947, 349, 428, + /* 2060 */ 1138, 197, 251, 180, 181, 436, 102, 182, 438, 103, + /* 2070 */ 104, 199, 248, 1140, 253, 1062, 105, 255, 1137, 166, + /* 2080 */ 24, 125, 125, 257, 1264, 273, 360, 513, 259, 126, + /* 2090 */ 15, 464, 594, 464, 204, 883, 1050, 518, 263, 373, + /* 2100 */ 381, 92, 585, 1130, 4, 203, 205, 426, 107, 522, + /* 2110 */ 25, 26, 329, 584, 913, 572, 527, 376, 588, 926, + /* 2120 */ 530, 109, 184, 318, 167, 110, 27, 538, 1050, 1050, + /* 2130 */ 1052, 1053, 35, 1211, 1091, 17, 476, 111, 1181, 234, + /* 2140 */ 292, 1180, 464, 294, 207, 994, 129, 1201, 272, 1000, + /* 2150 */ 28, 1197, 29, 30, 582, 1199, 1205, 1214, 31, 1204, + /* 2160 */ 32, 1186, 41, 566, 33, 1105, 211, 8, 115, 1092, + /* 2170 */ 1090, 1094, 34, 278, 578, 1095, 117, 122, 118, 1145, + /* 2180 */ 36, 18, 128, 1062, 1055, 895, 957, 37, 589, 125, + /* 2190 */ 125, 279, 186, 280, 1646, 157, 405, 126, 1220, 464, + /* 2200 */ 594, 464, 1218, 466, 1050, 1219, 300, 1281, 1281, 1281, + /* 2210 */ 1281, 407, 407, 406, 284, 404, 1281, 1281, 881, 1281, + /* 2220 */ 300, 1281, 1281, 571, 1281, 407, 407, 406, 284, 404, + /* 2230 */ 1281, 247, 881, 338, 1281, 1281, 1050, 1050, 1052, 1053, + /* 2240 */ 35, 337, 1281, 1281, 1281, 247, 1281, 338, 1281, 1281, + /* 2250 */ 1281, 1281, 1281, 1281, 1281, 337, 1281, 1281, 1281, 1281, + /* 2260 */ 1281, 1281, 1281, 1281, 1281, 1214, 1281, 1281, 1281, 1281, + /* 2270 */ 1281, 1281, 249, 1281, 1281, 1281, 1281, 1281, 1281, 1281, + /* 2280 */ 178, 1281, 1281, 43, 1281, 1281, 249, 1281, 1281, 1281, + /* 2290 */ 1281, 1281, 1281, 1281, 178, 1281, 1281, 43, 1281, 1281, + /* 2300 */ 248, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, + /* 2310 */ 1281, 1281, 1281, 1281, 248, 1281, 1281, 1281, 1281, 1281, + /* 2320 */ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, + /* 2330 */ 1281, 1281, 1281, 1281, 1281, 426, 1281, 1281, 1281, 1281, + /* 2340 */ 329, 584, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 426, + /* 2350 */ 1281, 1281, 1281, 1281, 329, 584, 1281, 1281, 1281, 1281, + /* 2360 */ 1281, 1281, 1281, 1281, 476, 1281, 1281, 1281, 1281, 1281, + /* 2370 */ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 476, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 276, 277, 278, 240, 241, 224, 194, 226, 194, 240, - /* 10 */ 241, 194, 216, 220, 194, 234, 253, 194, 255, 19, - /* 20 */ 224, 297, 253, 194, 255, 205, 212, 213, 205, 217, - /* 30 */ 218, 31, 205, 194, 217, 218, 194, 217, 218, 39, - /* 40 */ 217, 218, 312, 43, 44, 45, 316, 47, 48, 49, + /* 0 */ 277, 278, 279, 241, 242, 225, 195, 227, 195, 312, + /* 10 */ 195, 218, 195, 316, 195, 235, 254, 195, 256, 19, + /* 20 */ 297, 277, 278, 279, 218, 206, 213, 214, 206, 218, + /* 30 */ 219, 31, 206, 218, 219, 218, 219, 218, 219, 39, + /* 40 */ 218, 219, 195, 43, 44, 45, 195, 47, 48, 49, /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 19, - /* 60 */ 240, 241, 194, 240, 241, 194, 254, 240, 241, 276, - /* 70 */ 277, 278, 233, 253, 254, 255, 253, 254, 255, 217, - /* 80 */ 253, 239, 255, 43, 44, 45, 263, 47, 48, 49, - /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 270, - /* 100 */ 286, 22, 23, 103, 104, 105, 106, 107, 108, 109, - /* 110 */ 110, 111, 112, 113, 114, 82, 47, 48, 49, 50, - /* 120 */ 186, 187, 188, 189, 190, 191, 189, 87, 191, 89, - /* 130 */ 196, 19, 198, 196, 317, 198, 319, 25, 194, 205, - /* 140 */ 298, 270, 205, 103, 104, 105, 106, 107, 108, 109, - /* 150 */ 110, 111, 112, 113, 114, 43, 44, 45, 11, 47, + /* 60 */ 241, 242, 195, 241, 242, 195, 255, 241, 242, 195, + /* 70 */ 255, 237, 238, 254, 255, 256, 254, 255, 256, 264, + /* 80 */ 254, 207, 256, 43, 44, 45, 264, 47, 48, 49, + /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 251, + /* 100 */ 287, 253, 215, 103, 104, 105, 106, 107, 108, 109, + /* 110 */ 110, 111, 112, 113, 114, 82, 265, 195, 271, 11, + /* 120 */ 187, 188, 189, 190, 191, 192, 190, 87, 192, 89, + /* 130 */ 197, 19, 199, 197, 317, 199, 319, 25, 271, 206, + /* 140 */ 218, 219, 206, 103, 104, 105, 106, 107, 108, 109, + /* 150 */ 110, 111, 112, 113, 114, 43, 44, 45, 195, 47, /* 160 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 170 */ 58, 60, 139, 140, 240, 241, 214, 240, 241, 311, - /* 180 */ 312, 102, 70, 239, 316, 194, 19, 253, 77, 255, - /* 190 */ 253, 122, 255, 55, 56, 57, 58, 59, 207, 88, - /* 200 */ 194, 90, 268, 194, 93, 268, 107, 108, 109, 110, - /* 210 */ 111, 112, 113, 114, 47, 103, 104, 105, 106, 107, - /* 220 */ 108, 109, 110, 111, 112, 113, 114, 114, 117, 118, - /* 230 */ 119, 276, 277, 278, 300, 19, 194, 300, 276, 277, - /* 240 */ 278, 103, 104, 105, 106, 107, 108, 109, 110, 111, - /* 250 */ 112, 113, 114, 55, 56, 57, 58, 146, 194, 43, - /* 260 */ 44, 45, 47, 47, 48, 49, 50, 51, 52, 53, - /* 270 */ 54, 55, 56, 57, 58, 82, 129, 130, 60, 129, - /* 280 */ 130, 217, 218, 116, 68, 25, 103, 104, 105, 106, - /* 290 */ 107, 108, 109, 110, 111, 112, 113, 114, 23, 132, - /* 300 */ 294, 103, 104, 105, 106, 107, 108, 109, 110, 111, - /* 310 */ 112, 113, 114, 217, 121, 306, 194, 308, 26, 103, + /* 170 */ 58, 60, 139, 140, 241, 242, 289, 241, 242, 309, + /* 180 */ 310, 294, 70, 47, 48, 49, 50, 254, 77, 256, + /* 190 */ 254, 195, 256, 55, 56, 57, 58, 59, 221, 88, + /* 200 */ 109, 90, 269, 240, 93, 269, 107, 108, 109, 110, + /* 210 */ 111, 112, 113, 114, 215, 103, 104, 105, 106, 107, + /* 220 */ 108, 109, 110, 111, 112, 113, 114, 136, 117, 118, + /* 230 */ 119, 298, 141, 300, 298, 19, 300, 129, 130, 317, + /* 240 */ 318, 103, 104, 105, 106, 107, 108, 109, 110, 111, + /* 250 */ 112, 113, 114, 114, 277, 278, 279, 146, 122, 43, + /* 260 */ 44, 45, 195, 47, 48, 49, 50, 51, 52, 53, + /* 270 */ 54, 55, 56, 57, 58, 218, 277, 278, 279, 19, + /* 280 */ 19, 195, 286, 23, 68, 218, 219, 55, 56, 57, + /* 290 */ 58, 103, 104, 105, 106, 107, 108, 109, 110, 111, + /* 300 */ 112, 113, 114, 43, 44, 45, 232, 47, 48, 49, + /* 310 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 103, /* 320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - /* 330 */ 114, 116, 139, 140, 217, 117, 118, 119, 120, 19, - /* 340 */ 194, 123, 124, 125, 24, 109, 110, 111, 112, 113, - /* 350 */ 114, 133, 60, 311, 312, 250, 194, 252, 316, 19, - /* 360 */ 194, 166, 167, 43, 44, 45, 205, 47, 48, 49, - /* 370 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 217, - /* 380 */ 218, 317, 318, 43, 44, 45, 264, 47, 48, 49, - /* 390 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 139, - /* 400 */ 140, 240, 241, 139, 140, 188, 189, 190, 191, 117, - /* 410 */ 118, 119, 231, 196, 253, 198, 255, 194, 194, 258, - /* 420 */ 259, 146, 205, 103, 104, 105, 106, 107, 108, 109, - /* 430 */ 110, 111, 112, 113, 114, 109, 212, 213, 236, 237, - /* 440 */ 217, 218, 194, 103, 104, 105, 106, 107, 108, 109, - /* 450 */ 110, 111, 112, 113, 114, 194, 120, 240, 241, 123, - /* 460 */ 124, 125, 136, 194, 19, 74, 60, 141, 23, 133, - /* 470 */ 253, 194, 255, 82, 194, 309, 310, 254, 29, 317, - /* 480 */ 318, 194, 33, 22, 199, 268, 263, 239, 43, 44, - /* 490 */ 45, 151, 47, 48, 49, 50, 51, 52, 53, 54, - /* 500 */ 55, 56, 57, 58, 217, 218, 194, 60, 19, 146, - /* 510 */ 286, 242, 23, 107, 108, 66, 204, 300, 206, 128, - /* 520 */ 73, 60, 116, 117, 118, 119, 265, 121, 165, 60, - /* 530 */ 139, 140, 43, 44, 45, 129, 47, 48, 49, 50, - /* 540 */ 51, 52, 53, 54, 55, 56, 57, 58, 103, 104, - /* 550 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - /* 560 */ 154, 194, 156, 194, 117, 118, 119, 280, 283, 205, - /* 570 */ 101, 220, 287, 19, 20, 306, 22, 308, 117, 118, - /* 580 */ 119, 211, 212, 213, 217, 218, 117, 118, 236, 237, - /* 590 */ 36, 122, 103, 104, 105, 106, 107, 108, 109, 110, - /* 600 */ 111, 112, 113, 114, 240, 241, 194, 60, 194, 194, - /* 610 */ 194, 194, 19, 194, 60, 194, 23, 253, 206, 255, - /* 620 */ 73, 254, 19, 154, 155, 156, 72, 276, 277, 278, - /* 630 */ 263, 217, 218, 217, 218, 271, 43, 44, 45, 271, - /* 640 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 650 */ 57, 58, 183, 194, 285, 101, 19, 214, 60, 242, - /* 660 */ 23, 107, 108, 109, 117, 118, 119, 16, 254, 115, - /* 670 */ 254, 117, 118, 119, 194, 60, 122, 263, 205, 264, - /* 680 */ 43, 44, 45, 264, 47, 48, 49, 50, 51, 52, - /* 690 */ 53, 54, 55, 56, 57, 58, 103, 104, 105, 106, - /* 700 */ 107, 108, 109, 110, 111, 112, 113, 114, 154, 155, - /* 710 */ 156, 157, 158, 240, 241, 117, 118, 119, 101, 205, - /* 720 */ 117, 19, 20, 306, 22, 308, 253, 74, 255, 78, - /* 730 */ 205, 80, 117, 118, 119, 118, 293, 183, 36, 122, - /* 740 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 750 */ 113, 114, 194, 294, 240, 241, 211, 212, 213, 144, - /* 760 */ 19, 23, 60, 25, 23, 240, 241, 253, 245, 255, - /* 770 */ 15, 154, 155, 156, 72, 217, 218, 194, 253, 256, - /* 780 */ 255, 128, 129, 130, 43, 44, 45, 22, 47, 48, - /* 790 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - /* 800 */ 183, 19, 77, 101, 19, 128, 129, 130, 23, 107, - /* 810 */ 108, 60, 254, 88, 21, 90, 61, 115, 93, 117, - /* 820 */ 118, 119, 239, 22, 122, 60, 194, 205, 43, 44, - /* 830 */ 45, 205, 47, 48, 49, 50, 51, 52, 53, 54, - /* 840 */ 55, 56, 57, 58, 103, 104, 105, 106, 107, 108, - /* 850 */ 109, 110, 111, 112, 113, 114, 154, 155, 156, 157, - /* 860 */ 158, 60, 240, 241, 60, 116, 240, 241, 117, 118, - /* 870 */ 119, 146, 194, 19, 81, 253, 275, 255, 24, 253, - /* 880 */ 98, 255, 117, 118, 119, 183, 22, 194, 103, 104, - /* 890 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - /* 900 */ 151, 194, 270, 152, 22, 23, 194, 25, 19, 202, - /* 910 */ 217, 218, 23, 109, 207, 314, 315, 124, 117, 118, - /* 920 */ 119, 117, 118, 119, 60, 232, 22, 23, 19, 25, - /* 930 */ 303, 304, 43, 44, 45, 22, 47, 48, 49, 50, - /* 940 */ 51, 52, 53, 54, 55, 56, 57, 58, 270, 227, - /* 950 */ 96, 60, 43, 44, 45, 162, 47, 48, 49, 50, - /* 960 */ 51, 52, 53, 54, 55, 56, 57, 58, 114, 112, - /* 970 */ 113, 114, 194, 60, 120, 121, 122, 123, 124, 125, - /* 980 */ 126, 117, 118, 119, 102, 25, 132, 107, 108, 194, - /* 990 */ 194, 227, 103, 104, 105, 106, 107, 108, 109, 110, - /* 1000 */ 111, 112, 113, 114, 194, 194, 102, 194, 117, 118, - /* 1010 */ 119, 233, 103, 104, 105, 106, 107, 108, 109, 110, - /* 1020 */ 111, 112, 113, 114, 194, 194, 19, 194, 217, 218, - /* 1030 */ 117, 118, 119, 241, 154, 144, 156, 135, 242, 137, - /* 1040 */ 138, 130, 19, 232, 194, 253, 23, 255, 217, 218, - /* 1050 */ 217, 218, 242, 16, 7, 8, 9, 25, 261, 262, - /* 1060 */ 265, 194, 19, 232, 153, 232, 43, 44, 45, 160, - /* 1070 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1080 */ 57, 58, 194, 227, 217, 218, 43, 44, 45, 194, - /* 1090 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1100 */ 57, 58, 306, 143, 308, 217, 218, 294, 12, 77, - /* 1110 */ 22, 23, 217, 218, 194, 78, 306, 80, 308, 194, - /* 1120 */ 232, 254, 90, 27, 117, 93, 103, 104, 105, 106, - /* 1130 */ 107, 108, 109, 110, 111, 112, 113, 114, 42, 194, - /* 1140 */ 35, 194, 217, 218, 214, 194, 103, 104, 105, 106, - /* 1150 */ 107, 108, 109, 110, 111, 112, 113, 114, 194, 239, - /* 1160 */ 64, 194, 217, 218, 217, 218, 209, 210, 217, 218, - /* 1170 */ 74, 207, 67, 22, 194, 77, 19, 232, 245, 232, - /* 1180 */ 75, 24, 312, 232, 217, 218, 316, 25, 90, 256, - /* 1190 */ 102, 93, 159, 229, 161, 231, 19, 217, 218, 162, - /* 1200 */ 43, 44, 45, 160, 47, 48, 49, 50, 51, 52, - /* 1210 */ 53, 54, 55, 56, 57, 58, 19, 23, 288, 25, - /* 1220 */ 43, 44, 45, 293, 47, 48, 49, 50, 51, 52, - /* 1230 */ 53, 54, 55, 56, 57, 58, 131, 22, 275, 24, - /* 1240 */ 43, 44, 45, 194, 47, 48, 49, 50, 51, 52, - /* 1250 */ 53, 54, 55, 56, 57, 58, 194, 194, 107, 108, - /* 1260 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1270 */ 113, 114, 194, 25, 194, 60, 194, 314, 315, 194, - /* 1280 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1290 */ 113, 114, 19, 194, 194, 217, 218, 217, 218, 25, - /* 1300 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1310 */ 113, 114, 150, 119, 265, 312, 67, 217, 218, 316, - /* 1320 */ 19, 239, 194, 194, 128, 129, 130, 265, 265, 209, - /* 1330 */ 210, 31, 254, 118, 254, 86, 60, 194, 144, 39, - /* 1340 */ 19, 130, 275, 312, 95, 44, 45, 316, 47, 48, - /* 1350 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - /* 1360 */ 217, 218, 24, 194, 153, 12, 45, 119, 47, 48, - /* 1370 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - /* 1380 */ 27, 314, 315, 22, 312, 24, 217, 218, 316, 116, - /* 1390 */ 117, 22, 144, 25, 118, 42, 147, 194, 60, 19, - /* 1400 */ 20, 127, 22, 194, 103, 104, 105, 106, 107, 108, - /* 1410 */ 109, 110, 111, 112, 113, 114, 36, 64, 145, 194, - /* 1420 */ 217, 218, 194, 54, 103, 104, 105, 106, 107, 108, - /* 1430 */ 109, 110, 111, 112, 113, 114, 194, 22, 310, 25, - /* 1440 */ 60, 194, 217, 218, 194, 217, 218, 194, 260, 194, - /* 1450 */ 301, 302, 72, 262, 262, 194, 118, 266, 266, 217, - /* 1460 */ 218, 194, 82, 245, 217, 218, 194, 217, 218, 194, - /* 1470 */ 217, 218, 217, 218, 256, 60, 24, 194, 217, 218, - /* 1480 */ 194, 101, 194, 245, 217, 218, 194, 107, 108, 217, - /* 1490 */ 218, 22, 217, 218, 256, 115, 245, 117, 118, 119, - /* 1500 */ 217, 218, 122, 217, 218, 217, 218, 256, 22, 217, - /* 1510 */ 218, 116, 258, 259, 146, 19, 20, 194, 22, 139, - /* 1520 */ 140, 150, 151, 136, 23, 194, 25, 194, 141, 194, - /* 1530 */ 194, 62, 36, 118, 154, 155, 156, 157, 158, 100, - /* 1540 */ 145, 194, 154, 194, 156, 49, 194, 23, 194, 25, - /* 1550 */ 217, 218, 217, 218, 194, 257, 60, 143, 194, 60, - /* 1560 */ 194, 121, 122, 183, 217, 218, 217, 218, 72, 217, - /* 1570 */ 218, 217, 218, 134, 23, 194, 25, 217, 218, 7, - /* 1580 */ 8, 321, 86, 217, 218, 194, 122, 91, 19, 20, - /* 1590 */ 23, 22, 25, 23, 142, 25, 132, 101, 217, 218, - /* 1600 */ 194, 194, 194, 107, 108, 36, 194, 194, 217, 218, - /* 1610 */ 194, 115, 194, 117, 118, 119, 194, 118, 122, 194, - /* 1620 */ 23, 194, 25, 217, 218, 217, 218, 194, 142, 60, - /* 1630 */ 217, 218, 194, 217, 218, 217, 218, 84, 85, 217, - /* 1640 */ 218, 72, 217, 218, 217, 218, 60, 23, 60, 25, - /* 1650 */ 154, 155, 156, 157, 158, 86, 154, 194, 156, 194, - /* 1660 */ 91, 19, 20, 23, 22, 25, 194, 23, 194, 25, - /* 1670 */ 101, 23, 194, 25, 194, 194, 107, 108, 36, 183, - /* 1680 */ 217, 218, 217, 218, 115, 194, 117, 118, 119, 217, - /* 1690 */ 218, 122, 194, 237, 194, 217, 218, 217, 218, 194, - /* 1700 */ 194, 23, 60, 25, 118, 23, 118, 25, 217, 218, - /* 1710 */ 23, 194, 25, 194, 72, 217, 218, 217, 218, 23, - /* 1720 */ 194, 25, 194, 154, 155, 156, 157, 158, 86, 23, - /* 1730 */ 194, 25, 194, 91, 217, 218, 217, 218, 194, 194, - /* 1740 */ 194, 194, 194, 101, 194, 217, 218, 290, 194, 107, - /* 1750 */ 108, 194, 183, 217, 218, 194, 194, 115, 194, 117, - /* 1760 */ 118, 119, 194, 243, 122, 194, 289, 194, 194, 194, - /* 1770 */ 194, 257, 257, 257, 244, 257, 192, 273, 215, 269, - /* 1780 */ 246, 299, 269, 295, 247, 273, 247, 246, 295, 230, - /* 1790 */ 261, 226, 261, 261, 273, 273, 154, 155, 156, 157, - /* 1800 */ 158, 0, 1, 2, 221, 220, 5, 220, 250, 220, - /* 1810 */ 261, 10, 11, 12, 13, 14, 250, 282, 17, 197, - /* 1820 */ 61, 19, 20, 246, 22, 183, 244, 142, 201, 201, - /* 1830 */ 38, 30, 299, 32, 201, 152, 22, 151, 36, 299, - /* 1840 */ 43, 40, 235, 18, 238, 285, 238, 238, 296, 238, - /* 1850 */ 201, 296, 274, 272, 18, 200, 235, 150, 235, 247, - /* 1860 */ 247, 247, 60, 247, 274, 274, 272, 201, 200, 159, - /* 1870 */ 63, 292, 71, 201, 72, 200, 22, 201, 222, 200, - /* 1880 */ 79, 201, 222, 82, 291, 116, 219, 65, 200, 219, - /* 1890 */ 219, 228, 22, 127, 225, 166, 222, 24, 225, 114, - /* 1900 */ 99, 284, 221, 101, 284, 228, 307, 315, 219, 107, - /* 1910 */ 108, 219, 219, 219, 201, 92, 320, 115, 320, 117, - /* 1920 */ 118, 119, 222, 83, 122, 267, 267, 149, 146, 19, - /* 1930 */ 20, 22, 22, 279, 250, 134, 201, 148, 159, 249, - /* 1940 */ 139, 140, 251, 141, 25, 281, 36, 147, 251, 248, - /* 1950 */ 247, 203, 13, 195, 6, 195, 154, 155, 156, 157, - /* 1960 */ 158, 193, 305, 193, 163, 193, 305, 302, 214, 208, - /* 1970 */ 60, 214, 208, 223, 223, 4, 214, 214, 3, 22, - /* 1980 */ 215, 214, 72, 208, 164, 183, 215, 15, 23, 16, - /* 1990 */ 23, 140, 131, 152, 25, 143, 20, 16, 24, 1, - /* 2000 */ 145, 143, 131, 131, 62, 37, 54, 54, 152, 54, - /* 2010 */ 54, 101, 131, 117, 34, 1, 142, 107, 108, 22, - /* 2020 */ 5, 116, 162, 69, 25, 115, 76, 117, 118, 119, - /* 2030 */ 1, 2, 122, 69, 5, 41, 142, 116, 20, 10, - /* 2040 */ 11, 12, 13, 14, 24, 19, 17, 132, 5, 126, - /* 2050 */ 22, 141, 68, 10, 11, 12, 13, 14, 22, 30, - /* 2060 */ 17, 32, 22, 22, 154, 155, 156, 157, 158, 40, - /* 2070 */ 23, 68, 60, 30, 24, 32, 97, 28, 22, 68, - /* 2080 */ 23, 37, 34, 40, 150, 22, 25, 23, 23, 23, - /* 2090 */ 22, 98, 23, 183, 23, 117, 34, 22, 25, 89, - /* 2100 */ 71, 142, 144, 76, 34, 23, 34, 76, 79, 87, - /* 2110 */ 34, 82, 34, 94, 71, 34, 22, 24, 44, 34, - /* 2120 */ 25, 25, 79, 23, 23, 82, 143, 23, 99, 143, - /* 2130 */ 23, 22, 11, 25, 23, 25, 22, 22, 22, 1, - /* 2140 */ 23, 23, 99, 136, 22, 22, 142, 142, 142, 25, - /* 2150 */ 25, 23, 15, 1, 322, 322, 322, 322, 322, 322, - /* 2160 */ 322, 322, 322, 134, 322, 322, 322, 322, 139, 140, - /* 2170 */ 322, 322, 322, 322, 322, 322, 322, 134, 322, 322, - /* 2180 */ 322, 322, 139, 140, 322, 322, 322, 322, 322, 322, - /* 2190 */ 322, 322, 163, 322, 322, 322, 322, 322, 322, 322, - /* 2200 */ 322, 322, 322, 322, 322, 322, 163, 322, 322, 322, - /* 2210 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2220 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2230 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2240 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2250 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2260 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2270 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2280 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2290 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2300 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2310 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, + /* 330 */ 114, 135, 60, 137, 138, 103, 104, 105, 106, 107, + /* 340 */ 108, 109, 110, 111, 112, 113, 114, 82, 281, 206, + /* 350 */ 195, 109, 110, 111, 112, 113, 114, 195, 195, 195, + /* 360 */ 205, 22, 207, 103, 104, 105, 106, 107, 108, 109, + /* 370 */ 110, 111, 112, 113, 114, 195, 60, 116, 117, 107, + /* 380 */ 108, 218, 219, 19, 241, 242, 121, 23, 116, 117, + /* 390 */ 118, 119, 306, 121, 308, 206, 234, 254, 15, 256, + /* 400 */ 195, 129, 259, 260, 139, 140, 145, 43, 44, 45, + /* 410 */ 200, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 420 */ 56, 57, 58, 218, 219, 60, 154, 19, 156, 265, + /* 430 */ 241, 242, 24, 117, 118, 119, 120, 21, 73, 123, + /* 440 */ 124, 125, 74, 254, 61, 256, 107, 108, 221, 133, + /* 450 */ 82, 43, 44, 45, 195, 47, 48, 49, 50, 51, + /* 460 */ 52, 53, 54, 55, 56, 57, 58, 103, 104, 105, + /* 470 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 195, + /* 480 */ 317, 318, 117, 118, 119, 22, 120, 195, 22, 123, + /* 490 */ 124, 125, 19, 20, 284, 22, 128, 81, 288, 133, + /* 500 */ 195, 195, 218, 219, 277, 278, 279, 139, 140, 36, + /* 510 */ 195, 103, 104, 105, 106, 107, 108, 109, 110, 111, + /* 520 */ 112, 113, 114, 218, 219, 62, 60, 195, 241, 242, + /* 530 */ 271, 19, 240, 60, 189, 190, 191, 192, 233, 255, + /* 540 */ 124, 254, 197, 256, 199, 72, 129, 130, 264, 195, + /* 550 */ 195, 206, 22, 23, 60, 43, 44, 45, 206, 47, + /* 560 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 570 */ 58, 195, 218, 219, 101, 195, 60, 271, 162, 195, + /* 580 */ 107, 108, 109, 117, 118, 119, 241, 242, 115, 73, + /* 590 */ 117, 118, 119, 241, 242, 122, 60, 195, 266, 254, + /* 600 */ 312, 256, 218, 219, 316, 203, 254, 195, 256, 255, + /* 610 */ 208, 117, 118, 119, 269, 103, 104, 105, 106, 107, + /* 620 */ 108, 109, 110, 111, 112, 113, 114, 154, 155, 156, + /* 630 */ 157, 158, 102, 117, 118, 119, 19, 242, 144, 255, + /* 640 */ 23, 206, 24, 298, 195, 300, 206, 195, 264, 254, + /* 650 */ 206, 256, 240, 117, 118, 119, 183, 22, 22, 23, + /* 660 */ 43, 44, 45, 151, 47, 48, 49, 50, 51, 52, + /* 670 */ 53, 54, 55, 56, 57, 58, 241, 242, 60, 195, + /* 680 */ 19, 241, 242, 195, 23, 241, 242, 195, 152, 254, + /* 690 */ 310, 256, 243, 312, 254, 60, 256, 316, 254, 206, + /* 700 */ 256, 60, 218, 219, 43, 44, 45, 272, 47, 48, + /* 710 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + /* 720 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 730 */ 113, 114, 240, 60, 241, 242, 118, 25, 102, 255, + /* 740 */ 166, 167, 101, 22, 26, 19, 20, 254, 22, 256, + /* 750 */ 139, 140, 117, 118, 119, 306, 195, 308, 117, 118, + /* 760 */ 237, 238, 36, 122, 103, 104, 105, 106, 107, 108, + /* 770 */ 109, 110, 111, 112, 113, 114, 195, 195, 60, 218, + /* 780 */ 219, 60, 109, 195, 19, 217, 60, 25, 23, 77, + /* 790 */ 117, 118, 119, 225, 233, 154, 155, 156, 72, 312, + /* 800 */ 218, 219, 90, 316, 22, 93, 303, 304, 43, 44, + /* 810 */ 45, 195, 47, 48, 49, 50, 51, 52, 53, 54, + /* 820 */ 55, 56, 57, 58, 183, 195, 195, 101, 19, 213, + /* 830 */ 214, 243, 23, 107, 108, 117, 118, 119, 117, 118, + /* 840 */ 119, 115, 60, 117, 118, 119, 195, 60, 122, 218, + /* 850 */ 219, 22, 43, 44, 45, 35, 47, 48, 49, 50, + /* 860 */ 51, 52, 53, 54, 55, 56, 57, 58, 103, 104, + /* 870 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 880 */ 154, 155, 156, 157, 158, 195, 255, 67, 195, 60, + /* 890 */ 101, 240, 311, 312, 306, 75, 308, 316, 29, 117, + /* 900 */ 118, 119, 33, 287, 117, 118, 119, 118, 146, 183, + /* 910 */ 195, 122, 103, 104, 105, 106, 107, 108, 109, 110, + /* 920 */ 111, 112, 113, 114, 215, 195, 77, 60, 25, 195, + /* 930 */ 122, 144, 19, 218, 219, 66, 23, 88, 246, 90, + /* 940 */ 132, 25, 93, 154, 155, 156, 117, 118, 119, 257, + /* 950 */ 195, 131, 218, 219, 195, 265, 43, 44, 45, 195, + /* 960 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 970 */ 57, 58, 183, 218, 219, 195, 19, 218, 219, 195, + /* 980 */ 23, 195, 218, 219, 117, 118, 119, 195, 233, 255, + /* 990 */ 195, 195, 233, 22, 23, 146, 25, 233, 218, 219, + /* 1000 */ 43, 44, 45, 294, 47, 48, 49, 50, 51, 52, + /* 1010 */ 53, 54, 55, 56, 57, 58, 103, 104, 105, 106, + /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 114, 195, 12, + /* 1030 */ 234, 195, 240, 74, 195, 255, 195, 60, 243, 262, + /* 1040 */ 263, 311, 312, 25, 27, 19, 316, 107, 108, 265, + /* 1050 */ 24, 265, 195, 150, 195, 139, 140, 218, 219, 42, + /* 1060 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 1070 */ 113, 114, 233, 102, 67, 218, 219, 218, 219, 243, + /* 1080 */ 19, 64, 22, 23, 23, 25, 195, 128, 129, 130, + /* 1090 */ 233, 74, 233, 86, 154, 118, 156, 130, 265, 208, + /* 1100 */ 19, 306, 95, 308, 43, 44, 45, 266, 47, 48, + /* 1110 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + /* 1120 */ 153, 230, 96, 232, 43, 44, 45, 19, 47, 48, + /* 1130 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + /* 1140 */ 114, 22, 306, 24, 308, 127, 120, 121, 122, 123, + /* 1150 */ 124, 125, 126, 195, 147, 212, 213, 214, 132, 23, + /* 1160 */ 195, 25, 102, 100, 103, 104, 105, 106, 107, 108, + /* 1170 */ 109, 110, 111, 112, 113, 114, 218, 219, 19, 60, + /* 1180 */ 195, 12, 210, 211, 103, 104, 105, 106, 107, 108, + /* 1190 */ 109, 110, 111, 112, 113, 114, 27, 134, 195, 195, + /* 1200 */ 195, 210, 211, 218, 219, 195, 47, 195, 212, 213, + /* 1210 */ 214, 42, 16, 130, 19, 112, 113, 114, 23, 77, + /* 1220 */ 195, 218, 219, 218, 219, 117, 163, 164, 218, 219, + /* 1230 */ 218, 219, 90, 64, 19, 93, 153, 118, 43, 44, + /* 1240 */ 45, 160, 47, 48, 49, 50, 51, 52, 53, 54, + /* 1250 */ 55, 56, 57, 58, 195, 119, 272, 276, 43, 44, + /* 1260 */ 45, 195, 47, 48, 49, 50, 51, 52, 53, 54, + /* 1270 */ 55, 56, 57, 58, 78, 116, 80, 218, 219, 116, + /* 1280 */ 144, 128, 129, 130, 218, 219, 61, 195, 47, 195, + /* 1290 */ 16, 132, 195, 263, 195, 314, 315, 267, 103, 104, + /* 1300 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 1310 */ 218, 219, 218, 219, 151, 218, 219, 195, 103, 104, + /* 1320 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 1330 */ 210, 211, 195, 7, 8, 9, 195, 60, 195, 312, + /* 1340 */ 218, 219, 195, 316, 195, 120, 195, 263, 19, 195, + /* 1350 */ 125, 267, 78, 24, 80, 218, 219, 116, 162, 218, + /* 1360 */ 219, 218, 219, 301, 302, 218, 219, 195, 19, 218, + /* 1370 */ 219, 276, 43, 44, 45, 160, 47, 48, 49, 50, + /* 1380 */ 51, 52, 53, 54, 55, 56, 57, 58, 19, 146, + /* 1390 */ 218, 219, 43, 44, 45, 118, 47, 48, 49, 50, + /* 1400 */ 51, 52, 53, 54, 55, 56, 57, 58, 165, 314, + /* 1410 */ 315, 276, 43, 44, 45, 266, 47, 48, 49, 50, + /* 1420 */ 51, 52, 53, 54, 55, 56, 57, 58, 128, 129, + /* 1430 */ 130, 195, 103, 104, 105, 106, 107, 108, 109, 110, + /* 1440 */ 111, 112, 113, 114, 195, 228, 195, 61, 195, 314, + /* 1450 */ 315, 25, 103, 104, 105, 106, 107, 108, 109, 110, + /* 1460 */ 111, 112, 113, 114, 195, 22, 195, 218, 219, 218, + /* 1470 */ 219, 195, 103, 104, 105, 106, 107, 108, 109, 110, + /* 1480 */ 111, 112, 113, 114, 195, 195, 246, 218, 219, 218, + /* 1490 */ 219, 25, 19, 246, 218, 219, 246, 257, 259, 260, + /* 1500 */ 195, 22, 266, 60, 257, 195, 120, 257, 218, 219, + /* 1510 */ 116, 195, 19, 195, 150, 151, 25, 44, 45, 266, + /* 1520 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 1530 */ 57, 58, 195, 54, 218, 219, 218, 219, 45, 145, + /* 1540 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 1550 */ 57, 58, 246, 121, 122, 218, 219, 19, 23, 31, + /* 1560 */ 25, 118, 159, 257, 161, 24, 195, 39, 195, 143, + /* 1570 */ 195, 19, 20, 22, 22, 24, 103, 104, 105, 106, + /* 1580 */ 107, 108, 109, 110, 111, 112, 113, 114, 36, 218, + /* 1590 */ 219, 218, 219, 218, 219, 195, 103, 104, 105, 106, + /* 1600 */ 107, 108, 109, 110, 111, 112, 113, 114, 195, 143, + /* 1610 */ 119, 136, 60, 195, 22, 195, 141, 195, 218, 219, + /* 1620 */ 195, 23, 195, 25, 72, 23, 131, 25, 195, 134, + /* 1630 */ 23, 218, 219, 195, 82, 144, 218, 219, 218, 219, + /* 1640 */ 218, 219, 195, 218, 219, 218, 219, 60, 23, 195, + /* 1650 */ 25, 218, 219, 101, 195, 117, 218, 219, 195, 107, + /* 1660 */ 108, 23, 195, 25, 195, 218, 219, 115, 228, 117, + /* 1670 */ 118, 119, 218, 219, 122, 195, 19, 218, 219, 195, + /* 1680 */ 60, 218, 219, 142, 195, 218, 219, 19, 20, 195, + /* 1690 */ 22, 139, 140, 23, 23, 25, 25, 195, 218, 219, + /* 1700 */ 7, 8, 218, 219, 36, 118, 154, 155, 156, 157, + /* 1710 */ 158, 195, 23, 195, 25, 84, 85, 49, 195, 23, + /* 1720 */ 195, 25, 195, 23, 195, 25, 195, 23, 60, 25, + /* 1730 */ 23, 23, 25, 25, 142, 183, 218, 219, 118, 195, + /* 1740 */ 72, 218, 219, 218, 219, 218, 219, 218, 219, 218, + /* 1750 */ 219, 195, 195, 146, 86, 98, 23, 195, 25, 91, + /* 1760 */ 19, 20, 154, 22, 156, 154, 23, 156, 25, 101, + /* 1770 */ 23, 195, 25, 195, 195, 107, 108, 36, 195, 195, + /* 1780 */ 195, 195, 228, 115, 195, 117, 118, 119, 195, 195, + /* 1790 */ 122, 261, 195, 321, 195, 195, 195, 258, 238, 195, + /* 1800 */ 195, 60, 299, 291, 195, 195, 258, 195, 195, 195, + /* 1810 */ 290, 244, 216, 72, 245, 193, 258, 258, 299, 258, + /* 1820 */ 299, 274, 154, 155, 156, 157, 158, 86, 247, 295, + /* 1830 */ 248, 295, 91, 19, 20, 270, 22, 274, 270, 248, + /* 1840 */ 274, 222, 101, 227, 274, 221, 231, 221, 107, 108, + /* 1850 */ 36, 183, 262, 247, 221, 283, 115, 262, 117, 118, + /* 1860 */ 119, 198, 116, 122, 220, 262, 61, 220, 220, 251, + /* 1870 */ 247, 142, 251, 245, 60, 202, 299, 202, 38, 262, + /* 1880 */ 202, 22, 152, 151, 296, 43, 72, 236, 18, 239, + /* 1890 */ 202, 239, 239, 239, 18, 154, 155, 156, 157, 158, + /* 1900 */ 86, 150, 201, 248, 275, 91, 248, 273, 236, 248, + /* 1910 */ 275, 275, 273, 236, 248, 101, 286, 202, 201, 159, + /* 1920 */ 63, 107, 108, 296, 183, 293, 202, 201, 22, 115, + /* 1930 */ 202, 117, 118, 119, 292, 223, 122, 201, 65, 202, + /* 1940 */ 201, 223, 220, 220, 22, 220, 226, 226, 229, 127, + /* 1950 */ 223, 220, 166, 24, 285, 220, 222, 114, 315, 285, + /* 1960 */ 220, 202, 220, 307, 92, 320, 320, 229, 154, 155, + /* 1970 */ 156, 157, 158, 0, 1, 2, 223, 83, 5, 268, + /* 1980 */ 149, 268, 146, 10, 11, 12, 13, 14, 22, 280, + /* 1990 */ 17, 202, 159, 19, 20, 251, 22, 183, 282, 148, + /* 2000 */ 252, 252, 250, 30, 249, 32, 248, 147, 25, 13, + /* 2010 */ 36, 204, 196, 40, 196, 6, 302, 194, 194, 194, + /* 2020 */ 209, 215, 209, 215, 215, 215, 224, 224, 216, 209, + /* 2030 */ 4, 216, 215, 3, 60, 22, 122, 19, 122, 19, + /* 2040 */ 125, 22, 15, 22, 71, 16, 72, 23, 23, 140, + /* 2050 */ 305, 152, 79, 25, 131, 82, 143, 20, 16, 305, + /* 2060 */ 1, 143, 145, 131, 131, 62, 54, 131, 37, 54, + /* 2070 */ 54, 152, 99, 117, 34, 101, 54, 24, 1, 5, + /* 2080 */ 22, 107, 108, 116, 76, 25, 162, 41, 142, 115, + /* 2090 */ 24, 117, 118, 119, 116, 20, 122, 19, 126, 23, + /* 2100 */ 132, 19, 20, 69, 22, 69, 22, 134, 22, 68, + /* 2110 */ 22, 22, 139, 140, 60, 141, 68, 24, 36, 28, + /* 2120 */ 97, 22, 37, 68, 23, 150, 34, 22, 154, 155, + /* 2130 */ 156, 157, 158, 23, 23, 22, 163, 25, 23, 142, + /* 2140 */ 23, 98, 60, 23, 22, 144, 25, 76, 34, 117, + /* 2150 */ 34, 89, 34, 34, 72, 87, 76, 183, 34, 94, + /* 2160 */ 34, 23, 22, 24, 34, 23, 25, 44, 25, 23, + /* 2170 */ 23, 23, 22, 22, 25, 11, 143, 25, 143, 23, + /* 2180 */ 22, 22, 22, 101, 23, 23, 136, 22, 25, 107, + /* 2190 */ 108, 142, 25, 142, 142, 23, 15, 115, 1, 117, + /* 2200 */ 118, 119, 1, 2, 122, 1, 5, 322, 322, 322, + /* 2210 */ 322, 10, 11, 12, 13, 14, 322, 322, 17, 322, + /* 2220 */ 5, 322, 322, 141, 322, 10, 11, 12, 13, 14, + /* 2230 */ 322, 30, 17, 32, 322, 322, 154, 155, 156, 157, + /* 2240 */ 158, 40, 322, 322, 322, 30, 322, 32, 322, 322, + /* 2250 */ 322, 322, 322, 322, 322, 40, 322, 322, 322, 322, + /* 2260 */ 322, 322, 322, 322, 322, 183, 322, 322, 322, 322, + /* 2270 */ 322, 322, 71, 322, 322, 322, 322, 322, 322, 322, + /* 2280 */ 79, 322, 322, 82, 322, 322, 71, 322, 322, 322, + /* 2290 */ 322, 322, 322, 322, 79, 322, 322, 82, 322, 322, + /* 2300 */ 99, 322, 322, 322, 322, 322, 322, 322, 322, 322, + /* 2310 */ 322, 322, 322, 322, 99, 322, 322, 322, 322, 322, /* 2320 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2330 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2340 */ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, - /* 2350 */ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, - /* 2360 */ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, - /* 2370 */ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, - /* 2380 */ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, - /* 2390 */ 186, 186, 186, + /* 2330 */ 322, 322, 322, 322, 322, 134, 322, 322, 322, 322, + /* 2340 */ 139, 140, 322, 322, 322, 322, 322, 322, 322, 134, + /* 2350 */ 322, 322, 322, 322, 139, 140, 322, 322, 322, 322, + /* 2360 */ 322, 322, 322, 322, 163, 322, 322, 322, 322, 322, + /* 2370 */ 322, 322, 322, 322, 322, 322, 322, 322, 163, 322, + /* 2380 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, + /* 2390 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, + /* 2400 */ 322, 322, 322, 322, 322, 322, 322, 322, 187, 187, + /* 2410 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2420 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2430 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2440 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2450 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2460 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2470 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2480 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2490 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2500 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2510 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2520 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2530 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2540 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2550 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2560 */ 187, 187, 187, 187, 187, 187, }; -#define YY_SHIFT_COUNT (582) +#define YY_SHIFT_COUNT (599) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (2152) +#define YY_SHIFT_MAX (2215) static const unsigned short int yy_shift_ofst[] = { - /* 0 */ 2029, 1801, 2043, 1380, 1380, 33, 391, 1496, 1569, 1642, - /* 10 */ 702, 702, 702, 193, 33, 33, 33, 33, 33, 0, - /* 20 */ 0, 216, 1177, 702, 702, 702, 702, 702, 702, 702, - /* 30 */ 702, 702, 702, 702, 702, 702, 702, 702, 406, 406, - /* 40 */ 111, 111, 218, 447, 547, 598, 598, 260, 260, 260, - /* 50 */ 260, 40, 112, 320, 340, 445, 489, 593, 637, 741, - /* 60 */ 785, 889, 909, 1023, 1043, 1157, 1177, 1177, 1177, 1177, - /* 70 */ 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, - /* 80 */ 1177, 1177, 1177, 1177, 1197, 1177, 1301, 1321, 1321, 554, - /* 90 */ 1802, 1910, 702, 702, 702, 702, 702, 702, 702, 702, - /* 100 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, - /* 110 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, - /* 120 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, - /* 130 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, - /* 140 */ 702, 702, 138, 198, 198, 198, 198, 198, 198, 198, - /* 150 */ 183, 99, 236, 292, 598, 793, 167, 598, 598, 880, - /* 160 */ 880, 598, 857, 150, 195, 195, 195, 264, 113, 113, - /* 170 */ 2207, 2207, 854, 854, 854, 751, 765, 765, 765, 765, - /* 180 */ 1096, 1096, 725, 292, 882, 904, 598, 598, 598, 598, - /* 190 */ 598, 598, 598, 598, 598, 598, 598, 598, 598, 598, - /* 200 */ 598, 598, 598, 598, 598, 1273, 1032, 1032, 598, 147, - /* 210 */ 1098, 1098, 603, 603, 1276, 1276, 363, 2207, 2207, 2207, - /* 220 */ 2207, 2207, 2207, 2207, 469, 617, 617, 801, 336, 461, - /* 230 */ 804, 864, 615, 891, 913, 598, 598, 598, 598, 598, - /* 240 */ 598, 598, 598, 598, 598, 653, 598, 598, 598, 598, - /* 250 */ 598, 598, 598, 598, 598, 598, 598, 598, 1105, 1105, - /* 260 */ 1105, 598, 598, 598, 1194, 598, 598, 598, 1215, 1249, - /* 270 */ 598, 1353, 598, 598, 598, 598, 598, 598, 598, 598, - /* 280 */ 677, 449, 902, 1338, 1338, 1338, 1338, 1248, 902, 902, - /* 290 */ 326, 1151, 1047, 755, 749, 1371, 960, 1371, 1007, 1162, - /* 300 */ 749, 749, 1162, 749, 960, 1007, 1274, 738, 215, 1300, - /* 310 */ 1300, 1300, 1395, 1395, 1395, 1395, 1368, 1368, 1033, 1414, - /* 320 */ 1387, 1361, 1759, 1759, 1685, 1685, 1792, 1792, 1685, 1683, - /* 330 */ 1686, 1814, 1797, 1825, 1825, 1825, 1825, 1685, 1836, 1707, - /* 340 */ 1686, 1686, 1707, 1814, 1797, 1707, 1797, 1707, 1685, 1836, - /* 350 */ 1710, 1807, 1685, 1836, 1854, 1685, 1836, 1685, 1836, 1854, - /* 360 */ 1769, 1769, 1769, 1822, 1870, 1870, 1854, 1769, 1766, 1769, - /* 370 */ 1822, 1769, 1769, 1729, 1873, 1785, 1785, 1854, 1685, 1823, - /* 380 */ 1823, 1840, 1840, 1778, 1782, 1909, 1685, 1779, 1778, 1789, - /* 390 */ 1800, 1707, 1919, 1939, 1939, 1948, 1948, 1948, 2207, 2207, - /* 400 */ 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, - /* 410 */ 2207, 2207, 2207, 69, 1037, 79, 1088, 651, 1196, 1415, - /* 420 */ 1501, 1439, 1369, 1452, 911, 1211, 1524, 1469, 1551, 1567, - /* 430 */ 1570, 1624, 1640, 1644, 1499, 1440, 1572, 1464, 1597, 275, - /* 440 */ 782, 1586, 1648, 1678, 1553, 1682, 1687, 1388, 1502, 1696, - /* 450 */ 1706, 1588, 1486, 1971, 1975, 1957, 1820, 1972, 1973, 1965, - /* 460 */ 1967, 1851, 1841, 1861, 1969, 1969, 1974, 1852, 1976, 1855, - /* 470 */ 1981, 1998, 1858, 1871, 1969, 1872, 1942, 1968, 1969, 1856, - /* 480 */ 1952, 1953, 1955, 1956, 1881, 1896, 1980, 1874, 2014, 2015, - /* 490 */ 1997, 1905, 1860, 1954, 1999, 1964, 1950, 1994, 1894, 1921, - /* 500 */ 2020, 2018, 2026, 1915, 1923, 2028, 1984, 2036, 2040, 2047, - /* 510 */ 2041, 2003, 2012, 2050, 1979, 2049, 2056, 2011, 2044, 2057, - /* 520 */ 2048, 1934, 2063, 2064, 2065, 2061, 2066, 2068, 1993, 1959, - /* 530 */ 2069, 2071, 1978, 2062, 2075, 1958, 2073, 2070, 2072, 2076, - /* 540 */ 2078, 2010, 2027, 2022, 2074, 2031, 2019, 2081, 2082, 2094, - /* 550 */ 2093, 2095, 2096, 2085, 1983, 1986, 2100, 2073, 2101, 2104, - /* 560 */ 2107, 2109, 2108, 2110, 2111, 2114, 2121, 2115, 2116, 2117, - /* 570 */ 2118, 2122, 2123, 2124, 2007, 2004, 2005, 2006, 2125, 2128, - /* 580 */ 2137, 2138, 2152, + /* 0 */ 2201, 1973, 2215, 1552, 1552, 33, 368, 1668, 1741, 1814, + /* 10 */ 726, 726, 726, 265, 33, 33, 33, 33, 33, 0, + /* 20 */ 0, 216, 1349, 726, 726, 726, 726, 726, 726, 726, + /* 30 */ 726, 726, 726, 726, 726, 726, 726, 726, 272, 272, + /* 40 */ 111, 111, 316, 365, 516, 867, 867, 916, 916, 916, + /* 50 */ 916, 40, 112, 260, 364, 408, 512, 617, 661, 765, + /* 60 */ 809, 913, 957, 1061, 1081, 1195, 1215, 1329, 1349, 1349, + /* 70 */ 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, + /* 80 */ 1349, 1349, 1349, 1349, 1349, 1349, 1369, 1349, 1473, 1493, + /* 90 */ 1493, 473, 1974, 2082, 726, 726, 726, 726, 726, 726, + /* 100 */ 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, + /* 110 */ 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, + /* 120 */ 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, + /* 130 */ 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, + /* 140 */ 726, 726, 726, 726, 726, 726, 138, 232, 232, 232, + /* 150 */ 232, 232, 232, 232, 188, 99, 242, 718, 416, 1159, + /* 160 */ 867, 867, 940, 940, 867, 1103, 417, 574, 574, 574, + /* 170 */ 611, 139, 139, 2379, 2379, 1026, 1026, 1026, 536, 466, + /* 180 */ 466, 466, 466, 1017, 1017, 849, 718, 971, 1060, 867, + /* 190 */ 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, + /* 200 */ 867, 867, 867, 867, 867, 867, 867, 867, 261, 712, + /* 210 */ 712, 867, 108, 1142, 1142, 977, 1108, 1108, 977, 977, + /* 220 */ 1243, 2379, 2379, 2379, 2379, 2379, 2379, 2379, 641, 789, + /* 230 */ 789, 635, 366, 721, 673, 782, 494, 787, 829, 867, + /* 240 */ 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, + /* 250 */ 959, 867, 867, 867, 867, 867, 867, 867, 867, 867, + /* 260 */ 867, 867, 867, 867, 867, 820, 820, 820, 867, 867, + /* 270 */ 867, 1136, 867, 867, 867, 1119, 1007, 867, 1169, 867, + /* 280 */ 867, 867, 867, 867, 867, 867, 867, 1225, 1153, 869, + /* 290 */ 196, 618, 618, 618, 618, 1491, 196, 196, 91, 339, + /* 300 */ 1326, 1386, 383, 1163, 1364, 1426, 1364, 1538, 903, 1163, + /* 310 */ 1163, 903, 1163, 1426, 1538, 1018, 1535, 1241, 1528, 1528, + /* 320 */ 1528, 1394, 1394, 1394, 1394, 762, 762, 1403, 1466, 1475, + /* 330 */ 1551, 1746, 1805, 1746, 1746, 1729, 1729, 1840, 1840, 1729, + /* 340 */ 1730, 1732, 1859, 1842, 1870, 1870, 1870, 1870, 1729, 1876, + /* 350 */ 1751, 1732, 1732, 1751, 1859, 1842, 1751, 1842, 1751, 1729, + /* 360 */ 1876, 1760, 1857, 1729, 1876, 1906, 1729, 1876, 1729, 1876, + /* 370 */ 1906, 1746, 1746, 1746, 1873, 1922, 1922, 1906, 1746, 1822, + /* 380 */ 1746, 1873, 1746, 1746, 1786, 1929, 1843, 1843, 1906, 1729, + /* 390 */ 1872, 1872, 1894, 1894, 1831, 1836, 1966, 1729, 1833, 1831, + /* 400 */ 1851, 1860, 1751, 1983, 1996, 1996, 2009, 2009, 2009, 2379, + /* 410 */ 2379, 2379, 2379, 2379, 2379, 2379, 2379, 2379, 2379, 2379, + /* 420 */ 2379, 2379, 2379, 2379, 136, 1063, 1196, 530, 636, 1274, + /* 430 */ 1300, 1443, 1598, 1495, 1479, 967, 1083, 1602, 463, 1625, + /* 440 */ 1638, 1670, 1541, 1671, 1689, 1696, 1277, 1432, 1693, 808, + /* 450 */ 1700, 1607, 1657, 1587, 1704, 1707, 1631, 1708, 1733, 1608, + /* 460 */ 1611, 1743, 1747, 1620, 1592, 2026, 2030, 2013, 1914, 2018, + /* 470 */ 1916, 2020, 2019, 2021, 1915, 2027, 2029, 2024, 2025, 1909, + /* 480 */ 1899, 1923, 2028, 2028, 1913, 2037, 1917, 2042, 2059, 1918, + /* 490 */ 1932, 2028, 1933, 2003, 2031, 2028, 1919, 2012, 2015, 2016, + /* 500 */ 2022, 1936, 1956, 2040, 2053, 2077, 2074, 2058, 1967, 1924, + /* 510 */ 2034, 2060, 2036, 2008, 2046, 1946, 1978, 2066, 2075, 2078, + /* 520 */ 1968, 1972, 2084, 2041, 2086, 2088, 2076, 2089, 2048, 2054, + /* 530 */ 2093, 2023, 2091, 2099, 2055, 2085, 2101, 2092, 1975, 2105, + /* 540 */ 2110, 2111, 2112, 2115, 2113, 2043, 1997, 2117, 2120, 2032, + /* 550 */ 2114, 2122, 2001, 2121, 2116, 2118, 2119, 2124, 2062, 2071, + /* 560 */ 2068, 2123, 2080, 2065, 2126, 2138, 2140, 2139, 2141, 2143, + /* 570 */ 2130, 2033, 2035, 2142, 2121, 2146, 2147, 2148, 2150, 2149, + /* 580 */ 2152, 2156, 2151, 2164, 2158, 2159, 2161, 2162, 2160, 2165, + /* 590 */ 2163, 2050, 2049, 2051, 2052, 2167, 2172, 2181, 2197, 2204, }; -#define YY_REDUCE_COUNT (412) -#define YY_REDUCE_MIN (-276) -#define YY_REDUCE_MAX (1775) +#define YY_REDUCE_COUNT (423) +#define YY_REDUCE_MIN (-303) +#define YY_REDUCE_MAX (1825) static const short yy_reduce_ofst[] = { - /* 0 */ -66, 217, -63, -177, -180, 161, 364, 64, -183, 162, - /* 10 */ 223, 367, 414, -173, 473, 514, 525, 622, 626, -207, - /* 20 */ 351, -276, -38, 693, 811, 831, 833, 888, -188, 945, - /* 30 */ 947, 416, 558, 951, 867, 287, 1078, 1080, -186, 224, - /* 40 */ -132, 42, 964, 269, 417, 796, 810, -237, -231, -237, - /* 50 */ -231, -45, -45, -45, -45, -45, -45, -45, -45, -45, - /* 60 */ -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - /* 70 */ -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - /* 80 */ -45, -45, -45, -45, -45, -45, -45, -45, -45, 895, - /* 90 */ 925, 967, 980, 1100, 1143, 1169, 1203, 1225, 1228, 1242, - /* 100 */ 1247, 1250, 1253, 1255, 1261, 1267, 1272, 1275, 1283, 1286, - /* 110 */ 1288, 1292, 1333, 1335, 1347, 1349, 1352, 1354, 1360, 1366, - /* 120 */ 1381, 1391, 1406, 1408, 1413, 1416, 1418, 1422, 1425, 1427, - /* 130 */ 1463, 1465, 1472, 1478, 1480, 1491, 1498, 1500, 1517, 1519, - /* 140 */ 1528, 1536, -45, -45, -45, -45, -45, -45, -45, -45, - /* 150 */ -45, -45, -45, 312, -158, 285, -219, 9, 166, 370, - /* 160 */ 545, 707, -45, 930, 601, 963, 1067, 792, -45, -45, - /* 170 */ -45, -45, -204, -204, -204, 369, -171, -129, 632, 678, - /* 180 */ 202, 352, -270, 412, 627, 627, -9, 122, 415, 419, - /* 190 */ -56, 248, 583, 920, 6, 261, 459, 795, 1049, 813, - /* 200 */ 1062, 1082, -161, 778, 1063, 797, 870, 1003, 1128, 443, - /* 210 */ 1031, 1072, 1191, 1192, 957, 1120, 105, 1149, 523, 933, - /* 220 */ 1218, 1238, 1254, 1251, -138, 96, 117, 146, 181, 277, - /* 230 */ 280, 421, 480, 712, 830, 850, 1085, 1099, 1129, 1209, - /* 240 */ 1323, 1331, 1336, 1364, 1407, 368, 1412, 1433, 1438, 1474, - /* 250 */ 1481, 1505, 1506, 1526, 1538, 1544, 1545, 1546, 722, 764, - /* 260 */ 856, 1547, 1548, 1550, 1188, 1554, 1557, 1561, 1298, 1260, - /* 270 */ 1562, 1456, 1564, 280, 1568, 1571, 1573, 1574, 1575, 1576, - /* 280 */ 1457, 1477, 1520, 1514, 1515, 1516, 1518, 1188, 1520, 1520, - /* 290 */ 1530, 1563, 1584, 1482, 1504, 1510, 1534, 1513, 1488, 1537, - /* 300 */ 1512, 1521, 1539, 1522, 1541, 1493, 1583, 1559, 1565, 1585, - /* 310 */ 1587, 1589, 1529, 1531, 1532, 1549, 1558, 1566, 1535, 1577, - /* 320 */ 1582, 1622, 1533, 1540, 1627, 1628, 1552, 1555, 1633, 1560, - /* 330 */ 1578, 1581, 1607, 1606, 1608, 1609, 1611, 1649, 1655, 1612, - /* 340 */ 1590, 1591, 1613, 1594, 1621, 1614, 1623, 1616, 1666, 1668, - /* 350 */ 1579, 1593, 1672, 1675, 1656, 1676, 1679, 1680, 1688, 1660, - /* 360 */ 1667, 1670, 1671, 1663, 1669, 1673, 1674, 1689, 1681, 1692, - /* 370 */ 1677, 1693, 1694, 1592, 1599, 1617, 1620, 1700, 1713, 1596, - /* 380 */ 1598, 1658, 1659, 1691, 1684, 1654, 1735, 1664, 1697, 1690, - /* 390 */ 1701, 1703, 1748, 1758, 1760, 1768, 1770, 1772, 1657, 1661, - /* 400 */ 1665, 1761, 1754, 1757, 1762, 1763, 1764, 1750, 1751, 1765, - /* 410 */ 1771, 1767, 1775, + /* 0 */ -67, 345, -64, -178, -181, 143, 435, -78, -183, 163, + /* 10 */ -185, 284, 384, -174, 189, 352, 440, 444, 493, -23, + /* 20 */ 227, -277, -1, 305, 561, 755, 759, 764, -189, 839, + /* 30 */ 857, 354, 484, 859, 631, 67, 734, 780, -187, 616, + /* 40 */ 581, 730, 891, 449, 588, 795, 836, -238, 287, -238, + /* 50 */ 287, -256, -256, -256, -256, -256, -256, -256, -256, -256, + /* 60 */ -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + /* 70 */ -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + /* 80 */ -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + /* 90 */ -256, 205, 582, 715, 958, 985, 1003, 1005, 1010, 1012, + /* 100 */ 1059, 1066, 1092, 1094, 1097, 1122, 1137, 1141, 1143, 1147, + /* 110 */ 1151, 1172, 1249, 1251, 1269, 1271, 1276, 1290, 1316, 1318, + /* 120 */ 1337, 1371, 1373, 1375, 1400, 1413, 1418, 1420, 1422, 1425, + /* 130 */ 1427, 1433, 1438, 1447, 1454, 1459, 1463, 1467, 1480, 1484, + /* 140 */ 1518, 1523, 1525, 1527, 1529, 1531, -256, -256, -256, -256, + /* 150 */ -256, -256, -256, -256, -256, -256, -256, 155, 210, -220, + /* 160 */ 86, -130, 943, 996, 402, -256, -113, 981, 1095, 1135, + /* 170 */ 395, -256, -256, -256, -256, 568, 568, 568, -4, -153, + /* 180 */ -133, 259, 306, -166, 523, -303, -126, 503, 503, -37, + /* 190 */ -149, 164, 690, 292, 412, 492, 651, 784, 332, 786, + /* 200 */ 841, 1149, 833, 1236, 792, 162, 796, 1253, 777, 288, + /* 210 */ 381, 380, 709, 487, 1027, 972, 1030, 1084, 991, 1120, + /* 220 */ -152, 1062, 692, 1240, 1247, 1250, 1239, 1306, -207, -194, + /* 230 */ 57, 180, 74, 315, 355, 376, 452, 488, 630, 693, + /* 240 */ 965, 1004, 1025, 1099, 1154, 1289, 1305, 1310, 1469, 1489, + /* 250 */ 984, 1494, 1502, 1516, 1544, 1556, 1557, 1562, 1576, 1578, + /* 260 */ 1579, 1583, 1584, 1585, 1586, 1217, 1440, 1554, 1589, 1593, + /* 270 */ 1594, 1530, 1597, 1599, 1600, 1539, 1472, 1601, 1560, 1604, + /* 280 */ 355, 1605, 1609, 1610, 1612, 1613, 1614, 1503, 1512, 1520, + /* 290 */ 1567, 1548, 1558, 1559, 1561, 1530, 1567, 1567, 1569, 1596, + /* 300 */ 1622, 1519, 1521, 1547, 1565, 1581, 1568, 1534, 1582, 1563, + /* 310 */ 1566, 1591, 1570, 1606, 1536, 1619, 1615, 1616, 1624, 1626, + /* 320 */ 1633, 1590, 1595, 1603, 1617, 1618, 1621, 1572, 1623, 1628, + /* 330 */ 1663, 1644, 1577, 1647, 1648, 1673, 1675, 1588, 1627, 1678, + /* 340 */ 1630, 1629, 1634, 1651, 1650, 1652, 1653, 1654, 1688, 1701, + /* 350 */ 1655, 1635, 1636, 1658, 1639, 1672, 1661, 1677, 1666, 1715, + /* 360 */ 1717, 1632, 1642, 1724, 1726, 1712, 1728, 1736, 1737, 1739, + /* 370 */ 1718, 1722, 1723, 1725, 1719, 1720, 1721, 1727, 1731, 1734, + /* 380 */ 1735, 1738, 1740, 1742, 1643, 1656, 1669, 1674, 1753, 1759, + /* 390 */ 1645, 1646, 1711, 1713, 1748, 1744, 1709, 1789, 1716, 1749, + /* 400 */ 1752, 1755, 1758, 1807, 1816, 1818, 1823, 1824, 1825, 1745, + /* 410 */ 1754, 1714, 1811, 1806, 1808, 1809, 1810, 1813, 1802, 1803, + /* 420 */ 1812, 1815, 1817, 1820, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1663, 1663, 1663, 1491, 1254, 1367, 1254, 1254, 1254, 1254, - /* 10 */ 1491, 1491, 1491, 1254, 1254, 1254, 1254, 1254, 1254, 1397, - /* 20 */ 1397, 1544, 1287, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 30 */ 1254, 1254, 1254, 1254, 1254, 1490, 1254, 1254, 1254, 1254, - /* 40 */ 1578, 1578, 1254, 1254, 1254, 1254, 1254, 1563, 1562, 1254, - /* 50 */ 1254, 1254, 1406, 1254, 1413, 1254, 1254, 1254, 1254, 1254, - /* 60 */ 1492, 1493, 1254, 1254, 1254, 1254, 1543, 1545, 1508, 1420, - /* 70 */ 1419, 1418, 1417, 1526, 1385, 1411, 1404, 1408, 1487, 1488, - /* 80 */ 1486, 1641, 1493, 1492, 1254, 1407, 1455, 1471, 1454, 1254, - /* 90 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 100 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 110 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 120 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 130 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 140 */ 1254, 1254, 1463, 1470, 1469, 1468, 1477, 1467, 1464, 1457, - /* 150 */ 1456, 1458, 1459, 1278, 1254, 1275, 1329, 1254, 1254, 1254, - /* 160 */ 1254, 1254, 1460, 1287, 1448, 1447, 1446, 1254, 1474, 1461, - /* 170 */ 1473, 1472, 1551, 1615, 1614, 1509, 1254, 1254, 1254, 1254, - /* 180 */ 1254, 1254, 1578, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 190 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 200 */ 1254, 1254, 1254, 1254, 1254, 1387, 1578, 1578, 1254, 1287, - /* 210 */ 1578, 1578, 1388, 1388, 1283, 1283, 1391, 1558, 1358, 1358, - /* 220 */ 1358, 1358, 1367, 1358, 1254, 1254, 1254, 1254, 1254, 1254, - /* 230 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1548, - /* 240 */ 1546, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 250 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 260 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1363, 1254, - /* 270 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1608, - /* 280 */ 1254, 1521, 1343, 1363, 1363, 1363, 1363, 1365, 1344, 1342, - /* 290 */ 1357, 1288, 1261, 1655, 1423, 1412, 1364, 1412, 1652, 1410, - /* 300 */ 1423, 1423, 1410, 1423, 1364, 1652, 1304, 1630, 1299, 1397, - /* 310 */ 1397, 1397, 1387, 1387, 1387, 1387, 1391, 1391, 1489, 1364, - /* 320 */ 1357, 1254, 1655, 1655, 1373, 1373, 1654, 1654, 1373, 1509, - /* 330 */ 1638, 1432, 1332, 1338, 1338, 1338, 1338, 1373, 1272, 1410, - /* 340 */ 1638, 1638, 1410, 1432, 1332, 1410, 1332, 1410, 1373, 1272, - /* 350 */ 1525, 1649, 1373, 1272, 1499, 1373, 1272, 1373, 1272, 1499, - /* 360 */ 1330, 1330, 1330, 1319, 1254, 1254, 1499, 1330, 1304, 1330, - /* 370 */ 1319, 1330, 1330, 1596, 1254, 1503, 1503, 1499, 1373, 1588, - /* 380 */ 1588, 1400, 1400, 1405, 1391, 1494, 1373, 1254, 1405, 1403, - /* 390 */ 1401, 1410, 1322, 1611, 1611, 1607, 1607, 1607, 1660, 1660, - /* 400 */ 1558, 1623, 1287, 1287, 1287, 1287, 1623, 1306, 1306, 1288, - /* 410 */ 1288, 1287, 1623, 1254, 1254, 1254, 1254, 1254, 1254, 1618, - /* 420 */ 1254, 1553, 1510, 1377, 1254, 1254, 1254, 1254, 1254, 1254, - /* 430 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 440 */ 1564, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 450 */ 1254, 1254, 1437, 1254, 1257, 1555, 1254, 1254, 1254, 1254, - /* 460 */ 1254, 1254, 1254, 1254, 1414, 1415, 1378, 1254, 1254, 1254, - /* 470 */ 1254, 1254, 1254, 1254, 1429, 1254, 1254, 1254, 1424, 1254, - /* 480 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1651, 1254, 1254, - /* 490 */ 1254, 1254, 1254, 1254, 1524, 1523, 1254, 1254, 1375, 1254, - /* 500 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 510 */ 1254, 1254, 1302, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 520 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 530 */ 1254, 1254, 1254, 1254, 1254, 1254, 1402, 1254, 1254, 1254, - /* 540 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 550 */ 1254, 1593, 1392, 1254, 1254, 1254, 1254, 1642, 1254, 1254, - /* 560 */ 1254, 1254, 1352, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 570 */ 1254, 1254, 1254, 1634, 1346, 1438, 1254, 1441, 1276, 1254, - /* 580 */ 1266, 1254, 1254, + /* 0 */ 1691, 1691, 1691, 1516, 1279, 1392, 1279, 1279, 1279, 1279, + /* 10 */ 1516, 1516, 1516, 1279, 1279, 1279, 1279, 1279, 1279, 1422, + /* 20 */ 1422, 1568, 1312, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 30 */ 1279, 1279, 1279, 1279, 1279, 1515, 1279, 1279, 1279, 1279, + /* 40 */ 1607, 1607, 1279, 1279, 1279, 1279, 1279, 1592, 1591, 1279, + /* 50 */ 1279, 1279, 1431, 1279, 1279, 1279, 1438, 1279, 1279, 1279, + /* 60 */ 1279, 1279, 1517, 1518, 1279, 1279, 1279, 1279, 1567, 1569, + /* 70 */ 1533, 1445, 1444, 1443, 1442, 1551, 1410, 1436, 1429, 1433, + /* 80 */ 1512, 1513, 1511, 1670, 1518, 1517, 1279, 1432, 1480, 1496, + /* 90 */ 1479, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 100 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 110 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 120 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 130 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 140 */ 1279, 1279, 1279, 1279, 1279, 1279, 1488, 1495, 1494, 1493, + /* 150 */ 1502, 1492, 1489, 1482, 1481, 1483, 1484, 1303, 1300, 1354, + /* 160 */ 1279, 1279, 1279, 1279, 1279, 1485, 1312, 1473, 1472, 1471, + /* 170 */ 1279, 1499, 1486, 1498, 1497, 1575, 1644, 1643, 1534, 1279, + /* 180 */ 1279, 1279, 1279, 1279, 1279, 1607, 1279, 1279, 1279, 1279, + /* 190 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 200 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1412, 1607, + /* 210 */ 1607, 1279, 1312, 1607, 1607, 1308, 1413, 1413, 1308, 1308, + /* 220 */ 1416, 1587, 1383, 1383, 1383, 1383, 1392, 1383, 1279, 1279, + /* 230 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 240 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1572, 1570, 1279, + /* 250 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 260 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 270 */ 1279, 1279, 1279, 1279, 1279, 1388, 1279, 1279, 1279, 1279, + /* 280 */ 1279, 1279, 1279, 1279, 1279, 1279, 1637, 1683, 1279, 1546, + /* 290 */ 1368, 1388, 1388, 1388, 1388, 1390, 1369, 1367, 1382, 1313, + /* 300 */ 1286, 1683, 1683, 1448, 1437, 1389, 1437, 1680, 1435, 1448, + /* 310 */ 1448, 1435, 1448, 1389, 1680, 1329, 1659, 1324, 1422, 1422, + /* 320 */ 1422, 1412, 1412, 1412, 1412, 1416, 1416, 1514, 1389, 1382, + /* 330 */ 1279, 1355, 1683, 1355, 1355, 1398, 1398, 1682, 1682, 1398, + /* 340 */ 1534, 1667, 1457, 1357, 1363, 1363, 1363, 1363, 1398, 1297, + /* 350 */ 1435, 1667, 1667, 1435, 1457, 1357, 1435, 1357, 1435, 1398, + /* 360 */ 1297, 1550, 1678, 1398, 1297, 1524, 1398, 1297, 1398, 1297, + /* 370 */ 1524, 1355, 1355, 1355, 1344, 1279, 1279, 1524, 1355, 1329, + /* 380 */ 1355, 1344, 1355, 1355, 1625, 1279, 1528, 1528, 1524, 1398, + /* 390 */ 1617, 1617, 1425, 1425, 1430, 1416, 1519, 1398, 1279, 1430, + /* 400 */ 1428, 1426, 1435, 1347, 1640, 1640, 1636, 1636, 1636, 1688, + /* 410 */ 1688, 1587, 1652, 1312, 1312, 1312, 1312, 1652, 1331, 1331, + /* 420 */ 1313, 1313, 1312, 1652, 1279, 1279, 1279, 1279, 1279, 1279, + /* 430 */ 1279, 1647, 1279, 1279, 1535, 1279, 1279, 1279, 1279, 1279, + /* 440 */ 1279, 1279, 1402, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 450 */ 1279, 1279, 1593, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 460 */ 1279, 1279, 1279, 1279, 1462, 1279, 1282, 1584, 1279, 1279, + /* 470 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 480 */ 1279, 1279, 1439, 1440, 1279, 1279, 1279, 1279, 1279, 1279, + /* 490 */ 1279, 1454, 1279, 1279, 1279, 1449, 1279, 1279, 1279, 1279, + /* 500 */ 1279, 1279, 1279, 1279, 1403, 1279, 1279, 1279, 1279, 1279, + /* 510 */ 1279, 1549, 1548, 1279, 1279, 1400, 1279, 1279, 1279, 1279, + /* 520 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1327, + /* 530 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 540 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 550 */ 1279, 1279, 1279, 1427, 1279, 1279, 1279, 1279, 1279, 1279, + /* 560 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1622, 1417, + /* 570 */ 1279, 1279, 1279, 1279, 1671, 1279, 1279, 1279, 1279, 1377, + /* 580 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 590 */ 1663, 1371, 1463, 1279, 1466, 1301, 1279, 1291, 1279, 1279, }; /********** End of lemon-generated parsing tables *****************************/ @@ -175401,6 +181615,7 @@ static const YYCODETYPE yyFallback[] = { 0, /* ERROR => nothing */ 0, /* QNUMBER => nothing */ 0, /* SPACE => nothing */ + 0, /* COMMENT => nothing */ 0, /* ILLEGAL => nothing */ }; #endif /* YYFALLBACK */ @@ -175670,120 +181885,120 @@ static const char *const yyTokenName[] = { /* 182 */ "ERROR", /* 183 */ "QNUMBER", /* 184 */ "SPACE", - /* 185 */ "ILLEGAL", - /* 186 */ "input", - /* 187 */ "cmdlist", - /* 188 */ "ecmd", - /* 189 */ "cmdx", - /* 190 */ "explain", - /* 191 */ "cmd", - /* 192 */ "transtype", - /* 193 */ "trans_opt", - /* 194 */ "nm", - /* 195 */ "savepoint_opt", - /* 196 */ "create_table", - /* 197 */ "create_table_args", - /* 198 */ "createkw", - /* 199 */ "temp", - /* 200 */ "ifnotexists", - /* 201 */ "dbnm", - /* 202 */ "columnlist", - /* 203 */ "conslist_opt", - /* 204 */ "table_option_set", - /* 205 */ "select", - /* 206 */ "table_option", - /* 207 */ "columnname", - /* 208 */ "carglist", - /* 209 */ "typetoken", - /* 210 */ "typename", - /* 211 */ "signed", - /* 212 */ "plus_num", - /* 213 */ "minus_num", - /* 214 */ "scanpt", - /* 215 */ "scantok", - /* 216 */ "ccons", - /* 217 */ "term", - /* 218 */ "expr", - /* 219 */ "onconf", - /* 220 */ "sortorder", - /* 221 */ "autoinc", - /* 222 */ "eidlist_opt", - /* 223 */ "refargs", - /* 224 */ "defer_subclause", - /* 225 */ "generated", - /* 226 */ "refarg", - /* 227 */ "refact", - /* 228 */ "init_deferred_pred_opt", - /* 229 */ "conslist", - /* 230 */ "tconscomma", - /* 231 */ "tcons", - /* 232 */ "sortlist", - /* 233 */ "eidlist", - /* 234 */ "defer_subclause_opt", - /* 235 */ "orconf", - /* 236 */ "resolvetype", - /* 237 */ "raisetype", - /* 238 */ "ifexists", - /* 239 */ "fullname", - /* 240 */ "selectnowith", - /* 241 */ "oneselect", - /* 242 */ "wqlist", - /* 243 */ "multiselect_op", - /* 244 */ "distinct", - /* 245 */ "selcollist", - /* 246 */ "from", - /* 247 */ "where_opt", - /* 248 */ "groupby_opt", - /* 249 */ "having_opt", - /* 250 */ "orderby_opt", - /* 251 */ "limit_opt", - /* 252 */ "window_clause", - /* 253 */ "values", - /* 254 */ "nexprlist", - /* 255 */ "mvalues", - /* 256 */ "sclp", - /* 257 */ "as", - /* 258 */ "seltablist", - /* 259 */ "stl_prefix", - /* 260 */ "joinop", - /* 261 */ "on_using", - /* 262 */ "indexed_by", - /* 263 */ "exprlist", - /* 264 */ "xfullname", - /* 265 */ "idlist", - /* 266 */ "indexed_opt", - /* 267 */ "nulls", - /* 268 */ "with", - /* 269 */ "where_opt_ret", - /* 270 */ "setlist", - /* 271 */ "insert_cmd", - /* 272 */ "idlist_opt", - /* 273 */ "upsert", - /* 274 */ "returning", - /* 275 */ "filter_over", - /* 276 */ "likeop", - /* 277 */ "between_op", - /* 278 */ "in_op", - /* 279 */ "paren_exprlist", - /* 280 */ "case_operand", - /* 281 */ "case_exprlist", - /* 282 */ "case_else", - /* 283 */ "uniqueflag", - /* 284 */ "collate", - /* 285 */ "vinto", - /* 286 */ "nmnum", - /* 287 */ "trigger_decl", - /* 288 */ "trigger_cmd_list", - /* 289 */ "trigger_time", - /* 290 */ "trigger_event", - /* 291 */ "foreach_clause", - /* 292 */ "when_clause", - /* 293 */ "trigger_cmd", - /* 294 */ "trnm", + /* 185 */ "COMMENT", + /* 186 */ "ILLEGAL", + /* 187 */ "input", + /* 188 */ "cmdlist", + /* 189 */ "ecmd", + /* 190 */ "cmdx", + /* 191 */ "explain", + /* 192 */ "cmd", + /* 193 */ "transtype", + /* 194 */ "trans_opt", + /* 195 */ "nm", + /* 196 */ "savepoint_opt", + /* 197 */ "create_table", + /* 198 */ "create_table_args", + /* 199 */ "createkw", + /* 200 */ "temp", + /* 201 */ "ifnotexists", + /* 202 */ "dbnm", + /* 203 */ "columnlist", + /* 204 */ "conslist_opt", + /* 205 */ "table_option_set", + /* 206 */ "select", + /* 207 */ "table_option", + /* 208 */ "columnname", + /* 209 */ "carglist", + /* 210 */ "typetoken", + /* 211 */ "typename", + /* 212 */ "signed", + /* 213 */ "plus_num", + /* 214 */ "minus_num", + /* 215 */ "scanpt", + /* 216 */ "scantok", + /* 217 */ "ccons", + /* 218 */ "term", + /* 219 */ "expr", + /* 220 */ "onconf", + /* 221 */ "sortorder", + /* 222 */ "autoinc", + /* 223 */ "eidlist_opt", + /* 224 */ "refargs", + /* 225 */ "defer_subclause", + /* 226 */ "generated", + /* 227 */ "refarg", + /* 228 */ "refact", + /* 229 */ "init_deferred_pred_opt", + /* 230 */ "conslist", + /* 231 */ "tconscomma", + /* 232 */ "tcons", + /* 233 */ "sortlist", + /* 234 */ "eidlist", + /* 235 */ "defer_subclause_opt", + /* 236 */ "orconf", + /* 237 */ "resolvetype", + /* 238 */ "raisetype", + /* 239 */ "ifexists", + /* 240 */ "fullname", + /* 241 */ "selectnowith", + /* 242 */ "oneselect", + /* 243 */ "wqlist", + /* 244 */ "multiselect_op", + /* 245 */ "distinct", + /* 246 */ "selcollist", + /* 247 */ "from", + /* 248 */ "where_opt", + /* 249 */ "groupby_opt", + /* 250 */ "having_opt", + /* 251 */ "orderby_opt", + /* 252 */ "limit_opt", + /* 253 */ "window_clause", + /* 254 */ "values", + /* 255 */ "nexprlist", + /* 256 */ "mvalues", + /* 257 */ "sclp", + /* 258 */ "as", + /* 259 */ "seltablist", + /* 260 */ "stl_prefix", + /* 261 */ "joinop", + /* 262 */ "on_using", + /* 263 */ "indexed_by", + /* 264 */ "exprlist", + /* 265 */ "xfullname", + /* 266 */ "idlist", + /* 267 */ "indexed_opt", + /* 268 */ "nulls", + /* 269 */ "with", + /* 270 */ "where_opt_ret", + /* 271 */ "setlist", + /* 272 */ "insert_cmd", + /* 273 */ "idlist_opt", + /* 274 */ "upsert", + /* 275 */ "returning", + /* 276 */ "filter_over", + /* 277 */ "likeop", + /* 278 */ "between_op", + /* 279 */ "in_op", + /* 280 */ "paren_exprlist", + /* 281 */ "case_operand", + /* 282 */ "case_exprlist", + /* 283 */ "case_else", + /* 284 */ "uniqueflag", + /* 285 */ "collate", + /* 286 */ "vinto", + /* 287 */ "nmnum", + /* 288 */ "trigger_decl", + /* 289 */ "trigger_cmd_list", + /* 290 */ "trigger_time", + /* 291 */ "trigger_event", + /* 292 */ "foreach_clause", + /* 293 */ "when_clause", + /* 294 */ "trigger_cmd", /* 295 */ "tridxby", /* 296 */ "database_kw_opt", /* 297 */ "key_opt", - /* 298 */ "add_column_fullname", + /* 298 */ "alter_add", /* 299 */ "kwcolumn_opt", /* 300 */ "create_vtab", /* 301 */ "vtabarglist", @@ -175936,8 +182151,8 @@ static const char *const yyRuleName[] = { /* 119 */ "fullname ::= nm DOT nm", /* 120 */ "xfullname ::= nm", /* 121 */ "xfullname ::= nm DOT nm", - /* 122 */ "xfullname ::= nm DOT nm AS nm", - /* 123 */ "xfullname ::= nm AS nm", + /* 122 */ "xfullname ::= nm AS nm", + /* 123 */ "xfullname ::= nm DOT nm AS nm", /* 124 */ "joinop ::= COMMA|JOIN", /* 125 */ "joinop ::= JOIN_KW JOIN", /* 126 */ "joinop ::= JOIN_KW nm JOIN", @@ -176086,143 +182301,146 @@ static const char *const yyRuleName[] = { /* 269 */ "when_clause ::= WHEN expr", /* 270 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", /* 271 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 272 */ "trnm ::= nm DOT nm", - /* 273 */ "tridxby ::= INDEXED BY nm", - /* 274 */ "tridxby ::= NOT INDEXED", - /* 275 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", - /* 276 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", - /* 277 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", - /* 278 */ "trigger_cmd ::= scanpt select scanpt", - /* 279 */ "expr ::= RAISE LP IGNORE RP", - /* 280 */ "expr ::= RAISE LP raisetype COMMA expr RP", - /* 281 */ "raisetype ::= ROLLBACK", - /* 282 */ "raisetype ::= ABORT", - /* 283 */ "raisetype ::= FAIL", - /* 284 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 285 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 286 */ "cmd ::= DETACH database_kw_opt expr", - /* 287 */ "key_opt ::=", - /* 288 */ "key_opt ::= KEY expr", - /* 289 */ "cmd ::= REINDEX", - /* 290 */ "cmd ::= REINDEX nm dbnm", - /* 291 */ "cmd ::= ANALYZE", - /* 292 */ "cmd ::= ANALYZE nm dbnm", - /* 293 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 294 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 272 */ "tridxby ::= INDEXED BY nm", + /* 273 */ "tridxby ::= NOT INDEXED", + /* 274 */ "trigger_cmd ::= UPDATE orconf xfullname tridxby SET setlist from where_opt scanpt", + /* 275 */ "trigger_cmd ::= scanpt insert_cmd INTO xfullname idlist_opt select upsert scanpt", + /* 276 */ "trigger_cmd ::= DELETE FROM xfullname tridxby where_opt scanpt", + /* 277 */ "trigger_cmd ::= scanpt select scanpt", + /* 278 */ "expr ::= RAISE LP IGNORE RP", + /* 279 */ "expr ::= RAISE LP raisetype COMMA expr RP", + /* 280 */ "raisetype ::= ROLLBACK", + /* 281 */ "raisetype ::= ABORT", + /* 282 */ "raisetype ::= FAIL", + /* 283 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 284 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 285 */ "cmd ::= DETACH database_kw_opt expr", + /* 286 */ "key_opt ::=", + /* 287 */ "key_opt ::= KEY expr", + /* 288 */ "cmd ::= REINDEX", + /* 289 */ "cmd ::= REINDEX nm dbnm", + /* 290 */ "cmd ::= ANALYZE", + /* 291 */ "cmd ::= ANALYZE nm dbnm", + /* 292 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 293 */ "cmd ::= alter_add carglist", + /* 294 */ "alter_add ::= ALTER TABLE fullname ADD kwcolumn_opt nm typetoken", /* 295 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", - /* 296 */ "add_column_fullname ::= fullname", - /* 297 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", - /* 298 */ "cmd ::= create_vtab", - /* 299 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 300 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 301 */ "vtabarg ::=", - /* 302 */ "vtabargtoken ::= ANY", - /* 303 */ "vtabargtoken ::= lp anylist RP", - /* 304 */ "lp ::= LP", - /* 305 */ "with ::= WITH wqlist", - /* 306 */ "with ::= WITH RECURSIVE wqlist", - /* 307 */ "wqas ::= AS", - /* 308 */ "wqas ::= AS MATERIALIZED", - /* 309 */ "wqas ::= AS NOT MATERIALIZED", - /* 310 */ "wqitem ::= withnm eidlist_opt wqas LP select RP", - /* 311 */ "withnm ::= nm", - /* 312 */ "wqlist ::= wqitem", - /* 313 */ "wqlist ::= wqlist COMMA wqitem", - /* 314 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", - /* 315 */ "windowdefn ::= nm AS LP window RP", - /* 316 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", - /* 317 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", - /* 318 */ "window ::= ORDER BY sortlist frame_opt", - /* 319 */ "window ::= nm ORDER BY sortlist frame_opt", - /* 320 */ "window ::= nm frame_opt", - /* 321 */ "frame_opt ::=", - /* 322 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", - /* 323 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", - /* 324 */ "range_or_rows ::= RANGE|ROWS|GROUPS", - /* 325 */ "frame_bound_s ::= frame_bound", - /* 326 */ "frame_bound_s ::= UNBOUNDED PRECEDING", - /* 327 */ "frame_bound_e ::= frame_bound", - /* 328 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", - /* 329 */ "frame_bound ::= expr PRECEDING|FOLLOWING", - /* 330 */ "frame_bound ::= CURRENT ROW", - /* 331 */ "frame_exclude_opt ::=", - /* 332 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", - /* 333 */ "frame_exclude ::= NO OTHERS", - /* 334 */ "frame_exclude ::= CURRENT ROW", - /* 335 */ "frame_exclude ::= GROUP|TIES", - /* 336 */ "window_clause ::= WINDOW windowdefn_list", - /* 337 */ "filter_over ::= filter_clause over_clause", - /* 338 */ "filter_over ::= over_clause", - /* 339 */ "filter_over ::= filter_clause", - /* 340 */ "over_clause ::= OVER LP window RP", - /* 341 */ "over_clause ::= OVER nm", - /* 342 */ "filter_clause ::= FILTER LP WHERE expr RP", - /* 343 */ "term ::= QNUMBER", - /* 344 */ "input ::= cmdlist", - /* 345 */ "cmdlist ::= cmdlist ecmd", - /* 346 */ "cmdlist ::= ecmd", - /* 347 */ "ecmd ::= SEMI", - /* 348 */ "ecmd ::= cmdx SEMI", - /* 349 */ "ecmd ::= explain cmdx SEMI", - /* 350 */ "trans_opt ::=", - /* 351 */ "trans_opt ::= TRANSACTION", - /* 352 */ "trans_opt ::= TRANSACTION nm", - /* 353 */ "savepoint_opt ::= SAVEPOINT", - /* 354 */ "savepoint_opt ::=", - /* 355 */ "cmd ::= create_table create_table_args", - /* 356 */ "table_option_set ::= table_option", - /* 357 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 358 */ "columnlist ::= columnname carglist", - /* 359 */ "nm ::= ID|INDEXED|JOIN_KW", - /* 360 */ "nm ::= STRING", - /* 361 */ "typetoken ::= typename", - /* 362 */ "typename ::= ID|STRING", - /* 363 */ "signed ::= plus_num", - /* 364 */ "signed ::= minus_num", - /* 365 */ "carglist ::= carglist ccons", - /* 366 */ "carglist ::=", - /* 367 */ "ccons ::= NULL onconf", - /* 368 */ "ccons ::= GENERATED ALWAYS AS generated", - /* 369 */ "ccons ::= AS generated", - /* 370 */ "conslist_opt ::= COMMA conslist", - /* 371 */ "conslist ::= conslist tconscomma tcons", - /* 372 */ "conslist ::= tcons", - /* 373 */ "tconscomma ::=", - /* 374 */ "defer_subclause_opt ::= defer_subclause", - /* 375 */ "resolvetype ::= raisetype", - /* 376 */ "selectnowith ::= oneselect", - /* 377 */ "oneselect ::= values", - /* 378 */ "sclp ::= selcollist COMMA", - /* 379 */ "as ::= ID|STRING", - /* 380 */ "indexed_opt ::= indexed_by", - /* 381 */ "returning ::=", - /* 382 */ "expr ::= term", - /* 383 */ "likeop ::= LIKE_KW|MATCH", - /* 384 */ "case_operand ::= expr", - /* 385 */ "exprlist ::= nexprlist", - /* 386 */ "nmnum ::= plus_num", - /* 387 */ "nmnum ::= nm", - /* 388 */ "nmnum ::= ON", - /* 389 */ "nmnum ::= DELETE", - /* 390 */ "nmnum ::= DEFAULT", - /* 391 */ "plus_num ::= INTEGER|FLOAT", - /* 392 */ "foreach_clause ::=", - /* 393 */ "foreach_clause ::= FOR EACH ROW", - /* 394 */ "trnm ::= nm", - /* 395 */ "tridxby ::=", - /* 396 */ "database_kw_opt ::= DATABASE", - /* 397 */ "database_kw_opt ::=", - /* 398 */ "kwcolumn_opt ::=", - /* 399 */ "kwcolumn_opt ::= COLUMNKW", - /* 400 */ "vtabarglist ::= vtabarg", - /* 401 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 402 */ "vtabarg ::= vtabarg vtabargtoken", - /* 403 */ "anylist ::=", - /* 404 */ "anylist ::= anylist LP anylist RP", - /* 405 */ "anylist ::= anylist ANY", - /* 406 */ "with ::=", - /* 407 */ "windowdefn_list ::= windowdefn", - /* 408 */ "window ::= frame_opt", + /* 296 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", + /* 297 */ "cmd ::= ALTER TABLE fullname DROP CONSTRAINT nm", + /* 298 */ "cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm DROP NOT NULL", + /* 299 */ "cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm SET NOT NULL onconf", + /* 300 */ "cmd ::= ALTER TABLE fullname ADD CONSTRAINT nm CHECK LP expr RP onconf", + /* 301 */ "cmd ::= ALTER TABLE fullname ADD CHECK LP expr RP onconf", + /* 302 */ "cmd ::= create_vtab", + /* 303 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 304 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 305 */ "vtabarg ::=", + /* 306 */ "vtabargtoken ::= ANY", + /* 307 */ "vtabargtoken ::= lp anylist RP", + /* 308 */ "lp ::= LP", + /* 309 */ "with ::= WITH wqlist", + /* 310 */ "with ::= WITH RECURSIVE wqlist", + /* 311 */ "wqas ::= AS", + /* 312 */ "wqas ::= AS MATERIALIZED", + /* 313 */ "wqas ::= AS NOT MATERIALIZED", + /* 314 */ "wqitem ::= withnm eidlist_opt wqas LP select RP", + /* 315 */ "withnm ::= nm", + /* 316 */ "wqlist ::= wqitem", + /* 317 */ "wqlist ::= wqlist COMMA wqitem", + /* 318 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", + /* 319 */ "windowdefn ::= nm AS LP window RP", + /* 320 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", + /* 321 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", + /* 322 */ "window ::= ORDER BY sortlist frame_opt", + /* 323 */ "window ::= nm ORDER BY sortlist frame_opt", + /* 324 */ "window ::= nm frame_opt", + /* 325 */ "frame_opt ::=", + /* 326 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", + /* 327 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", + /* 328 */ "range_or_rows ::= RANGE|ROWS|GROUPS", + /* 329 */ "frame_bound_s ::= frame_bound", + /* 330 */ "frame_bound_s ::= UNBOUNDED PRECEDING", + /* 331 */ "frame_bound_e ::= frame_bound", + /* 332 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", + /* 333 */ "frame_bound ::= expr PRECEDING|FOLLOWING", + /* 334 */ "frame_bound ::= CURRENT ROW", + /* 335 */ "frame_exclude_opt ::=", + /* 336 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", + /* 337 */ "frame_exclude ::= NO OTHERS", + /* 338 */ "frame_exclude ::= CURRENT ROW", + /* 339 */ "frame_exclude ::= GROUP|TIES", + /* 340 */ "window_clause ::= WINDOW windowdefn_list", + /* 341 */ "filter_over ::= filter_clause over_clause", + /* 342 */ "filter_over ::= over_clause", + /* 343 */ "filter_over ::= filter_clause", + /* 344 */ "over_clause ::= OVER LP window RP", + /* 345 */ "over_clause ::= OVER nm", + /* 346 */ "filter_clause ::= FILTER LP WHERE expr RP", + /* 347 */ "term ::= QNUMBER", + /* 348 */ "input ::= cmdlist", + /* 349 */ "cmdlist ::= cmdlist ecmd", + /* 350 */ "cmdlist ::= ecmd", + /* 351 */ "ecmd ::= SEMI", + /* 352 */ "ecmd ::= cmdx SEMI", + /* 353 */ "ecmd ::= explain cmdx SEMI", + /* 354 */ "trans_opt ::=", + /* 355 */ "trans_opt ::= TRANSACTION", + /* 356 */ "trans_opt ::= TRANSACTION nm", + /* 357 */ "savepoint_opt ::= SAVEPOINT", + /* 358 */ "savepoint_opt ::=", + /* 359 */ "cmd ::= create_table create_table_args", + /* 360 */ "table_option_set ::= table_option", + /* 361 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 362 */ "columnlist ::= columnname carglist", + /* 363 */ "nm ::= ID|INDEXED|JOIN_KW", + /* 364 */ "nm ::= STRING", + /* 365 */ "typetoken ::= typename", + /* 366 */ "typename ::= ID|STRING", + /* 367 */ "signed ::= plus_num", + /* 368 */ "signed ::= minus_num", + /* 369 */ "carglist ::= carglist ccons", + /* 370 */ "carglist ::=", + /* 371 */ "ccons ::= NULL onconf", + /* 372 */ "ccons ::= GENERATED ALWAYS AS generated", + /* 373 */ "ccons ::= AS generated", + /* 374 */ "conslist_opt ::= COMMA conslist", + /* 375 */ "conslist ::= conslist tconscomma tcons", + /* 376 */ "conslist ::= tcons", + /* 377 */ "tconscomma ::=", + /* 378 */ "defer_subclause_opt ::= defer_subclause", + /* 379 */ "resolvetype ::= raisetype", + /* 380 */ "selectnowith ::= oneselect", + /* 381 */ "oneselect ::= values", + /* 382 */ "sclp ::= selcollist COMMA", + /* 383 */ "as ::= ID|STRING", + /* 384 */ "indexed_opt ::= indexed_by", + /* 385 */ "returning ::=", + /* 386 */ "expr ::= term", + /* 387 */ "likeop ::= LIKE_KW|MATCH", + /* 388 */ "case_operand ::= expr", + /* 389 */ "exprlist ::= nexprlist", + /* 390 */ "nmnum ::= plus_num", + /* 391 */ "nmnum ::= nm", + /* 392 */ "nmnum ::= ON", + /* 393 */ "nmnum ::= DELETE", + /* 394 */ "nmnum ::= DEFAULT", + /* 395 */ "plus_num ::= INTEGER|FLOAT", + /* 396 */ "foreach_clause ::=", + /* 397 */ "foreach_clause ::= FOR EACH ROW", + /* 398 */ "tridxby ::=", + /* 399 */ "database_kw_opt ::= DATABASE", + /* 400 */ "database_kw_opt ::=", + /* 401 */ "kwcolumn_opt ::=", + /* 402 */ "kwcolumn_opt ::= COLUMNKW", + /* 403 */ "vtabarglist ::= vtabarg", + /* 404 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 405 */ "vtabarg ::= vtabarg vtabargtoken", + /* 406 */ "anylist ::=", + /* 407 */ "anylist ::= anylist LP anylist RP", + /* 408 */ "anylist ::= anylist ANY", + /* 409 */ "with ::=", + /* 410 */ "windowdefn_list ::= windowdefn", + /* 411 */ "window ::= frame_opt", }; #endif /* NDEBUG */ @@ -176237,15 +182455,24 @@ static int yyGrowStack(yyParser *p){ int newSize; int idx; yyStackEntry *pNew; +#ifdef YYSIZELIMIT + int nLimit = YYSIZELIMIT(sqlite3ParserCTX(p)); +#endif newSize = oldSize*2 + 100; +#ifdef YYSIZELIMIT + if( newSize>nLimit ){ + newSize = nLimit; + if( newSize<=oldSize ) return 1; + } +#endif idx = (int)(p->yytos - p->yystack); if( p->yystack==p->yystk0 ){ - pNew = YYREALLOC(0, newSize*sizeof(pNew[0])); + pNew = YYREALLOC(0, newSize*sizeof(pNew[0]), sqlite3ParserCTX(p)); if( pNew==0 ) return 1; memcpy(pNew, p->yystack, oldSize*sizeof(pNew[0])); }else{ - pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0])); + pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0]), sqlite3ParserCTX(p)); if( pNew==0 ) return 1; } p->yystack = pNew; @@ -176346,74 +182573,74 @@ static void yy_destructor( ** inside the C code. */ /********* Begin destructor definitions ***************************************/ - case 205: /* select */ - case 240: /* selectnowith */ - case 241: /* oneselect */ - case 253: /* values */ - case 255: /* mvalues */ + case 206: /* select */ + case 241: /* selectnowith */ + case 242: /* oneselect */ + case 254: /* values */ + case 256: /* mvalues */ { sqlite3SelectDelete(pParse->db, (yypminor->yy555)); } break; - case 217: /* term */ - case 218: /* expr */ - case 247: /* where_opt */ - case 249: /* having_opt */ - case 269: /* where_opt_ret */ - case 280: /* case_operand */ - case 282: /* case_else */ - case 285: /* vinto */ - case 292: /* when_clause */ + case 218: /* term */ + case 219: /* expr */ + case 248: /* where_opt */ + case 250: /* having_opt */ + case 270: /* where_opt_ret */ + case 281: /* case_operand */ + case 283: /* case_else */ + case 286: /* vinto */ + case 293: /* when_clause */ case 297: /* key_opt */ case 314: /* filter_clause */ { sqlite3ExprDelete(pParse->db, (yypminor->yy454)); } break; - case 222: /* eidlist_opt */ - case 232: /* sortlist */ - case 233: /* eidlist */ - case 245: /* selcollist */ - case 248: /* groupby_opt */ - case 250: /* orderby_opt */ - case 254: /* nexprlist */ - case 256: /* sclp */ - case 263: /* exprlist */ - case 270: /* setlist */ - case 279: /* paren_exprlist */ - case 281: /* case_exprlist */ + case 223: /* eidlist_opt */ + case 233: /* sortlist */ + case 234: /* eidlist */ + case 246: /* selcollist */ + case 249: /* groupby_opt */ + case 251: /* orderby_opt */ + case 255: /* nexprlist */ + case 257: /* sclp */ + case 264: /* exprlist */ + case 271: /* setlist */ + case 280: /* paren_exprlist */ + case 282: /* case_exprlist */ case 313: /* part_opt */ { sqlite3ExprListDelete(pParse->db, (yypminor->yy14)); } break; - case 239: /* fullname */ - case 246: /* from */ - case 258: /* seltablist */ - case 259: /* stl_prefix */ - case 264: /* xfullname */ + case 240: /* fullname */ + case 247: /* from */ + case 259: /* seltablist */ + case 260: /* stl_prefix */ + case 265: /* xfullname */ { sqlite3SrcListDelete(pParse->db, (yypminor->yy203)); } break; - case 242: /* wqlist */ + case 243: /* wqlist */ { sqlite3WithDelete(pParse->db, (yypminor->yy59)); } break; - case 252: /* window_clause */ + case 253: /* window_clause */ case 309: /* windowdefn_list */ { sqlite3WindowListDelete(pParse->db, (yypminor->yy211)); } break; - case 265: /* idlist */ - case 272: /* idlist_opt */ + case 266: /* idlist */ + case 273: /* idlist_opt */ { sqlite3IdListDelete(pParse->db, (yypminor->yy132)); } break; - case 275: /* filter_over */ + case 276: /* filter_over */ case 310: /* windowdefn */ case 311: /* window */ case 312: /* frame_opt */ @@ -176422,13 +182649,13 @@ sqlite3IdListDelete(pParse->db, (yypminor->yy132)); sqlite3WindowDelete(pParse->db, (yypminor->yy211)); } break; - case 288: /* trigger_cmd_list */ - case 293: /* trigger_cmd */ + case 289: /* trigger_cmd_list */ + case 294: /* trigger_cmd */ { sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy427)); } break; - case 290: /* trigger_event */ + case 291: /* trigger_event */ { sqlite3IdListDelete(pParse->db, (yypminor->yy286).b); } @@ -176490,7 +182717,9 @@ SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){ } #if YYGROWABLESTACK - if( pParser->yystack!=pParser->yystk0 ) YYFREE(pParser->yystack); + if( pParser->yystack!=pParser->yystk0 ){ + YYFREE(pParser->yystack, sqlite3ParserCTX(pParser)); + } #endif } @@ -176673,7 +182902,7 @@ static void yyStackOverflow(yyParser *yypParser){ ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ - sqlite3OomFault(pParse->db); + if( pParse->nErr==0 ) sqlite3ErrorMsg(pParse, "Recursion limit"); /******** End %stack_overflow code ********************************************/ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument var */ sqlite3ParserCTX_STORE @@ -176739,415 +182968,418 @@ static void yy_shift( /* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side ** of that rule */ static const YYCODETYPE yyRuleInfoLhs[] = { - 190, /* (0) explain ::= EXPLAIN */ - 190, /* (1) explain ::= EXPLAIN QUERY PLAN */ - 189, /* (2) cmdx ::= cmd */ - 191, /* (3) cmd ::= BEGIN transtype trans_opt */ - 192, /* (4) transtype ::= */ - 192, /* (5) transtype ::= DEFERRED */ - 192, /* (6) transtype ::= IMMEDIATE */ - 192, /* (7) transtype ::= EXCLUSIVE */ - 191, /* (8) cmd ::= COMMIT|END trans_opt */ - 191, /* (9) cmd ::= ROLLBACK trans_opt */ - 191, /* (10) cmd ::= SAVEPOINT nm */ - 191, /* (11) cmd ::= RELEASE savepoint_opt nm */ - 191, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ - 196, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ - 198, /* (14) createkw ::= CREATE */ - 200, /* (15) ifnotexists ::= */ - 200, /* (16) ifnotexists ::= IF NOT EXISTS */ - 199, /* (17) temp ::= TEMP */ - 199, /* (18) temp ::= */ - 197, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ - 197, /* (20) create_table_args ::= AS select */ - 204, /* (21) table_option_set ::= */ - 204, /* (22) table_option_set ::= table_option_set COMMA table_option */ - 206, /* (23) table_option ::= WITHOUT nm */ - 206, /* (24) table_option ::= nm */ - 207, /* (25) columnname ::= nm typetoken */ - 209, /* (26) typetoken ::= */ - 209, /* (27) typetoken ::= typename LP signed RP */ - 209, /* (28) typetoken ::= typename LP signed COMMA signed RP */ - 210, /* (29) typename ::= typename ID|STRING */ - 214, /* (30) scanpt ::= */ - 215, /* (31) scantok ::= */ - 216, /* (32) ccons ::= CONSTRAINT nm */ - 216, /* (33) ccons ::= DEFAULT scantok term */ - 216, /* (34) ccons ::= DEFAULT LP expr RP */ - 216, /* (35) ccons ::= DEFAULT PLUS scantok term */ - 216, /* (36) ccons ::= DEFAULT MINUS scantok term */ - 216, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ - 216, /* (38) ccons ::= NOT NULL onconf */ - 216, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ - 216, /* (40) ccons ::= UNIQUE onconf */ - 216, /* (41) ccons ::= CHECK LP expr RP */ - 216, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ - 216, /* (43) ccons ::= defer_subclause */ - 216, /* (44) ccons ::= COLLATE ID|STRING */ - 225, /* (45) generated ::= LP expr RP */ - 225, /* (46) generated ::= LP expr RP ID */ - 221, /* (47) autoinc ::= */ - 221, /* (48) autoinc ::= AUTOINCR */ - 223, /* (49) refargs ::= */ - 223, /* (50) refargs ::= refargs refarg */ - 226, /* (51) refarg ::= MATCH nm */ - 226, /* (52) refarg ::= ON INSERT refact */ - 226, /* (53) refarg ::= ON DELETE refact */ - 226, /* (54) refarg ::= ON UPDATE refact */ - 227, /* (55) refact ::= SET NULL */ - 227, /* (56) refact ::= SET DEFAULT */ - 227, /* (57) refact ::= CASCADE */ - 227, /* (58) refact ::= RESTRICT */ - 227, /* (59) refact ::= NO ACTION */ - 224, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ - 224, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - 228, /* (62) init_deferred_pred_opt ::= */ - 228, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ - 228, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ - 203, /* (65) conslist_opt ::= */ - 230, /* (66) tconscomma ::= COMMA */ - 231, /* (67) tcons ::= CONSTRAINT nm */ - 231, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ - 231, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ - 231, /* (70) tcons ::= CHECK LP expr RP onconf */ - 231, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ - 234, /* (72) defer_subclause_opt ::= */ - 219, /* (73) onconf ::= */ - 219, /* (74) onconf ::= ON CONFLICT resolvetype */ - 235, /* (75) orconf ::= */ - 235, /* (76) orconf ::= OR resolvetype */ - 236, /* (77) resolvetype ::= IGNORE */ - 236, /* (78) resolvetype ::= REPLACE */ - 191, /* (79) cmd ::= DROP TABLE ifexists fullname */ - 238, /* (80) ifexists ::= IF EXISTS */ - 238, /* (81) ifexists ::= */ - 191, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ - 191, /* (83) cmd ::= DROP VIEW ifexists fullname */ - 191, /* (84) cmd ::= select */ - 205, /* (85) select ::= WITH wqlist selectnowith */ - 205, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ - 205, /* (87) select ::= selectnowith */ - 240, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ - 243, /* (89) multiselect_op ::= UNION */ - 243, /* (90) multiselect_op ::= UNION ALL */ - 243, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ - 241, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ - 241, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ - 253, /* (94) values ::= VALUES LP nexprlist RP */ - 241, /* (95) oneselect ::= mvalues */ - 255, /* (96) mvalues ::= values COMMA LP nexprlist RP */ - 255, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */ - 244, /* (98) distinct ::= DISTINCT */ - 244, /* (99) distinct ::= ALL */ - 244, /* (100) distinct ::= */ - 256, /* (101) sclp ::= */ - 245, /* (102) selcollist ::= sclp scanpt expr scanpt as */ - 245, /* (103) selcollist ::= sclp scanpt STAR */ - 245, /* (104) selcollist ::= sclp scanpt nm DOT STAR */ - 257, /* (105) as ::= AS nm */ - 257, /* (106) as ::= */ - 246, /* (107) from ::= */ - 246, /* (108) from ::= FROM seltablist */ - 259, /* (109) stl_prefix ::= seltablist joinop */ - 259, /* (110) stl_prefix ::= */ - 258, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */ - 258, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ - 258, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ - 258, /* (114) seltablist ::= stl_prefix LP select RP as on_using */ - 258, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */ - 201, /* (116) dbnm ::= */ - 201, /* (117) dbnm ::= DOT nm */ - 239, /* (118) fullname ::= nm */ - 239, /* (119) fullname ::= nm DOT nm */ - 264, /* (120) xfullname ::= nm */ - 264, /* (121) xfullname ::= nm DOT nm */ - 264, /* (122) xfullname ::= nm DOT nm AS nm */ - 264, /* (123) xfullname ::= nm AS nm */ - 260, /* (124) joinop ::= COMMA|JOIN */ - 260, /* (125) joinop ::= JOIN_KW JOIN */ - 260, /* (126) joinop ::= JOIN_KW nm JOIN */ - 260, /* (127) joinop ::= JOIN_KW nm nm JOIN */ - 261, /* (128) on_using ::= ON expr */ - 261, /* (129) on_using ::= USING LP idlist RP */ - 261, /* (130) on_using ::= */ - 266, /* (131) indexed_opt ::= */ - 262, /* (132) indexed_by ::= INDEXED BY nm */ - 262, /* (133) indexed_by ::= NOT INDEXED */ - 250, /* (134) orderby_opt ::= */ - 250, /* (135) orderby_opt ::= ORDER BY sortlist */ - 232, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */ - 232, /* (137) sortlist ::= expr sortorder nulls */ - 220, /* (138) sortorder ::= ASC */ - 220, /* (139) sortorder ::= DESC */ - 220, /* (140) sortorder ::= */ - 267, /* (141) nulls ::= NULLS FIRST */ - 267, /* (142) nulls ::= NULLS LAST */ - 267, /* (143) nulls ::= */ - 248, /* (144) groupby_opt ::= */ - 248, /* (145) groupby_opt ::= GROUP BY nexprlist */ - 249, /* (146) having_opt ::= */ - 249, /* (147) having_opt ::= HAVING expr */ - 251, /* (148) limit_opt ::= */ - 251, /* (149) limit_opt ::= LIMIT expr */ - 251, /* (150) limit_opt ::= LIMIT expr OFFSET expr */ - 251, /* (151) limit_opt ::= LIMIT expr COMMA expr */ - 191, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ - 247, /* (153) where_opt ::= */ - 247, /* (154) where_opt ::= WHERE expr */ - 269, /* (155) where_opt_ret ::= */ - 269, /* (156) where_opt_ret ::= WHERE expr */ - 269, /* (157) where_opt_ret ::= RETURNING selcollist */ - 269, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */ - 191, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ - 270, /* (160) setlist ::= setlist COMMA nm EQ expr */ - 270, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */ - 270, /* (162) setlist ::= nm EQ expr */ - 270, /* (163) setlist ::= LP idlist RP EQ expr */ - 191, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ - 191, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ - 273, /* (166) upsert ::= */ - 273, /* (167) upsert ::= RETURNING selcollist */ - 273, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ - 273, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ - 273, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */ - 273, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ - 274, /* (172) returning ::= RETURNING selcollist */ - 271, /* (173) insert_cmd ::= INSERT orconf */ - 271, /* (174) insert_cmd ::= REPLACE */ - 272, /* (175) idlist_opt ::= */ - 272, /* (176) idlist_opt ::= LP idlist RP */ - 265, /* (177) idlist ::= idlist COMMA nm */ - 265, /* (178) idlist ::= nm */ - 218, /* (179) expr ::= LP expr RP */ - 218, /* (180) expr ::= ID|INDEXED|JOIN_KW */ - 218, /* (181) expr ::= nm DOT nm */ - 218, /* (182) expr ::= nm DOT nm DOT nm */ - 217, /* (183) term ::= NULL|FLOAT|BLOB */ - 217, /* (184) term ::= STRING */ - 217, /* (185) term ::= INTEGER */ - 218, /* (186) expr ::= VARIABLE */ - 218, /* (187) expr ::= expr COLLATE ID|STRING */ - 218, /* (188) expr ::= CAST LP expr AS typetoken RP */ - 218, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ - 218, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ - 218, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ - 218, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ - 218, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ - 218, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ - 217, /* (195) term ::= CTIME_KW */ - 218, /* (196) expr ::= LP nexprlist COMMA expr RP */ - 218, /* (197) expr ::= expr AND expr */ - 218, /* (198) expr ::= expr OR expr */ - 218, /* (199) expr ::= expr LT|GT|GE|LE expr */ - 218, /* (200) expr ::= expr EQ|NE expr */ - 218, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - 218, /* (202) expr ::= expr PLUS|MINUS expr */ - 218, /* (203) expr ::= expr STAR|SLASH|REM expr */ - 218, /* (204) expr ::= expr CONCAT expr */ - 276, /* (205) likeop ::= NOT LIKE_KW|MATCH */ - 218, /* (206) expr ::= expr likeop expr */ - 218, /* (207) expr ::= expr likeop expr ESCAPE expr */ - 218, /* (208) expr ::= expr ISNULL|NOTNULL */ - 218, /* (209) expr ::= expr NOT NULL */ - 218, /* (210) expr ::= expr IS expr */ - 218, /* (211) expr ::= expr IS NOT expr */ - 218, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */ - 218, /* (213) expr ::= expr IS DISTINCT FROM expr */ - 218, /* (214) expr ::= NOT expr */ - 218, /* (215) expr ::= BITNOT expr */ - 218, /* (216) expr ::= PLUS|MINUS expr */ - 218, /* (217) expr ::= expr PTR expr */ - 277, /* (218) between_op ::= BETWEEN */ - 277, /* (219) between_op ::= NOT BETWEEN */ - 218, /* (220) expr ::= expr between_op expr AND expr */ - 278, /* (221) in_op ::= IN */ - 278, /* (222) in_op ::= NOT IN */ - 218, /* (223) expr ::= expr in_op LP exprlist RP */ - 218, /* (224) expr ::= LP select RP */ - 218, /* (225) expr ::= expr in_op LP select RP */ - 218, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */ - 218, /* (227) expr ::= EXISTS LP select RP */ - 218, /* (228) expr ::= CASE case_operand case_exprlist case_else END */ - 281, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - 281, /* (230) case_exprlist ::= WHEN expr THEN expr */ - 282, /* (231) case_else ::= ELSE expr */ - 282, /* (232) case_else ::= */ - 280, /* (233) case_operand ::= */ - 263, /* (234) exprlist ::= */ - 254, /* (235) nexprlist ::= nexprlist COMMA expr */ - 254, /* (236) nexprlist ::= expr */ - 279, /* (237) paren_exprlist ::= */ - 279, /* (238) paren_exprlist ::= LP exprlist RP */ - 191, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - 283, /* (240) uniqueflag ::= UNIQUE */ - 283, /* (241) uniqueflag ::= */ - 222, /* (242) eidlist_opt ::= */ - 222, /* (243) eidlist_opt ::= LP eidlist RP */ - 233, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */ - 233, /* (245) eidlist ::= nm collate sortorder */ - 284, /* (246) collate ::= */ - 284, /* (247) collate ::= COLLATE ID|STRING */ - 191, /* (248) cmd ::= DROP INDEX ifexists fullname */ - 191, /* (249) cmd ::= VACUUM vinto */ - 191, /* (250) cmd ::= VACUUM nm vinto */ - 285, /* (251) vinto ::= INTO expr */ - 285, /* (252) vinto ::= */ - 191, /* (253) cmd ::= PRAGMA nm dbnm */ - 191, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */ - 191, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - 191, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */ - 191, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - 212, /* (258) plus_num ::= PLUS INTEGER|FLOAT */ - 213, /* (259) minus_num ::= MINUS INTEGER|FLOAT */ - 191, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - 287, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - 289, /* (262) trigger_time ::= BEFORE|AFTER */ - 289, /* (263) trigger_time ::= INSTEAD OF */ - 289, /* (264) trigger_time ::= */ - 290, /* (265) trigger_event ::= DELETE|INSERT */ - 290, /* (266) trigger_event ::= UPDATE */ - 290, /* (267) trigger_event ::= UPDATE OF idlist */ - 292, /* (268) when_clause ::= */ - 292, /* (269) when_clause ::= WHEN expr */ - 288, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - 288, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */ - 294, /* (272) trnm ::= nm DOT nm */ - 295, /* (273) tridxby ::= INDEXED BY nm */ - 295, /* (274) tridxby ::= NOT INDEXED */ - 293, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - 293, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - 293, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - 293, /* (278) trigger_cmd ::= scanpt select scanpt */ - 218, /* (279) expr ::= RAISE LP IGNORE RP */ - 218, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */ - 237, /* (281) raisetype ::= ROLLBACK */ - 237, /* (282) raisetype ::= ABORT */ - 237, /* (283) raisetype ::= FAIL */ - 191, /* (284) cmd ::= DROP TRIGGER ifexists fullname */ - 191, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - 191, /* (286) cmd ::= DETACH database_kw_opt expr */ - 297, /* (287) key_opt ::= */ - 297, /* (288) key_opt ::= KEY expr */ - 191, /* (289) cmd ::= REINDEX */ - 191, /* (290) cmd ::= REINDEX nm dbnm */ - 191, /* (291) cmd ::= ANALYZE */ - 191, /* (292) cmd ::= ANALYZE nm dbnm */ - 191, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */ - 191, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - 191, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - 298, /* (296) add_column_fullname ::= fullname */ - 191, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - 191, /* (298) cmd ::= create_vtab */ - 191, /* (299) cmd ::= create_vtab LP vtabarglist RP */ - 300, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 302, /* (301) vtabarg ::= */ - 303, /* (302) vtabargtoken ::= ANY */ - 303, /* (303) vtabargtoken ::= lp anylist RP */ - 304, /* (304) lp ::= LP */ - 268, /* (305) with ::= WITH wqlist */ - 268, /* (306) with ::= WITH RECURSIVE wqlist */ - 307, /* (307) wqas ::= AS */ - 307, /* (308) wqas ::= AS MATERIALIZED */ - 307, /* (309) wqas ::= AS NOT MATERIALIZED */ - 306, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */ - 308, /* (311) withnm ::= nm */ - 242, /* (312) wqlist ::= wqitem */ - 242, /* (313) wqlist ::= wqlist COMMA wqitem */ - 309, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - 310, /* (315) windowdefn ::= nm AS LP window RP */ - 311, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - 311, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - 311, /* (318) window ::= ORDER BY sortlist frame_opt */ - 311, /* (319) window ::= nm ORDER BY sortlist frame_opt */ - 311, /* (320) window ::= nm frame_opt */ - 312, /* (321) frame_opt ::= */ - 312, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - 312, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - 316, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */ - 318, /* (325) frame_bound_s ::= frame_bound */ - 318, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */ - 319, /* (327) frame_bound_e ::= frame_bound */ - 319, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */ - 317, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */ - 317, /* (330) frame_bound ::= CURRENT ROW */ - 320, /* (331) frame_exclude_opt ::= */ - 320, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */ - 321, /* (333) frame_exclude ::= NO OTHERS */ - 321, /* (334) frame_exclude ::= CURRENT ROW */ - 321, /* (335) frame_exclude ::= GROUP|TIES */ - 252, /* (336) window_clause ::= WINDOW windowdefn_list */ - 275, /* (337) filter_over ::= filter_clause over_clause */ - 275, /* (338) filter_over ::= over_clause */ - 275, /* (339) filter_over ::= filter_clause */ - 315, /* (340) over_clause ::= OVER LP window RP */ - 315, /* (341) over_clause ::= OVER nm */ - 314, /* (342) filter_clause ::= FILTER LP WHERE expr RP */ - 217, /* (343) term ::= QNUMBER */ - 186, /* (344) input ::= cmdlist */ - 187, /* (345) cmdlist ::= cmdlist ecmd */ - 187, /* (346) cmdlist ::= ecmd */ - 188, /* (347) ecmd ::= SEMI */ - 188, /* (348) ecmd ::= cmdx SEMI */ - 188, /* (349) ecmd ::= explain cmdx SEMI */ - 193, /* (350) trans_opt ::= */ - 193, /* (351) trans_opt ::= TRANSACTION */ - 193, /* (352) trans_opt ::= TRANSACTION nm */ - 195, /* (353) savepoint_opt ::= SAVEPOINT */ - 195, /* (354) savepoint_opt ::= */ - 191, /* (355) cmd ::= create_table create_table_args */ - 204, /* (356) table_option_set ::= table_option */ - 202, /* (357) columnlist ::= columnlist COMMA columnname carglist */ - 202, /* (358) columnlist ::= columnname carglist */ - 194, /* (359) nm ::= ID|INDEXED|JOIN_KW */ - 194, /* (360) nm ::= STRING */ - 209, /* (361) typetoken ::= typename */ - 210, /* (362) typename ::= ID|STRING */ - 211, /* (363) signed ::= plus_num */ - 211, /* (364) signed ::= minus_num */ - 208, /* (365) carglist ::= carglist ccons */ - 208, /* (366) carglist ::= */ - 216, /* (367) ccons ::= NULL onconf */ - 216, /* (368) ccons ::= GENERATED ALWAYS AS generated */ - 216, /* (369) ccons ::= AS generated */ - 203, /* (370) conslist_opt ::= COMMA conslist */ - 229, /* (371) conslist ::= conslist tconscomma tcons */ - 229, /* (372) conslist ::= tcons */ - 230, /* (373) tconscomma ::= */ - 234, /* (374) defer_subclause_opt ::= defer_subclause */ - 236, /* (375) resolvetype ::= raisetype */ - 240, /* (376) selectnowith ::= oneselect */ - 241, /* (377) oneselect ::= values */ - 256, /* (378) sclp ::= selcollist COMMA */ - 257, /* (379) as ::= ID|STRING */ - 266, /* (380) indexed_opt ::= indexed_by */ - 274, /* (381) returning ::= */ - 218, /* (382) expr ::= term */ - 276, /* (383) likeop ::= LIKE_KW|MATCH */ - 280, /* (384) case_operand ::= expr */ - 263, /* (385) exprlist ::= nexprlist */ - 286, /* (386) nmnum ::= plus_num */ - 286, /* (387) nmnum ::= nm */ - 286, /* (388) nmnum ::= ON */ - 286, /* (389) nmnum ::= DELETE */ - 286, /* (390) nmnum ::= DEFAULT */ - 212, /* (391) plus_num ::= INTEGER|FLOAT */ - 291, /* (392) foreach_clause ::= */ - 291, /* (393) foreach_clause ::= FOR EACH ROW */ - 294, /* (394) trnm ::= nm */ - 295, /* (395) tridxby ::= */ - 296, /* (396) database_kw_opt ::= DATABASE */ - 296, /* (397) database_kw_opt ::= */ - 299, /* (398) kwcolumn_opt ::= */ - 299, /* (399) kwcolumn_opt ::= COLUMNKW */ - 301, /* (400) vtabarglist ::= vtabarg */ - 301, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ - 302, /* (402) vtabarg ::= vtabarg vtabargtoken */ - 305, /* (403) anylist ::= */ - 305, /* (404) anylist ::= anylist LP anylist RP */ - 305, /* (405) anylist ::= anylist ANY */ - 268, /* (406) with ::= */ - 309, /* (407) windowdefn_list ::= windowdefn */ - 311, /* (408) window ::= frame_opt */ + 191, /* (0) explain ::= EXPLAIN */ + 191, /* (1) explain ::= EXPLAIN QUERY PLAN */ + 190, /* (2) cmdx ::= cmd */ + 192, /* (3) cmd ::= BEGIN transtype trans_opt */ + 193, /* (4) transtype ::= */ + 193, /* (5) transtype ::= DEFERRED */ + 193, /* (6) transtype ::= IMMEDIATE */ + 193, /* (7) transtype ::= EXCLUSIVE */ + 192, /* (8) cmd ::= COMMIT|END trans_opt */ + 192, /* (9) cmd ::= ROLLBACK trans_opt */ + 192, /* (10) cmd ::= SAVEPOINT nm */ + 192, /* (11) cmd ::= RELEASE savepoint_opt nm */ + 192, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + 197, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + 199, /* (14) createkw ::= CREATE */ + 201, /* (15) ifnotexists ::= */ + 201, /* (16) ifnotexists ::= IF NOT EXISTS */ + 200, /* (17) temp ::= TEMP */ + 200, /* (18) temp ::= */ + 198, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ + 198, /* (20) create_table_args ::= AS select */ + 205, /* (21) table_option_set ::= */ + 205, /* (22) table_option_set ::= table_option_set COMMA table_option */ + 207, /* (23) table_option ::= WITHOUT nm */ + 207, /* (24) table_option ::= nm */ + 208, /* (25) columnname ::= nm typetoken */ + 210, /* (26) typetoken ::= */ + 210, /* (27) typetoken ::= typename LP signed RP */ + 210, /* (28) typetoken ::= typename LP signed COMMA signed RP */ + 211, /* (29) typename ::= typename ID|STRING */ + 215, /* (30) scanpt ::= */ + 216, /* (31) scantok ::= */ + 217, /* (32) ccons ::= CONSTRAINT nm */ + 217, /* (33) ccons ::= DEFAULT scantok term */ + 217, /* (34) ccons ::= DEFAULT LP expr RP */ + 217, /* (35) ccons ::= DEFAULT PLUS scantok term */ + 217, /* (36) ccons ::= DEFAULT MINUS scantok term */ + 217, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ + 217, /* (38) ccons ::= NOT NULL onconf */ + 217, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + 217, /* (40) ccons ::= UNIQUE onconf */ + 217, /* (41) ccons ::= CHECK LP expr RP */ + 217, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ + 217, /* (43) ccons ::= defer_subclause */ + 217, /* (44) ccons ::= COLLATE ID|STRING */ + 226, /* (45) generated ::= LP expr RP */ + 226, /* (46) generated ::= LP expr RP ID */ + 222, /* (47) autoinc ::= */ + 222, /* (48) autoinc ::= AUTOINCR */ + 224, /* (49) refargs ::= */ + 224, /* (50) refargs ::= refargs refarg */ + 227, /* (51) refarg ::= MATCH nm */ + 227, /* (52) refarg ::= ON INSERT refact */ + 227, /* (53) refarg ::= ON DELETE refact */ + 227, /* (54) refarg ::= ON UPDATE refact */ + 228, /* (55) refact ::= SET NULL */ + 228, /* (56) refact ::= SET DEFAULT */ + 228, /* (57) refact ::= CASCADE */ + 228, /* (58) refact ::= RESTRICT */ + 228, /* (59) refact ::= NO ACTION */ + 225, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + 225, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 229, /* (62) init_deferred_pred_opt ::= */ + 229, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + 229, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 204, /* (65) conslist_opt ::= */ + 231, /* (66) tconscomma ::= COMMA */ + 232, /* (67) tcons ::= CONSTRAINT nm */ + 232, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + 232, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ + 232, /* (70) tcons ::= CHECK LP expr RP onconf */ + 232, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 235, /* (72) defer_subclause_opt ::= */ + 220, /* (73) onconf ::= */ + 220, /* (74) onconf ::= ON CONFLICT resolvetype */ + 236, /* (75) orconf ::= */ + 236, /* (76) orconf ::= OR resolvetype */ + 237, /* (77) resolvetype ::= IGNORE */ + 237, /* (78) resolvetype ::= REPLACE */ + 192, /* (79) cmd ::= DROP TABLE ifexists fullname */ + 239, /* (80) ifexists ::= IF EXISTS */ + 239, /* (81) ifexists ::= */ + 192, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + 192, /* (83) cmd ::= DROP VIEW ifexists fullname */ + 192, /* (84) cmd ::= select */ + 206, /* (85) select ::= WITH wqlist selectnowith */ + 206, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ + 206, /* (87) select ::= selectnowith */ + 241, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ + 244, /* (89) multiselect_op ::= UNION */ + 244, /* (90) multiselect_op ::= UNION ALL */ + 244, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ + 242, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + 242, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + 254, /* (94) values ::= VALUES LP nexprlist RP */ + 242, /* (95) oneselect ::= mvalues */ + 256, /* (96) mvalues ::= values COMMA LP nexprlist RP */ + 256, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */ + 245, /* (98) distinct ::= DISTINCT */ + 245, /* (99) distinct ::= ALL */ + 245, /* (100) distinct ::= */ + 257, /* (101) sclp ::= */ + 246, /* (102) selcollist ::= sclp scanpt expr scanpt as */ + 246, /* (103) selcollist ::= sclp scanpt STAR */ + 246, /* (104) selcollist ::= sclp scanpt nm DOT STAR */ + 258, /* (105) as ::= AS nm */ + 258, /* (106) as ::= */ + 247, /* (107) from ::= */ + 247, /* (108) from ::= FROM seltablist */ + 260, /* (109) stl_prefix ::= seltablist joinop */ + 260, /* (110) stl_prefix ::= */ + 259, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */ + 259, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ + 259, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ + 259, /* (114) seltablist ::= stl_prefix LP select RP as on_using */ + 259, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */ + 202, /* (116) dbnm ::= */ + 202, /* (117) dbnm ::= DOT nm */ + 240, /* (118) fullname ::= nm */ + 240, /* (119) fullname ::= nm DOT nm */ + 265, /* (120) xfullname ::= nm */ + 265, /* (121) xfullname ::= nm DOT nm */ + 265, /* (122) xfullname ::= nm AS nm */ + 265, /* (123) xfullname ::= nm DOT nm AS nm */ + 261, /* (124) joinop ::= COMMA|JOIN */ + 261, /* (125) joinop ::= JOIN_KW JOIN */ + 261, /* (126) joinop ::= JOIN_KW nm JOIN */ + 261, /* (127) joinop ::= JOIN_KW nm nm JOIN */ + 262, /* (128) on_using ::= ON expr */ + 262, /* (129) on_using ::= USING LP idlist RP */ + 262, /* (130) on_using ::= */ + 267, /* (131) indexed_opt ::= */ + 263, /* (132) indexed_by ::= INDEXED BY nm */ + 263, /* (133) indexed_by ::= NOT INDEXED */ + 251, /* (134) orderby_opt ::= */ + 251, /* (135) orderby_opt ::= ORDER BY sortlist */ + 233, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */ + 233, /* (137) sortlist ::= expr sortorder nulls */ + 221, /* (138) sortorder ::= ASC */ + 221, /* (139) sortorder ::= DESC */ + 221, /* (140) sortorder ::= */ + 268, /* (141) nulls ::= NULLS FIRST */ + 268, /* (142) nulls ::= NULLS LAST */ + 268, /* (143) nulls ::= */ + 249, /* (144) groupby_opt ::= */ + 249, /* (145) groupby_opt ::= GROUP BY nexprlist */ + 250, /* (146) having_opt ::= */ + 250, /* (147) having_opt ::= HAVING expr */ + 252, /* (148) limit_opt ::= */ + 252, /* (149) limit_opt ::= LIMIT expr */ + 252, /* (150) limit_opt ::= LIMIT expr OFFSET expr */ + 252, /* (151) limit_opt ::= LIMIT expr COMMA expr */ + 192, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ + 248, /* (153) where_opt ::= */ + 248, /* (154) where_opt ::= WHERE expr */ + 270, /* (155) where_opt_ret ::= */ + 270, /* (156) where_opt_ret ::= WHERE expr */ + 270, /* (157) where_opt_ret ::= RETURNING selcollist */ + 270, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */ + 192, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ + 271, /* (160) setlist ::= setlist COMMA nm EQ expr */ + 271, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */ + 271, /* (162) setlist ::= nm EQ expr */ + 271, /* (163) setlist ::= LP idlist RP EQ expr */ + 192, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + 192, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + 274, /* (166) upsert ::= */ + 274, /* (167) upsert ::= RETURNING selcollist */ + 274, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ + 274, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ + 274, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */ + 274, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ + 275, /* (172) returning ::= RETURNING selcollist */ + 272, /* (173) insert_cmd ::= INSERT orconf */ + 272, /* (174) insert_cmd ::= REPLACE */ + 273, /* (175) idlist_opt ::= */ + 273, /* (176) idlist_opt ::= LP idlist RP */ + 266, /* (177) idlist ::= idlist COMMA nm */ + 266, /* (178) idlist ::= nm */ + 219, /* (179) expr ::= LP expr RP */ + 219, /* (180) expr ::= ID|INDEXED|JOIN_KW */ + 219, /* (181) expr ::= nm DOT nm */ + 219, /* (182) expr ::= nm DOT nm DOT nm */ + 218, /* (183) term ::= NULL|FLOAT|BLOB */ + 218, /* (184) term ::= STRING */ + 218, /* (185) term ::= INTEGER */ + 219, /* (186) expr ::= VARIABLE */ + 219, /* (187) expr ::= expr COLLATE ID|STRING */ + 219, /* (188) expr ::= CAST LP expr AS typetoken RP */ + 219, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ + 219, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + 219, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + 219, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + 219, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + 219, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + 218, /* (195) term ::= CTIME_KW */ + 219, /* (196) expr ::= LP nexprlist COMMA expr RP */ + 219, /* (197) expr ::= expr AND expr */ + 219, /* (198) expr ::= expr OR expr */ + 219, /* (199) expr ::= expr LT|GT|GE|LE expr */ + 219, /* (200) expr ::= expr EQ|NE expr */ + 219, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + 219, /* (202) expr ::= expr PLUS|MINUS expr */ + 219, /* (203) expr ::= expr STAR|SLASH|REM expr */ + 219, /* (204) expr ::= expr CONCAT expr */ + 277, /* (205) likeop ::= NOT LIKE_KW|MATCH */ + 219, /* (206) expr ::= expr likeop expr */ + 219, /* (207) expr ::= expr likeop expr ESCAPE expr */ + 219, /* (208) expr ::= expr ISNULL|NOTNULL */ + 219, /* (209) expr ::= expr NOT NULL */ + 219, /* (210) expr ::= expr IS expr */ + 219, /* (211) expr ::= expr IS NOT expr */ + 219, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */ + 219, /* (213) expr ::= expr IS DISTINCT FROM expr */ + 219, /* (214) expr ::= NOT expr */ + 219, /* (215) expr ::= BITNOT expr */ + 219, /* (216) expr ::= PLUS|MINUS expr */ + 219, /* (217) expr ::= expr PTR expr */ + 278, /* (218) between_op ::= BETWEEN */ + 278, /* (219) between_op ::= NOT BETWEEN */ + 219, /* (220) expr ::= expr between_op expr AND expr */ + 279, /* (221) in_op ::= IN */ + 279, /* (222) in_op ::= NOT IN */ + 219, /* (223) expr ::= expr in_op LP exprlist RP */ + 219, /* (224) expr ::= LP select RP */ + 219, /* (225) expr ::= expr in_op LP select RP */ + 219, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */ + 219, /* (227) expr ::= EXISTS LP select RP */ + 219, /* (228) expr ::= CASE case_operand case_exprlist case_else END */ + 282, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + 282, /* (230) case_exprlist ::= WHEN expr THEN expr */ + 283, /* (231) case_else ::= ELSE expr */ + 283, /* (232) case_else ::= */ + 281, /* (233) case_operand ::= */ + 264, /* (234) exprlist ::= */ + 255, /* (235) nexprlist ::= nexprlist COMMA expr */ + 255, /* (236) nexprlist ::= expr */ + 280, /* (237) paren_exprlist ::= */ + 280, /* (238) paren_exprlist ::= LP exprlist RP */ + 192, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + 284, /* (240) uniqueflag ::= UNIQUE */ + 284, /* (241) uniqueflag ::= */ + 223, /* (242) eidlist_opt ::= */ + 223, /* (243) eidlist_opt ::= LP eidlist RP */ + 234, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */ + 234, /* (245) eidlist ::= nm collate sortorder */ + 285, /* (246) collate ::= */ + 285, /* (247) collate ::= COLLATE ID|STRING */ + 192, /* (248) cmd ::= DROP INDEX ifexists fullname */ + 192, /* (249) cmd ::= VACUUM vinto */ + 192, /* (250) cmd ::= VACUUM nm vinto */ + 286, /* (251) vinto ::= INTO expr */ + 286, /* (252) vinto ::= */ + 192, /* (253) cmd ::= PRAGMA nm dbnm */ + 192, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */ + 192, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + 192, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */ + 192, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + 213, /* (258) plus_num ::= PLUS INTEGER|FLOAT */ + 214, /* (259) minus_num ::= MINUS INTEGER|FLOAT */ + 192, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + 288, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + 290, /* (262) trigger_time ::= BEFORE|AFTER */ + 290, /* (263) trigger_time ::= INSTEAD OF */ + 290, /* (264) trigger_time ::= */ + 291, /* (265) trigger_event ::= DELETE|INSERT */ + 291, /* (266) trigger_event ::= UPDATE */ + 291, /* (267) trigger_event ::= UPDATE OF idlist */ + 293, /* (268) when_clause ::= */ + 293, /* (269) when_clause ::= WHEN expr */ + 289, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + 289, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */ + 295, /* (272) tridxby ::= INDEXED BY nm */ + 295, /* (273) tridxby ::= NOT INDEXED */ + 294, /* (274) trigger_cmd ::= UPDATE orconf xfullname tridxby SET setlist from where_opt scanpt */ + 294, /* (275) trigger_cmd ::= scanpt insert_cmd INTO xfullname idlist_opt select upsert scanpt */ + 294, /* (276) trigger_cmd ::= DELETE FROM xfullname tridxby where_opt scanpt */ + 294, /* (277) trigger_cmd ::= scanpt select scanpt */ + 219, /* (278) expr ::= RAISE LP IGNORE RP */ + 219, /* (279) expr ::= RAISE LP raisetype COMMA expr RP */ + 238, /* (280) raisetype ::= ROLLBACK */ + 238, /* (281) raisetype ::= ABORT */ + 238, /* (282) raisetype ::= FAIL */ + 192, /* (283) cmd ::= DROP TRIGGER ifexists fullname */ + 192, /* (284) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + 192, /* (285) cmd ::= DETACH database_kw_opt expr */ + 297, /* (286) key_opt ::= */ + 297, /* (287) key_opt ::= KEY expr */ + 192, /* (288) cmd ::= REINDEX */ + 192, /* (289) cmd ::= REINDEX nm dbnm */ + 192, /* (290) cmd ::= ANALYZE */ + 192, /* (291) cmd ::= ANALYZE nm dbnm */ + 192, /* (292) cmd ::= ALTER TABLE fullname RENAME TO nm */ + 192, /* (293) cmd ::= alter_add carglist */ + 298, /* (294) alter_add ::= ALTER TABLE fullname ADD kwcolumn_opt nm typetoken */ + 192, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + 192, /* (296) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + 192, /* (297) cmd ::= ALTER TABLE fullname DROP CONSTRAINT nm */ + 192, /* (298) cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm DROP NOT NULL */ + 192, /* (299) cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm SET NOT NULL onconf */ + 192, /* (300) cmd ::= ALTER TABLE fullname ADD CONSTRAINT nm CHECK LP expr RP onconf */ + 192, /* (301) cmd ::= ALTER TABLE fullname ADD CHECK LP expr RP onconf */ + 192, /* (302) cmd ::= create_vtab */ + 192, /* (303) cmd ::= create_vtab LP vtabarglist RP */ + 300, /* (304) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 302, /* (305) vtabarg ::= */ + 303, /* (306) vtabargtoken ::= ANY */ + 303, /* (307) vtabargtoken ::= lp anylist RP */ + 304, /* (308) lp ::= LP */ + 269, /* (309) with ::= WITH wqlist */ + 269, /* (310) with ::= WITH RECURSIVE wqlist */ + 307, /* (311) wqas ::= AS */ + 307, /* (312) wqas ::= AS MATERIALIZED */ + 307, /* (313) wqas ::= AS NOT MATERIALIZED */ + 306, /* (314) wqitem ::= withnm eidlist_opt wqas LP select RP */ + 308, /* (315) withnm ::= nm */ + 243, /* (316) wqlist ::= wqitem */ + 243, /* (317) wqlist ::= wqlist COMMA wqitem */ + 309, /* (318) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + 310, /* (319) windowdefn ::= nm AS LP window RP */ + 311, /* (320) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + 311, /* (321) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + 311, /* (322) window ::= ORDER BY sortlist frame_opt */ + 311, /* (323) window ::= nm ORDER BY sortlist frame_opt */ + 311, /* (324) window ::= nm frame_opt */ + 312, /* (325) frame_opt ::= */ + 312, /* (326) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + 312, /* (327) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + 316, /* (328) range_or_rows ::= RANGE|ROWS|GROUPS */ + 318, /* (329) frame_bound_s ::= frame_bound */ + 318, /* (330) frame_bound_s ::= UNBOUNDED PRECEDING */ + 319, /* (331) frame_bound_e ::= frame_bound */ + 319, /* (332) frame_bound_e ::= UNBOUNDED FOLLOWING */ + 317, /* (333) frame_bound ::= expr PRECEDING|FOLLOWING */ + 317, /* (334) frame_bound ::= CURRENT ROW */ + 320, /* (335) frame_exclude_opt ::= */ + 320, /* (336) frame_exclude_opt ::= EXCLUDE frame_exclude */ + 321, /* (337) frame_exclude ::= NO OTHERS */ + 321, /* (338) frame_exclude ::= CURRENT ROW */ + 321, /* (339) frame_exclude ::= GROUP|TIES */ + 253, /* (340) window_clause ::= WINDOW windowdefn_list */ + 276, /* (341) filter_over ::= filter_clause over_clause */ + 276, /* (342) filter_over ::= over_clause */ + 276, /* (343) filter_over ::= filter_clause */ + 315, /* (344) over_clause ::= OVER LP window RP */ + 315, /* (345) over_clause ::= OVER nm */ + 314, /* (346) filter_clause ::= FILTER LP WHERE expr RP */ + 218, /* (347) term ::= QNUMBER */ + 187, /* (348) input ::= cmdlist */ + 188, /* (349) cmdlist ::= cmdlist ecmd */ + 188, /* (350) cmdlist ::= ecmd */ + 189, /* (351) ecmd ::= SEMI */ + 189, /* (352) ecmd ::= cmdx SEMI */ + 189, /* (353) ecmd ::= explain cmdx SEMI */ + 194, /* (354) trans_opt ::= */ + 194, /* (355) trans_opt ::= TRANSACTION */ + 194, /* (356) trans_opt ::= TRANSACTION nm */ + 196, /* (357) savepoint_opt ::= SAVEPOINT */ + 196, /* (358) savepoint_opt ::= */ + 192, /* (359) cmd ::= create_table create_table_args */ + 205, /* (360) table_option_set ::= table_option */ + 203, /* (361) columnlist ::= columnlist COMMA columnname carglist */ + 203, /* (362) columnlist ::= columnname carglist */ + 195, /* (363) nm ::= ID|INDEXED|JOIN_KW */ + 195, /* (364) nm ::= STRING */ + 210, /* (365) typetoken ::= typename */ + 211, /* (366) typename ::= ID|STRING */ + 212, /* (367) signed ::= plus_num */ + 212, /* (368) signed ::= minus_num */ + 209, /* (369) carglist ::= carglist ccons */ + 209, /* (370) carglist ::= */ + 217, /* (371) ccons ::= NULL onconf */ + 217, /* (372) ccons ::= GENERATED ALWAYS AS generated */ + 217, /* (373) ccons ::= AS generated */ + 204, /* (374) conslist_opt ::= COMMA conslist */ + 230, /* (375) conslist ::= conslist tconscomma tcons */ + 230, /* (376) conslist ::= tcons */ + 231, /* (377) tconscomma ::= */ + 235, /* (378) defer_subclause_opt ::= defer_subclause */ + 237, /* (379) resolvetype ::= raisetype */ + 241, /* (380) selectnowith ::= oneselect */ + 242, /* (381) oneselect ::= values */ + 257, /* (382) sclp ::= selcollist COMMA */ + 258, /* (383) as ::= ID|STRING */ + 267, /* (384) indexed_opt ::= indexed_by */ + 275, /* (385) returning ::= */ + 219, /* (386) expr ::= term */ + 277, /* (387) likeop ::= LIKE_KW|MATCH */ + 281, /* (388) case_operand ::= expr */ + 264, /* (389) exprlist ::= nexprlist */ + 287, /* (390) nmnum ::= plus_num */ + 287, /* (391) nmnum ::= nm */ + 287, /* (392) nmnum ::= ON */ + 287, /* (393) nmnum ::= DELETE */ + 287, /* (394) nmnum ::= DEFAULT */ + 213, /* (395) plus_num ::= INTEGER|FLOAT */ + 292, /* (396) foreach_clause ::= */ + 292, /* (397) foreach_clause ::= FOR EACH ROW */ + 295, /* (398) tridxby ::= */ + 296, /* (399) database_kw_opt ::= DATABASE */ + 296, /* (400) database_kw_opt ::= */ + 299, /* (401) kwcolumn_opt ::= */ + 299, /* (402) kwcolumn_opt ::= COLUMNKW */ + 301, /* (403) vtabarglist ::= vtabarg */ + 301, /* (404) vtabarglist ::= vtabarglist COMMA vtabarg */ + 302, /* (405) vtabarg ::= vtabarg vtabargtoken */ + 305, /* (406) anylist ::= */ + 305, /* (407) anylist ::= anylist LP anylist RP */ + 305, /* (408) anylist ::= anylist ANY */ + 269, /* (409) with ::= */ + 309, /* (410) windowdefn_list ::= windowdefn */ + 311, /* (411) window ::= frame_opt */ }; /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number @@ -177275,8 +183507,8 @@ static const signed char yyRuleInfoNRhs[] = { -3, /* (119) fullname ::= nm DOT nm */ -1, /* (120) xfullname ::= nm */ -3, /* (121) xfullname ::= nm DOT nm */ - -5, /* (122) xfullname ::= nm DOT nm AS nm */ - -3, /* (123) xfullname ::= nm AS nm */ + -3, /* (122) xfullname ::= nm AS nm */ + -5, /* (123) xfullname ::= nm DOT nm AS nm */ -1, /* (124) joinop ::= COMMA|JOIN */ -2, /* (125) joinop ::= JOIN_KW JOIN */ -3, /* (126) joinop ::= JOIN_KW nm JOIN */ @@ -177425,143 +183657,146 @@ static const signed char yyRuleInfoNRhs[] = { -2, /* (269) when_clause ::= WHEN expr */ -3, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ -2, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */ - -3, /* (272) trnm ::= nm DOT nm */ - -3, /* (273) tridxby ::= INDEXED BY nm */ - -2, /* (274) tridxby ::= NOT INDEXED */ - -9, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - -8, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - -6, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - -3, /* (278) trigger_cmd ::= scanpt select scanpt */ - -4, /* (279) expr ::= RAISE LP IGNORE RP */ - -6, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */ - -1, /* (281) raisetype ::= ROLLBACK */ - -1, /* (282) raisetype ::= ABORT */ - -1, /* (283) raisetype ::= FAIL */ - -4, /* (284) cmd ::= DROP TRIGGER ifexists fullname */ - -6, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - -3, /* (286) cmd ::= DETACH database_kw_opt expr */ - 0, /* (287) key_opt ::= */ - -2, /* (288) key_opt ::= KEY expr */ - -1, /* (289) cmd ::= REINDEX */ - -3, /* (290) cmd ::= REINDEX nm dbnm */ - -1, /* (291) cmd ::= ANALYZE */ - -3, /* (292) cmd ::= ANALYZE nm dbnm */ - -6, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */ - -7, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + -3, /* (272) tridxby ::= INDEXED BY nm */ + -2, /* (273) tridxby ::= NOT INDEXED */ + -9, /* (274) trigger_cmd ::= UPDATE orconf xfullname tridxby SET setlist from where_opt scanpt */ + -8, /* (275) trigger_cmd ::= scanpt insert_cmd INTO xfullname idlist_opt select upsert scanpt */ + -6, /* (276) trigger_cmd ::= DELETE FROM xfullname tridxby where_opt scanpt */ + -3, /* (277) trigger_cmd ::= scanpt select scanpt */ + -4, /* (278) expr ::= RAISE LP IGNORE RP */ + -6, /* (279) expr ::= RAISE LP raisetype COMMA expr RP */ + -1, /* (280) raisetype ::= ROLLBACK */ + -1, /* (281) raisetype ::= ABORT */ + -1, /* (282) raisetype ::= FAIL */ + -4, /* (283) cmd ::= DROP TRIGGER ifexists fullname */ + -6, /* (284) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + -3, /* (285) cmd ::= DETACH database_kw_opt expr */ + 0, /* (286) key_opt ::= */ + -2, /* (287) key_opt ::= KEY expr */ + -1, /* (288) cmd ::= REINDEX */ + -3, /* (289) cmd ::= REINDEX nm dbnm */ + -1, /* (290) cmd ::= ANALYZE */ + -3, /* (291) cmd ::= ANALYZE nm dbnm */ + -6, /* (292) cmd ::= ALTER TABLE fullname RENAME TO nm */ + -2, /* (293) cmd ::= alter_add carglist */ + -7, /* (294) alter_add ::= ALTER TABLE fullname ADD kwcolumn_opt nm typetoken */ -6, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - -1, /* (296) add_column_fullname ::= fullname */ - -8, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - -1, /* (298) cmd ::= create_vtab */ - -4, /* (299) cmd ::= create_vtab LP vtabarglist RP */ - -8, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 0, /* (301) vtabarg ::= */ - -1, /* (302) vtabargtoken ::= ANY */ - -3, /* (303) vtabargtoken ::= lp anylist RP */ - -1, /* (304) lp ::= LP */ - -2, /* (305) with ::= WITH wqlist */ - -3, /* (306) with ::= WITH RECURSIVE wqlist */ - -1, /* (307) wqas ::= AS */ - -2, /* (308) wqas ::= AS MATERIALIZED */ - -3, /* (309) wqas ::= AS NOT MATERIALIZED */ - -6, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */ - -1, /* (311) withnm ::= nm */ - -1, /* (312) wqlist ::= wqitem */ - -3, /* (313) wqlist ::= wqlist COMMA wqitem */ - -3, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - -5, /* (315) windowdefn ::= nm AS LP window RP */ - -5, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - -6, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - -4, /* (318) window ::= ORDER BY sortlist frame_opt */ - -5, /* (319) window ::= nm ORDER BY sortlist frame_opt */ - -2, /* (320) window ::= nm frame_opt */ - 0, /* (321) frame_opt ::= */ - -3, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - -6, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - -1, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */ - -1, /* (325) frame_bound_s ::= frame_bound */ - -2, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */ - -1, /* (327) frame_bound_e ::= frame_bound */ - -2, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */ - -2, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */ - -2, /* (330) frame_bound ::= CURRENT ROW */ - 0, /* (331) frame_exclude_opt ::= */ - -2, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */ - -2, /* (333) frame_exclude ::= NO OTHERS */ - -2, /* (334) frame_exclude ::= CURRENT ROW */ - -1, /* (335) frame_exclude ::= GROUP|TIES */ - -2, /* (336) window_clause ::= WINDOW windowdefn_list */ - -2, /* (337) filter_over ::= filter_clause over_clause */ - -1, /* (338) filter_over ::= over_clause */ - -1, /* (339) filter_over ::= filter_clause */ - -4, /* (340) over_clause ::= OVER LP window RP */ - -2, /* (341) over_clause ::= OVER nm */ - -5, /* (342) filter_clause ::= FILTER LP WHERE expr RP */ - -1, /* (343) term ::= QNUMBER */ - -1, /* (344) input ::= cmdlist */ - -2, /* (345) cmdlist ::= cmdlist ecmd */ - -1, /* (346) cmdlist ::= ecmd */ - -1, /* (347) ecmd ::= SEMI */ - -2, /* (348) ecmd ::= cmdx SEMI */ - -3, /* (349) ecmd ::= explain cmdx SEMI */ - 0, /* (350) trans_opt ::= */ - -1, /* (351) trans_opt ::= TRANSACTION */ - -2, /* (352) trans_opt ::= TRANSACTION nm */ - -1, /* (353) savepoint_opt ::= SAVEPOINT */ - 0, /* (354) savepoint_opt ::= */ - -2, /* (355) cmd ::= create_table create_table_args */ - -1, /* (356) table_option_set ::= table_option */ - -4, /* (357) columnlist ::= columnlist COMMA columnname carglist */ - -2, /* (358) columnlist ::= columnname carglist */ - -1, /* (359) nm ::= ID|INDEXED|JOIN_KW */ - -1, /* (360) nm ::= STRING */ - -1, /* (361) typetoken ::= typename */ - -1, /* (362) typename ::= ID|STRING */ - -1, /* (363) signed ::= plus_num */ - -1, /* (364) signed ::= minus_num */ - -2, /* (365) carglist ::= carglist ccons */ - 0, /* (366) carglist ::= */ - -2, /* (367) ccons ::= NULL onconf */ - -4, /* (368) ccons ::= GENERATED ALWAYS AS generated */ - -2, /* (369) ccons ::= AS generated */ - -2, /* (370) conslist_opt ::= COMMA conslist */ - -3, /* (371) conslist ::= conslist tconscomma tcons */ - -1, /* (372) conslist ::= tcons */ - 0, /* (373) tconscomma ::= */ - -1, /* (374) defer_subclause_opt ::= defer_subclause */ - -1, /* (375) resolvetype ::= raisetype */ - -1, /* (376) selectnowith ::= oneselect */ - -1, /* (377) oneselect ::= values */ - -2, /* (378) sclp ::= selcollist COMMA */ - -1, /* (379) as ::= ID|STRING */ - -1, /* (380) indexed_opt ::= indexed_by */ - 0, /* (381) returning ::= */ - -1, /* (382) expr ::= term */ - -1, /* (383) likeop ::= LIKE_KW|MATCH */ - -1, /* (384) case_operand ::= expr */ - -1, /* (385) exprlist ::= nexprlist */ - -1, /* (386) nmnum ::= plus_num */ - -1, /* (387) nmnum ::= nm */ - -1, /* (388) nmnum ::= ON */ - -1, /* (389) nmnum ::= DELETE */ - -1, /* (390) nmnum ::= DEFAULT */ - -1, /* (391) plus_num ::= INTEGER|FLOAT */ - 0, /* (392) foreach_clause ::= */ - -3, /* (393) foreach_clause ::= FOR EACH ROW */ - -1, /* (394) trnm ::= nm */ - 0, /* (395) tridxby ::= */ - -1, /* (396) database_kw_opt ::= DATABASE */ - 0, /* (397) database_kw_opt ::= */ - 0, /* (398) kwcolumn_opt ::= */ - -1, /* (399) kwcolumn_opt ::= COLUMNKW */ - -1, /* (400) vtabarglist ::= vtabarg */ - -3, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ - -2, /* (402) vtabarg ::= vtabarg vtabargtoken */ - 0, /* (403) anylist ::= */ - -4, /* (404) anylist ::= anylist LP anylist RP */ - -2, /* (405) anylist ::= anylist ANY */ - 0, /* (406) with ::= */ - -1, /* (407) windowdefn_list ::= windowdefn */ - -1, /* (408) window ::= frame_opt */ + -8, /* (296) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + -6, /* (297) cmd ::= ALTER TABLE fullname DROP CONSTRAINT nm */ + -9, /* (298) cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm DROP NOT NULL */ + -10, /* (299) cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm SET NOT NULL onconf */ + -11, /* (300) cmd ::= ALTER TABLE fullname ADD CONSTRAINT nm CHECK LP expr RP onconf */ + -9, /* (301) cmd ::= ALTER TABLE fullname ADD CHECK LP expr RP onconf */ + -1, /* (302) cmd ::= create_vtab */ + -4, /* (303) cmd ::= create_vtab LP vtabarglist RP */ + -8, /* (304) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 0, /* (305) vtabarg ::= */ + -1, /* (306) vtabargtoken ::= ANY */ + -3, /* (307) vtabargtoken ::= lp anylist RP */ + -1, /* (308) lp ::= LP */ + -2, /* (309) with ::= WITH wqlist */ + -3, /* (310) with ::= WITH RECURSIVE wqlist */ + -1, /* (311) wqas ::= AS */ + -2, /* (312) wqas ::= AS MATERIALIZED */ + -3, /* (313) wqas ::= AS NOT MATERIALIZED */ + -6, /* (314) wqitem ::= withnm eidlist_opt wqas LP select RP */ + -1, /* (315) withnm ::= nm */ + -1, /* (316) wqlist ::= wqitem */ + -3, /* (317) wqlist ::= wqlist COMMA wqitem */ + -3, /* (318) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + -5, /* (319) windowdefn ::= nm AS LP window RP */ + -5, /* (320) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + -6, /* (321) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + -4, /* (322) window ::= ORDER BY sortlist frame_opt */ + -5, /* (323) window ::= nm ORDER BY sortlist frame_opt */ + -2, /* (324) window ::= nm frame_opt */ + 0, /* (325) frame_opt ::= */ + -3, /* (326) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + -6, /* (327) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + -1, /* (328) range_or_rows ::= RANGE|ROWS|GROUPS */ + -1, /* (329) frame_bound_s ::= frame_bound */ + -2, /* (330) frame_bound_s ::= UNBOUNDED PRECEDING */ + -1, /* (331) frame_bound_e ::= frame_bound */ + -2, /* (332) frame_bound_e ::= UNBOUNDED FOLLOWING */ + -2, /* (333) frame_bound ::= expr PRECEDING|FOLLOWING */ + -2, /* (334) frame_bound ::= CURRENT ROW */ + 0, /* (335) frame_exclude_opt ::= */ + -2, /* (336) frame_exclude_opt ::= EXCLUDE frame_exclude */ + -2, /* (337) frame_exclude ::= NO OTHERS */ + -2, /* (338) frame_exclude ::= CURRENT ROW */ + -1, /* (339) frame_exclude ::= GROUP|TIES */ + -2, /* (340) window_clause ::= WINDOW windowdefn_list */ + -2, /* (341) filter_over ::= filter_clause over_clause */ + -1, /* (342) filter_over ::= over_clause */ + -1, /* (343) filter_over ::= filter_clause */ + -4, /* (344) over_clause ::= OVER LP window RP */ + -2, /* (345) over_clause ::= OVER nm */ + -5, /* (346) filter_clause ::= FILTER LP WHERE expr RP */ + -1, /* (347) term ::= QNUMBER */ + -1, /* (348) input ::= cmdlist */ + -2, /* (349) cmdlist ::= cmdlist ecmd */ + -1, /* (350) cmdlist ::= ecmd */ + -1, /* (351) ecmd ::= SEMI */ + -2, /* (352) ecmd ::= cmdx SEMI */ + -3, /* (353) ecmd ::= explain cmdx SEMI */ + 0, /* (354) trans_opt ::= */ + -1, /* (355) trans_opt ::= TRANSACTION */ + -2, /* (356) trans_opt ::= TRANSACTION nm */ + -1, /* (357) savepoint_opt ::= SAVEPOINT */ + 0, /* (358) savepoint_opt ::= */ + -2, /* (359) cmd ::= create_table create_table_args */ + -1, /* (360) table_option_set ::= table_option */ + -4, /* (361) columnlist ::= columnlist COMMA columnname carglist */ + -2, /* (362) columnlist ::= columnname carglist */ + -1, /* (363) nm ::= ID|INDEXED|JOIN_KW */ + -1, /* (364) nm ::= STRING */ + -1, /* (365) typetoken ::= typename */ + -1, /* (366) typename ::= ID|STRING */ + -1, /* (367) signed ::= plus_num */ + -1, /* (368) signed ::= minus_num */ + -2, /* (369) carglist ::= carglist ccons */ + 0, /* (370) carglist ::= */ + -2, /* (371) ccons ::= NULL onconf */ + -4, /* (372) ccons ::= GENERATED ALWAYS AS generated */ + -2, /* (373) ccons ::= AS generated */ + -2, /* (374) conslist_opt ::= COMMA conslist */ + -3, /* (375) conslist ::= conslist tconscomma tcons */ + -1, /* (376) conslist ::= tcons */ + 0, /* (377) tconscomma ::= */ + -1, /* (378) defer_subclause_opt ::= defer_subclause */ + -1, /* (379) resolvetype ::= raisetype */ + -1, /* (380) selectnowith ::= oneselect */ + -1, /* (381) oneselect ::= values */ + -2, /* (382) sclp ::= selcollist COMMA */ + -1, /* (383) as ::= ID|STRING */ + -1, /* (384) indexed_opt ::= indexed_by */ + 0, /* (385) returning ::= */ + -1, /* (386) expr ::= term */ + -1, /* (387) likeop ::= LIKE_KW|MATCH */ + -1, /* (388) case_operand ::= expr */ + -1, /* (389) exprlist ::= nexprlist */ + -1, /* (390) nmnum ::= plus_num */ + -1, /* (391) nmnum ::= nm */ + -1, /* (392) nmnum ::= ON */ + -1, /* (393) nmnum ::= DELETE */ + -1, /* (394) nmnum ::= DEFAULT */ + -1, /* (395) plus_num ::= INTEGER|FLOAT */ + 0, /* (396) foreach_clause ::= */ + -3, /* (397) foreach_clause ::= FOR EACH ROW */ + 0, /* (398) tridxby ::= */ + -1, /* (399) database_kw_opt ::= DATABASE */ + 0, /* (400) database_kw_opt ::= */ + 0, /* (401) kwcolumn_opt ::= */ + -1, /* (402) kwcolumn_opt ::= COLUMNKW */ + -1, /* (403) vtabarglist ::= vtabarg */ + -3, /* (404) vtabarglist ::= vtabarglist COMMA vtabarg */ + -2, /* (405) vtabarg ::= vtabarg vtabargtoken */ + 0, /* (406) anylist ::= */ + -4, /* (407) anylist ::= anylist LP anylist RP */ + -2, /* (408) anylist ::= anylist ANY */ + 0, /* (409) with ::= */ + -1, /* (410) windowdefn_list ::= windowdefn */ + -1, /* (411) window ::= frame_opt */ }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -177621,7 +183856,7 @@ static YYACTIONTYPE yy_reduce( case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); - case 324: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==324); + case 328: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==328); {yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/} break; case 8: /* cmd ::= COMMIT|END trans_opt */ @@ -177649,7 +183884,9 @@ static YYACTIONTYPE yy_reduce( } break; case 14: /* createkw ::= CREATE */ -{disableLookaside(pParse);} +{ + disableLookaside(pParse); +} break; case 15: /* ifnotexists ::= */ case 18: /* temp ::= */ yytestcase(yyruleno==18); @@ -177741,7 +183978,7 @@ static YYACTIONTYPE yy_reduce( break; case 32: /* ccons ::= CONSTRAINT nm */ case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67); -{pParse->constraintName = yymsp[0].minor.yy0;} +{ASSERT_IS_CREATE; pParse->u1.cr.constraintName = yymsp[0].minor.yy0;} break; case 33: /* ccons ::= DEFAULT scantok term */ {sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} @@ -177851,7 +184088,7 @@ static YYACTIONTYPE yy_reduce( {yymsp[-1].minor.yy144 = 0;} break; case 66: /* tconscomma ::= COMMA */ -{pParse->constraintName.n = 0;} +{ASSERT_IS_CREATE; pParse->u1.cr.constraintName.n = 0;} break; case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ {sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy144,yymsp[-2].minor.yy144,0);} @@ -177901,7 +184138,11 @@ static YYACTIONTYPE yy_reduce( case 84: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0}; - sqlite3Select(pParse, yymsp[0].minor.yy555, &dest); + if( (pParse->db->mDbFlags & DBFLAG_EncodingFixed)!=0 + || sqlite3ReadSchema(pParse)==SQLITE_OK + ){ + sqlite3Select(pParse, yymsp[0].minor.yy555, &dest); + } sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555); } break; @@ -177934,8 +184175,8 @@ static YYACTIONTYPE yy_reduce( if( pRhs ){ pRhs->op = (u8)yymsp[-1].minor.yy144; pRhs->pPrior = pLhs; - if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; - pRhs->selFlags &= ~SF_MultiValue; + if( ALWAYS(pLhs) ) pLhs->selFlags &= ~(u32)SF_MultiValue; + pRhs->selFlags &= ~(u32)SF_MultiValue; if( yymsp[-1].minor.yy144!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); @@ -178109,6 +184350,7 @@ static YYACTIONTYPE yy_reduce( {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; case 118: /* fullname ::= nm */ + case 120: /* xfullname ::= nm */ yytestcase(yyruleno==120); { yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0); @@ -178116,29 +184358,38 @@ static YYACTIONTYPE yy_reduce( yymsp[0].minor.yy203 = yylhsminor.yy203; break; case 119: /* fullname ::= nm DOT nm */ + case 121: /* xfullname ::= nm DOT nm */ yytestcase(yyruleno==121); { yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0); } yymsp[-2].minor.yy203 = yylhsminor.yy203; break; - case 120: /* xfullname ::= nm */ -{yymsp[0].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} - break; - case 121: /* xfullname ::= nm DOT nm */ -{yymsp[-2].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} - break; - case 122: /* xfullname ::= nm DOT nm AS nm */ + case 122: /* xfullname ::= nm AS nm */ { - yymsp[-4].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ - if( yymsp[-4].minor.yy203 ) yymsp[-4].minor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); + if( yylhsminor.yy203 ){ + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[-2].minor.yy0); + }else{ + yylhsminor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + } + } } + yymsp[-2].minor.yy203 = yylhsminor.yy203; break; - case 123: /* xfullname ::= nm AS nm */ + case 123: /* xfullname ::= nm DOT nm AS nm */ { - yymsp[-2].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ - if( yymsp[-2].minor.yy203 ) yymsp[-2].minor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); + if( yylhsminor.yy203 ){ + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[-2].minor.yy0); + }else{ + yylhsminor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + } + } } + yymsp[-4].minor.yy203 = yylhsminor.yy203; break; case 124: /* joinop ::= COMMA|JOIN */ { yymsp[0].minor.yy144 = JT_INNER; } @@ -178354,7 +184605,12 @@ static YYACTIONTYPE yy_reduce( break; case 185: /* term ::= INTEGER */ { - yylhsminor.yy454 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); + int iValue; + if( sqlite3GetInt32(yymsp[0].minor.yy0.z, &iValue)==0 ){ + yylhsminor.yy454 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 0); + }else{ + yylhsminor.yy454 = sqlite3ExprInt32(pParse->db, iValue); + } if( yylhsminor.yy454 ) yylhsminor.yy454->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail); } yymsp[0].minor.yy454 = yylhsminor.yy454; @@ -178372,7 +184628,7 @@ static YYACTIONTYPE yy_reduce( Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/ assert( t.n>=2 ); if( pParse->nested==0 ){ - sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); + parserSyntaxError(pParse, &t); yymsp[0].minor.yy454 = 0; }else{ yymsp[0].minor.yy454 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); @@ -178444,9 +184700,11 @@ static YYACTIONTYPE yy_reduce( ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454); yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); if( yymsp[-4].minor.yy454 ){ + int i; yymsp[-4].minor.yy454->x.pList = pList; - if( ALWAYS(pList->nExpr) ){ - yymsp[-4].minor.yy454->flags |= pList->a[0].pExpr->flags & EP_Propagate; + for(i=0; inExpr; i++){ + assert( pList->a[i].pExpr!=0 ); + yymsp[-4].minor.yy454->flags |= pList->a[i].pExpr->flags & EP_Propagate; } }else{ sqlite3ExprListDelete(pParse->db, pList); @@ -178494,33 +184752,29 @@ static YYACTIONTYPE yy_reduce( } break; case 208: /* expr ::= expr ISNULL|NOTNULL */ -{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy454,0);} +{yymsp[-1].minor.yy454 = sqlite3PExprIsNull(pParse,yymsp[0].major,yymsp[-1].minor.yy454);} break; case 209: /* expr ::= expr NOT NULL */ -{yymsp[-2].minor.yy454 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy454,0);} +{yymsp[-2].minor.yy454 = sqlite3PExprIsNull(pParse,TK_NOTNULL,yymsp[-2].minor.yy454);} break; case 210: /* expr ::= expr IS expr */ { - yymsp[-2].minor.yy454 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-2].minor.yy454, TK_ISNULL); + yymsp[-2].minor.yy454 = sqlite3PExprIs(pParse, TK_IS, yymsp[-2].minor.yy454, yymsp[0].minor.yy454); } break; case 211: /* expr ::= expr IS NOT expr */ { - yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-3].minor.yy454, TK_NOTNULL); + yymsp[-3].minor.yy454 = sqlite3PExprIs(pParse, TK_ISNOT, yymsp[-3].minor.yy454, yymsp[0].minor.yy454); } break; case 212: /* expr ::= expr IS NOT DISTINCT FROM expr */ { - yymsp[-5].minor.yy454 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-5].minor.yy454, TK_ISNULL); + yymsp[-5].minor.yy454 = sqlite3PExprIs(pParse, TK_IS, yymsp[-5].minor.yy454, yymsp[0].minor.yy454); } break; case 213: /* expr ::= expr IS DISTINCT FROM expr */ { - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-4].minor.yy454, TK_NOTNULL); + yymsp[-4].minor.yy454 = sqlite3PExprIs(pParse, TK_ISNOT, yymsp[-4].minor.yy454, yymsp[0].minor.yy454); } break; case 214: /* expr ::= NOT expr */ @@ -178561,6 +184815,7 @@ static YYACTIONTYPE yy_reduce( yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy454, 0); if( yymsp[-4].minor.yy454 ){ yymsp[-4].minor.yy454->x.pList = pList; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454); }else{ sqlite3ExprListDelete(pParse->db, pList); } @@ -178575,12 +184830,21 @@ static YYACTIONTYPE yy_reduce( ** expr1 IN () ** expr1 NOT IN () ** - ** simplify to constants 0 (false) and 1 (true), respectively, - ** regardless of the value of expr1. + ** simplify to constants 0 (false) and 1 (true), respectively. + ** + ** Except, do not apply this optimization if expr1 contains a function + ** because that function might be an aggregate (we don't know yet whether + ** it is or not) and if it is an aggregate, that could change the meaning + ** of the whole query. */ - sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy454); - yymsp[-4].minor.yy454 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy144 ? "true" : "false"); - if( yymsp[-4].minor.yy454 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy454); + Expr *pB = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy144 ? "true" : "false"); + if( pB ) sqlite3ExprIdToTrueFalse(pB); + if( !ExprHasProperty(yymsp[-4].minor.yy454, EP_HasFunc) ){ + sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy454); + yymsp[-4].minor.yy454 = pB; + }else{ + yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, yymsp[-3].minor.yy144 ? TK_OR : TK_AND, pB, yymsp[-4].minor.yy454); + } }else{ Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr; if( yymsp[-1].minor.yy14->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && yymsp[-4].minor.yy454->op!=TK_VECTOR ){ @@ -178688,7 +184952,7 @@ static YYACTIONTYPE yy_reduce( } break; case 240: /* uniqueflag ::= UNIQUE */ - case 282: /* raisetype ::= ABORT */ yytestcase(yyruleno==282); + case 281: /* raisetype ::= ABORT */ yytestcase(yyruleno==281); {yymsp[0].minor.yy144 = OE_Abort;} break; case 241: /* uniqueflag ::= */ @@ -178740,6 +185004,10 @@ static YYACTIONTYPE yy_reduce( { sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy144, yymsp[-4].minor.yy286.a, yymsp[-4].minor.yy286.b, yymsp[-2].minor.yy203, yymsp[0].minor.yy454, yymsp[-10].minor.yy144, yymsp[-8].minor.yy144); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ +#ifdef SQLITE_DEBUG + assert( pParse->isCreate ); /* Set by createkw reduce action */ + pParse->isCreate = 0; /* But, should not be set for CREATE TRIGGER */ +#endif } break; case 262: /* trigger_time ::= BEFORE|AFTER */ @@ -178759,67 +185027,57 @@ static YYACTIONTYPE yy_reduce( {yymsp[-2].minor.yy286.a = TK_UPDATE; yymsp[-2].minor.yy286.b = yymsp[0].minor.yy132;} break; case 268: /* when_clause ::= */ - case 287: /* key_opt ::= */ yytestcase(yyruleno==287); + case 286: /* key_opt ::= */ yytestcase(yyruleno==286); { yymsp[1].minor.yy454 = 0; } break; case 269: /* when_clause ::= WHEN expr */ - case 288: /* key_opt ::= KEY expr */ yytestcase(yyruleno==288); + case 287: /* key_opt ::= KEY expr */ yytestcase(yyruleno==287); { yymsp[-1].minor.yy454 = yymsp[0].minor.yy454; } break; case 270: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { - assert( yymsp[-2].minor.yy427!=0 ); yymsp[-2].minor.yy427->pLast->pNext = yymsp[-1].minor.yy427; yymsp[-2].minor.yy427->pLast = yymsp[-1].minor.yy427; } break; case 271: /* trigger_cmd_list ::= trigger_cmd SEMI */ { - assert( yymsp[-1].minor.yy427!=0 ); yymsp[-1].minor.yy427->pLast = yymsp[-1].minor.yy427; } break; - case 272: /* trnm ::= nm DOT nm */ -{ - yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; - sqlite3ErrorMsg(pParse, - "qualified table names are not allowed on INSERT, UPDATE, and DELETE " - "statements within triggers"); -} - break; - case 273: /* tridxby ::= INDEXED BY nm */ + case 272: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 274: /* tridxby ::= NOT INDEXED */ + case 273: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 275: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ -{yylhsminor.yy427 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy203, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454, yymsp[-7].minor.yy144, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy168);} + case 274: /* trigger_cmd ::= UPDATE orconf xfullname tridxby SET setlist from where_opt scanpt */ +{yylhsminor.yy427 = sqlite3TriggerUpdateStep(pParse, yymsp[-6].minor.yy203, yymsp[-2].minor.yy203, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454, yymsp[-7].minor.yy144, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy168);} yymsp[-8].minor.yy427 = yylhsminor.yy427; break; - case 276: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + case 275: /* trigger_cmd ::= scanpt insert_cmd INTO xfullname idlist_opt select upsert scanpt */ { - yylhsminor.yy427 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy132,yymsp[-2].minor.yy555,yymsp[-6].minor.yy144,yymsp[-1].minor.yy122,yymsp[-7].minor.yy168,yymsp[0].minor.yy168);/*yylhsminor.yy427-overwrites-yymsp[-6].minor.yy144*/ + yylhsminor.yy427 = sqlite3TriggerInsertStep(pParse,yymsp[-4].minor.yy203,yymsp[-3].minor.yy132,yymsp[-2].minor.yy555,yymsp[-6].minor.yy144,yymsp[-1].minor.yy122,yymsp[-7].minor.yy168,yymsp[0].minor.yy168);/*yylhsminor.yy427-overwrites-yymsp[-6].minor.yy144*/ } yymsp[-7].minor.yy427 = yylhsminor.yy427; break; - case 277: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ -{yylhsminor.yy427 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy454, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy168);} + case 276: /* trigger_cmd ::= DELETE FROM xfullname tridxby where_opt scanpt */ +{yylhsminor.yy427 = sqlite3TriggerDeleteStep(pParse, yymsp[-3].minor.yy203, yymsp[-1].minor.yy454, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy168);} yymsp[-5].minor.yy427 = yylhsminor.yy427; break; - case 278: /* trigger_cmd ::= scanpt select scanpt */ + case 277: /* trigger_cmd ::= scanpt select scanpt */ {yylhsminor.yy427 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy555, yymsp[-2].minor.yy168, yymsp[0].minor.yy168); /*yylhsminor.yy427-overwrites-yymsp[-1].minor.yy555*/} yymsp[-2].minor.yy427 = yylhsminor.yy427; break; - case 279: /* expr ::= RAISE LP IGNORE RP */ + case 278: /* expr ::= RAISE LP IGNORE RP */ { yymsp[-3].minor.yy454 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); if( yymsp[-3].minor.yy454 ){ @@ -178827,7 +185085,7 @@ static YYACTIONTYPE yy_reduce( } } break; - case 280: /* expr ::= RAISE LP raisetype COMMA expr RP */ + case 279: /* expr ::= RAISE LP raisetype COMMA expr RP */ { yymsp[-5].minor.yy454 = sqlite3PExpr(pParse, TK_RAISE, yymsp[-1].minor.yy454, 0); if( yymsp[-5].minor.yy454 ) { @@ -178835,48 +185093,56 @@ static YYACTIONTYPE yy_reduce( } } break; - case 281: /* raisetype ::= ROLLBACK */ + case 280: /* raisetype ::= ROLLBACK */ {yymsp[0].minor.yy144 = OE_Rollback;} break; - case 283: /* raisetype ::= FAIL */ + case 282: /* raisetype ::= FAIL */ {yymsp[0].minor.yy144 = OE_Fail;} break; - case 284: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 283: /* cmd ::= DROP TRIGGER ifexists fullname */ { sqlite3DropTrigger(pParse,yymsp[0].minor.yy203,yymsp[-1].minor.yy144); } break; - case 285: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 284: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { sqlite3Attach(pParse, yymsp[-3].minor.yy454, yymsp[-1].minor.yy454, yymsp[0].minor.yy454); } break; - case 286: /* cmd ::= DETACH database_kw_opt expr */ + case 285: /* cmd ::= DETACH database_kw_opt expr */ { sqlite3Detach(pParse, yymsp[0].minor.yy454); } break; - case 289: /* cmd ::= REINDEX */ + case 288: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 290: /* cmd ::= REINDEX nm dbnm */ + case 289: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 291: /* cmd ::= ANALYZE */ + case 290: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 292: /* cmd ::= ANALYZE nm dbnm */ + case 291: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 293: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 292: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy203,&yymsp[0].minor.yy0); } break; - case 294: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 293: /* cmd ::= alter_add carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); +} + break; + case 294: /* alter_add ::= ALTER TABLE fullname ADD kwcolumn_opt nm typetoken */ +{ + disableLookaside(pParse); + sqlite3AlterBeginAddColumn(pParse, yymsp[-4].minor.yy203); + sqlite3AddColumn(pParse, yymsp[-1].minor.yy0, yymsp[0].minor.yy0); + yymsp[-6].minor.yy0 = yymsp[-1].minor.yy0; } break; case 295: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ @@ -178884,68 +185150,87 @@ static YYACTIONTYPE yy_reduce( sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy203, &yymsp[0].minor.yy0); } break; - case 296: /* add_column_fullname ::= fullname */ + case 296: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ { - disableLookaside(pParse); - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy203); + sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy203, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); } break; - case 297: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + case 297: /* cmd ::= ALTER TABLE fullname DROP CONSTRAINT nm */ { - sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy203, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); + sqlite3AlterDropConstraint(pParse, yymsp[-3].minor.yy203, &yymsp[0].minor.yy0, 0); +} + break; + case 298: /* cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm DROP NOT NULL */ +{ + sqlite3AlterDropConstraint(pParse, yymsp[-6].minor.yy203, 0, &yymsp[-3].minor.yy0); +} + break; + case 299: /* cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm SET NOT NULL onconf */ +{ + sqlite3AlterSetNotNull(pParse, yymsp[-7].minor.yy203, &yymsp[-4].minor.yy0, &yymsp[-2].minor.yy0); +} + break; + case 300: /* cmd ::= ALTER TABLE fullname ADD CONSTRAINT nm CHECK LP expr RP onconf */ +{ + sqlite3AlterAddConstraint(pParse, yymsp[-8].minor.yy203, &yymsp[-6].minor.yy0, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1), yymsp[-2].minor.yy454); +} + break; + case 301: /* cmd ::= ALTER TABLE fullname ADD CHECK LP expr RP onconf */ +{ + sqlite3AlterAddConstraint(pParse, yymsp[-6].minor.yy203, &yymsp[-4].minor.yy0, 0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1), yymsp[-2].minor.yy454); } break; - case 298: /* cmd ::= create_vtab */ + case 302: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 299: /* cmd ::= create_vtab LP vtabarglist RP */ + case 303: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 300: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 304: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy144); } break; - case 301: /* vtabarg ::= */ + case 305: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 302: /* vtabargtoken ::= ANY */ - case 303: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==303); - case 304: /* lp ::= LP */ yytestcase(yyruleno==304); + case 306: /* vtabargtoken ::= ANY */ + case 307: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==307); + case 308: /* lp ::= LP */ yytestcase(yyruleno==308); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 305: /* with ::= WITH wqlist */ - case 306: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==306); + case 309: /* with ::= WITH wqlist */ + case 310: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==310); { sqlite3WithPush(pParse, yymsp[0].minor.yy59, 1); } break; - case 307: /* wqas ::= AS */ + case 311: /* wqas ::= AS */ {yymsp[0].minor.yy462 = M10d_Any;} break; - case 308: /* wqas ::= AS MATERIALIZED */ + case 312: /* wqas ::= AS MATERIALIZED */ {yymsp[-1].minor.yy462 = M10d_Yes;} break; - case 309: /* wqas ::= AS NOT MATERIALIZED */ + case 313: /* wqas ::= AS NOT MATERIALIZED */ {yymsp[-2].minor.yy462 = M10d_No;} break; - case 310: /* wqitem ::= withnm eidlist_opt wqas LP select RP */ + case 314: /* wqitem ::= withnm eidlist_opt wqas LP select RP */ { yymsp[-5].minor.yy67 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy555, yymsp[-3].minor.yy462); /*A-overwrites-X*/ } break; - case 311: /* withnm ::= nm */ + case 315: /* withnm ::= nm */ {pParse->bHasWith = 1;} break; - case 312: /* wqlist ::= wqitem */ + case 316: /* wqlist ::= wqitem */ { yymsp[0].minor.yy59 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy67); /*A-overwrites-X*/ } break; - case 313: /* wqlist ::= wqlist COMMA wqitem */ + case 317: /* wqlist ::= wqlist COMMA wqitem */ { yymsp[-2].minor.yy59 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy59, yymsp[0].minor.yy67); } break; - case 314: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ + case 318: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ { assert( yymsp[0].minor.yy211!=0 ); sqlite3WindowChain(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy211); @@ -178954,7 +185239,7 @@ static YYACTIONTYPE yy_reduce( } yymsp[-2].minor.yy211 = yylhsminor.yy211; break; - case 315: /* windowdefn ::= nm AS LP window RP */ + case 319: /* windowdefn ::= nm AS LP window RP */ { if( ALWAYS(yymsp[-1].minor.yy211) ){ yymsp[-1].minor.yy211->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); @@ -178963,83 +185248,83 @@ static YYACTIONTYPE yy_reduce( } yymsp[-4].minor.yy211 = yylhsminor.yy211; break; - case 316: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + case 320: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ { yymsp[-4].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, 0); } break; - case 317: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + case 321: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ { yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, &yymsp[-5].minor.yy0); } yymsp[-5].minor.yy211 = yylhsminor.yy211; break; - case 318: /* window ::= ORDER BY sortlist frame_opt */ + case 322: /* window ::= ORDER BY sortlist frame_opt */ { yymsp[-3].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, 0); } break; - case 319: /* window ::= nm ORDER BY sortlist frame_opt */ + case 323: /* window ::= nm ORDER BY sortlist frame_opt */ { yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0); } yymsp[-4].minor.yy211 = yylhsminor.yy211; break; - case 320: /* window ::= nm frame_opt */ + case 324: /* window ::= nm frame_opt */ { yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, 0, &yymsp[-1].minor.yy0); } yymsp[-1].minor.yy211 = yylhsminor.yy211; break; - case 321: /* frame_opt ::= */ + case 325: /* frame_opt ::= */ { yymsp[1].minor.yy211 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); } break; - case 322: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + case 326: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ { yylhsminor.yy211 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy144, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy462); } yymsp[-2].minor.yy211 = yylhsminor.yy211; break; - case 323: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + case 327: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ { yylhsminor.yy211 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy144, yymsp[-3].minor.yy509.eType, yymsp[-3].minor.yy509.pExpr, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, yymsp[0].minor.yy462); } yymsp[-5].minor.yy211 = yylhsminor.yy211; break; - case 325: /* frame_bound_s ::= frame_bound */ - case 327: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==327); + case 329: /* frame_bound_s ::= frame_bound */ + case 331: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==331); {yylhsminor.yy509 = yymsp[0].minor.yy509;} yymsp[0].minor.yy509 = yylhsminor.yy509; break; - case 326: /* frame_bound_s ::= UNBOUNDED PRECEDING */ - case 328: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==328); - case 330: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==330); + case 330: /* frame_bound_s ::= UNBOUNDED PRECEDING */ + case 332: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==332); + case 334: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==334); {yylhsminor.yy509.eType = yymsp[-1].major; yylhsminor.yy509.pExpr = 0;} yymsp[-1].minor.yy509 = yylhsminor.yy509; break; - case 329: /* frame_bound ::= expr PRECEDING|FOLLOWING */ + case 333: /* frame_bound ::= expr PRECEDING|FOLLOWING */ {yylhsminor.yy509.eType = yymsp[0].major; yylhsminor.yy509.pExpr = yymsp[-1].minor.yy454;} yymsp[-1].minor.yy509 = yylhsminor.yy509; break; - case 331: /* frame_exclude_opt ::= */ + case 335: /* frame_exclude_opt ::= */ {yymsp[1].minor.yy462 = 0;} break; - case 332: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ + case 336: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ {yymsp[-1].minor.yy462 = yymsp[0].minor.yy462;} break; - case 333: /* frame_exclude ::= NO OTHERS */ - case 334: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==334); + case 337: /* frame_exclude ::= NO OTHERS */ + case 338: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==338); {yymsp[-1].minor.yy462 = yymsp[-1].major; /*A-overwrites-X*/} break; - case 335: /* frame_exclude ::= GROUP|TIES */ + case 339: /* frame_exclude ::= GROUP|TIES */ {yymsp[0].minor.yy462 = yymsp[0].major; /*A-overwrites-X*/} break; - case 336: /* window_clause ::= WINDOW windowdefn_list */ + case 340: /* window_clause ::= WINDOW windowdefn_list */ { yymsp[-1].minor.yy211 = yymsp[0].minor.yy211; } break; - case 337: /* filter_over ::= filter_clause over_clause */ + case 341: /* filter_over ::= filter_clause over_clause */ { if( yymsp[0].minor.yy211 ){ yymsp[0].minor.yy211->pFilter = yymsp[-1].minor.yy454; @@ -179050,13 +185335,13 @@ static YYACTIONTYPE yy_reduce( } yymsp[-1].minor.yy211 = yylhsminor.yy211; break; - case 338: /* filter_over ::= over_clause */ + case 342: /* filter_over ::= over_clause */ { yylhsminor.yy211 = yymsp[0].minor.yy211; } yymsp[0].minor.yy211 = yylhsminor.yy211; break; - case 339: /* filter_over ::= filter_clause */ + case 343: /* filter_over ::= filter_clause */ { yylhsminor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( yylhsminor.yy211 ){ @@ -179068,13 +185353,13 @@ static YYACTIONTYPE yy_reduce( } yymsp[0].minor.yy211 = yylhsminor.yy211; break; - case 340: /* over_clause ::= OVER LP window RP */ + case 344: /* over_clause ::= OVER LP window RP */ { yymsp[-3].minor.yy211 = yymsp[-1].minor.yy211; assert( yymsp[-3].minor.yy211!=0 ); } break; - case 341: /* over_clause ::= OVER nm */ + case 345: /* over_clause ::= OVER nm */ { yymsp[-1].minor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( yymsp[-1].minor.yy211 ){ @@ -179082,10 +185367,10 @@ static YYACTIONTYPE yy_reduce( } } break; - case 342: /* filter_clause ::= FILTER LP WHERE expr RP */ + case 346: /* filter_clause ::= FILTER LP WHERE expr RP */ { yymsp[-4].minor.yy454 = yymsp[-1].minor.yy454; } break; - case 343: /* term ::= QNUMBER */ + case 347: /* term ::= QNUMBER */ { yylhsminor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); sqlite3DequoteNumber(pParse, yylhsminor.yy454); @@ -179093,71 +185378,70 @@ static YYACTIONTYPE yy_reduce( yymsp[0].minor.yy454 = yylhsminor.yy454; break; default: - /* (344) input ::= cmdlist */ yytestcase(yyruleno==344); - /* (345) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==345); - /* (346) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=346); - /* (347) ecmd ::= SEMI */ yytestcase(yyruleno==347); - /* (348) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==348); - /* (349) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=349); - /* (350) trans_opt ::= */ yytestcase(yyruleno==350); - /* (351) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==351); - /* (352) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==352); - /* (353) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==353); - /* (354) savepoint_opt ::= */ yytestcase(yyruleno==354); - /* (355) cmd ::= create_table create_table_args */ yytestcase(yyruleno==355); - /* (356) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=356); - /* (357) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==357); - /* (358) columnlist ::= columnname carglist */ yytestcase(yyruleno==358); - /* (359) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==359); - /* (360) nm ::= STRING */ yytestcase(yyruleno==360); - /* (361) typetoken ::= typename */ yytestcase(yyruleno==361); - /* (362) typename ::= ID|STRING */ yytestcase(yyruleno==362); - /* (363) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=363); - /* (364) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=364); - /* (365) carglist ::= carglist ccons */ yytestcase(yyruleno==365); - /* (366) carglist ::= */ yytestcase(yyruleno==366); - /* (367) ccons ::= NULL onconf */ yytestcase(yyruleno==367); - /* (368) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==368); - /* (369) ccons ::= AS generated */ yytestcase(yyruleno==369); - /* (370) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==370); - /* (371) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==371); - /* (372) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=372); - /* (373) tconscomma ::= */ yytestcase(yyruleno==373); - /* (374) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=374); - /* (375) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=375); - /* (376) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=376); - /* (377) oneselect ::= values */ yytestcase(yyruleno==377); - /* (378) sclp ::= selcollist COMMA */ yytestcase(yyruleno==378); - /* (379) as ::= ID|STRING */ yytestcase(yyruleno==379); - /* (380) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=380); - /* (381) returning ::= */ yytestcase(yyruleno==381); - /* (382) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=382); - /* (383) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==383); - /* (384) case_operand ::= expr */ yytestcase(yyruleno==384); - /* (385) exprlist ::= nexprlist */ yytestcase(yyruleno==385); - /* (386) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=386); - /* (387) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=387); - /* (388) nmnum ::= ON */ yytestcase(yyruleno==388); - /* (389) nmnum ::= DELETE */ yytestcase(yyruleno==389); - /* (390) nmnum ::= DEFAULT */ yytestcase(yyruleno==390); - /* (391) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==391); - /* (392) foreach_clause ::= */ yytestcase(yyruleno==392); - /* (393) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==393); - /* (394) trnm ::= nm */ yytestcase(yyruleno==394); - /* (395) tridxby ::= */ yytestcase(yyruleno==395); - /* (396) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==396); - /* (397) database_kw_opt ::= */ yytestcase(yyruleno==397); - /* (398) kwcolumn_opt ::= */ yytestcase(yyruleno==398); - /* (399) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==399); - /* (400) vtabarglist ::= vtabarg */ yytestcase(yyruleno==400); - /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==401); - /* (402) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==402); - /* (403) anylist ::= */ yytestcase(yyruleno==403); - /* (404) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==404); - /* (405) anylist ::= anylist ANY */ yytestcase(yyruleno==405); - /* (406) with ::= */ yytestcase(yyruleno==406); - /* (407) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=407); - /* (408) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=408); + /* (348) input ::= cmdlist */ yytestcase(yyruleno==348); + /* (349) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==349); + /* (350) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=350); + /* (351) ecmd ::= SEMI */ yytestcase(yyruleno==351); + /* (352) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==352); + /* (353) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=353); + /* (354) trans_opt ::= */ yytestcase(yyruleno==354); + /* (355) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==355); + /* (356) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==356); + /* (357) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==357); + /* (358) savepoint_opt ::= */ yytestcase(yyruleno==358); + /* (359) cmd ::= create_table create_table_args */ yytestcase(yyruleno==359); + /* (360) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=360); + /* (361) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==361); + /* (362) columnlist ::= columnname carglist */ yytestcase(yyruleno==362); + /* (363) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==363); + /* (364) nm ::= STRING */ yytestcase(yyruleno==364); + /* (365) typetoken ::= typename */ yytestcase(yyruleno==365); + /* (366) typename ::= ID|STRING */ yytestcase(yyruleno==366); + /* (367) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=367); + /* (368) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=368); + /* (369) carglist ::= carglist ccons */ yytestcase(yyruleno==369); + /* (370) carglist ::= */ yytestcase(yyruleno==370); + /* (371) ccons ::= NULL onconf */ yytestcase(yyruleno==371); + /* (372) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==372); + /* (373) ccons ::= AS generated */ yytestcase(yyruleno==373); + /* (374) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==374); + /* (375) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==375); + /* (376) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=376); + /* (377) tconscomma ::= */ yytestcase(yyruleno==377); + /* (378) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=378); + /* (379) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=379); + /* (380) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=380); + /* (381) oneselect ::= values */ yytestcase(yyruleno==381); + /* (382) sclp ::= selcollist COMMA */ yytestcase(yyruleno==382); + /* (383) as ::= ID|STRING */ yytestcase(yyruleno==383); + /* (384) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=384); + /* (385) returning ::= */ yytestcase(yyruleno==385); + /* (386) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=386); + /* (387) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==387); + /* (388) case_operand ::= expr */ yytestcase(yyruleno==388); + /* (389) exprlist ::= nexprlist */ yytestcase(yyruleno==389); + /* (390) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=390); + /* (391) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=391); + /* (392) nmnum ::= ON */ yytestcase(yyruleno==392); + /* (393) nmnum ::= DELETE */ yytestcase(yyruleno==393); + /* (394) nmnum ::= DEFAULT */ yytestcase(yyruleno==394); + /* (395) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==395); + /* (396) foreach_clause ::= */ yytestcase(yyruleno==396); + /* (397) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==397); + /* (398) tridxby ::= */ yytestcase(yyruleno==398); + /* (399) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==399); + /* (400) database_kw_opt ::= */ yytestcase(yyruleno==400); + /* (401) kwcolumn_opt ::= */ yytestcase(yyruleno==401); + /* (402) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==402); + /* (403) vtabarglist ::= vtabarg */ yytestcase(yyruleno==403); + /* (404) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==404); + /* (405) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==405); + /* (406) anylist ::= */ yytestcase(yyruleno==406); + /* (407) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==407); + /* (408) anylist ::= anylist ANY */ yytestcase(yyruleno==408); + /* (409) with ::= */ yytestcase(yyruleno==409); + /* (410) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=410); + /* (411) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=411); break; /********** End reduce actions ************************************************/ }; @@ -179220,7 +185504,7 @@ static void yy_syntax_error( UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */ if( TOKEN.z[0] ){ - sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); + parserSyntaxError(pParse, &TOKEN); }else{ sqlite3ErrorMsg(pParse, "incomplete input"); } @@ -179936,8 +186220,8 @@ static const unsigned char aKWCode[148] = {0, /* Check to see if z[0..n-1] is a keyword. If it is, write the ** parser symbol code for that keyword into *pType. Always ** return the integer n (the length of the token). */ -static int keywordCode(const char *z, int n, int *pType){ - int i, j; +static i64 keywordCode(const char *z, i64 n, int *pType){ + i64 i, j; const char *zKW; assert( n>=2 ); i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127; @@ -180182,7 +186466,7 @@ static int getToken(const unsigned char **pz){ int t; /* Token type to return */ do { z += sqlite3GetToken(z, &t); - }while( t==TK_SPACE ); + }while( t==TK_SPACE || t==TK_COMMENT ); if( t==TK_ID || t==TK_STRING || t==TK_JOIN_KW @@ -180253,8 +186537,9 @@ static int analyzeFilterKeyword(const unsigned char *z, int lastToken){ ** Return the length (in bytes) of the token that begins at z[0]. ** Store the token type in *tokenType before returning. */ -SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ - int i, c; +SQLITE_PRIVATE i64 sqlite3GetToken(const unsigned char *z, int *tokenType){ + i64 i; + int c; switch( aiClass[*z] ){ /* Switch on the character-class of the first byte ** of the token. See the comment on the CC_ defines ** above. */ @@ -180271,7 +186556,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ case CC_MINUS: { if( z[1]=='-' ){ for(i=2; (c=z[i])!=0 && c!='\n'; i++){} - *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ + *tokenType = TK_COMMENT; return i; }else if( z[1]=='>' ){ *tokenType = TK_PTR; @@ -180307,7 +186592,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ } for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){} if( c ) i++; - *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ + *tokenType = TK_COMMENT; return i; } case CC_PERCENT: { @@ -180490,7 +186775,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ } case CC_DOLLAR: case CC_VARALPHA: { - int n = 0; + i64 n = 0; testcase( z[0]=='$' ); testcase( z[0]=='@' ); testcase( z[0]==':' ); testcase( z[0]=='#' ); *tokenType = TK_VARIABLE; @@ -180582,11 +186867,11 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){ int nErr = 0; /* Number of errors encountered */ void *pEngine; /* The LEMON-generated LALR(1) parser */ - int n = 0; /* Length of the next token token */ + i64 n = 0; /* Length of the next token token */ int tokenType; /* type of the next token */ int lastTokenParsed = -1; /* type of the previous token */ sqlite3 *db = pParse->db; /* The database connection */ - int mxSqlLen; /* Max length of an SQL string */ + i64 mxSqlLen; /* Max length of an SQL string */ Parse *pParentParse = 0; /* Outer parse context, if any */ #ifdef sqlite3Parser_ENGINEALWAYSONSTACK yyParser sEngine; /* Space to hold the Lemon-generated Parser object */ @@ -180636,12 +186921,12 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){ if( tokenType>=TK_WINDOW ){ assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW - || tokenType==TK_QNUMBER + || tokenType==TK_QNUMBER || tokenType==TK_COMMENT ); #else if( tokenType>=TK_SPACE ){ assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL - || tokenType==TK_QNUMBER + || tokenType==TK_QNUMBER || tokenType==TK_COMMENT ); #endif /* SQLITE_OMIT_WINDOWFUNC */ if( AtomicLoad(&db->u1.isInterrupted) ){ @@ -180675,16 +186960,23 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){ assert( n==6 ); tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed); #endif /* SQLITE_OMIT_WINDOWFUNC */ + }else if( tokenType==TK_COMMENT + && (db->init.busy || (db->flags & SQLITE_Comments)!=0) + ){ + /* Ignore SQL comments if either (1) we are reparsing the schema or + ** (2) SQLITE_DBCONFIG_ENABLE_COMMENTS is turned on (the default). */ + zSql += n; + continue; }else if( tokenType!=TK_QNUMBER ){ Token x; x.z = zSql; - x.n = n; + x.n = (u32)n; sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", &x); break; } } pParse->sLastToken.z = zSql; - pParse->sLastToken.n = n; + pParse->sLastToken.n = (u32)n; sqlite3Parser(pEngine, tokenType, pParse->sLastToken); lastTokenParsed = tokenType; zSql += n; @@ -180709,9 +187001,11 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){ } if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){ if( pParse->zErrMsg==0 ){ - pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc)); + pParse->zErrMsg = sqlite3DbStrDup(db, sqlite3ErrStr(pParse->rc)); + } + if( (pParse->prepFlags & SQLITE_PREPARE_DONT_LOG)==0 ){ + sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail); } - sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail); nErr++; } pParse->zTail = zSql; @@ -180758,7 +187052,7 @@ SQLITE_PRIVATE char *sqlite3Normalize( ){ sqlite3 *db; /* The database connection */ int i; /* Next unread byte of zSql[] */ - int n; /* length of current token */ + i64 n; /* length of current token */ int tokenType; /* type of current token */ int prevType = 0; /* Previous non-whitespace token */ int nParen; /* Number of nested levels of parentheses */ @@ -180779,6 +187073,7 @@ SQLITE_PRIVATE char *sqlite3Normalize( n = sqlite3GetToken((unsigned char*)zSql+i, &tokenType); if( NEVER(n<=0) ) break; switch( tokenType ){ + case TK_COMMENT: case TK_SPACE: { break; } @@ -180787,7 +187082,7 @@ SQLITE_PRIVATE char *sqlite3Normalize( sqlite3_str_append(pStr, " NULL", 5); break; } - /* Fall through */ + /* no break */ deliberate_fall_through } case TK_STRING: case TK_INTEGER: @@ -180851,7 +187146,7 @@ SQLITE_PRIVATE char *sqlite3Normalize( } case TK_SELECT: { iStartIN = 0; - /* fall through */ + /* no break */ deliberate_fall_through } default: { if( sqlite3IsIdChar(zSql[i]) ) addSpaceSeparator(pStr); @@ -181335,9 +187630,6 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { sqlite3DbstatRegister, #endif sqlite3TestExtInit, -#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) - sqlite3JsonTableFunctions, -#endif #ifdef SQLITE_ENABLE_STMTVTAB sqlite3StmtVtabInit, #endif @@ -181347,6 +187639,7 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { #ifdef SQLITE_EXTRA_AUTOEXT SQLITE_EXTRA_AUTOEXT, #endif + sqlite3mc_builtin_extensions, }; #ifndef SQLITE_AMALGAMATION @@ -181564,6 +187857,16 @@ SQLITE_API int sqlite3_initialize(void){ if( rc==SQLITE_OK ){ sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage, sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage); + int sqlite3mc_initialize(const char*); + rc = sqlite3mc_initialize(0); +#ifdef SQLITE_EXTRA_INIT_MUTEXED + { + int SQLITE_EXTRA_INIT_MUTEXED(const char*); + rc = SQLITE_EXTRA_INIT_MUTEXED(0); + } +#endif + } + if( rc==SQLITE_OK ){ sqlite3MemoryBarrier(); sqlite3GlobalConfig.isInit = 1; #ifdef SQLITE_EXTRA_INIT @@ -181638,6 +187941,8 @@ SQLITE_API int sqlite3_shutdown(void){ void SQLITE_EXTRA_SHUTDOWN(void); SQLITE_EXTRA_SHUTDOWN(); #endif + void sqlite3mc_shutdown(void); + sqlite3mc_shutdown(); sqlite3_os_end(); sqlite3_reset_auto_extension(); sqlite3GlobalConfig.isInit = 0; @@ -182020,17 +188325,22 @@ SQLITE_API int sqlite3_config(int op, ...){ ** If lookaside is already active, return SQLITE_BUSY. ** ** The sz parameter is the number of bytes in each lookaside slot. -** The cnt parameter is the number of slots. If pStart is NULL the -** space for the lookaside memory is obtained from sqlite3_malloc(). -** If pStart is not NULL then it is sz*cnt bytes of memory to use for -** the lookaside memory. +** The cnt parameter is the number of slots. If pBuf is NULL the +** space for the lookaside memory is obtained from sqlite3_malloc() +** or similar. If pBuf is not NULL then it is sz*cnt bytes of memory +** to use for the lookaside memory. */ -static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ +static int setupLookaside( + sqlite3 *db, /* Database connection being configured */ + void *pBuf, /* Memory to use for lookaside. May be NULL */ + int sz, /* Desired size of each lookaside memory slot */ + int cnt /* Number of slots to allocate */ +){ #ifndef SQLITE_OMIT_LOOKASIDE - void *pStart; - sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt; - int nBig; /* Number of full-size slots */ - int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */ + void *pStart; /* Start of the lookaside buffer */ + sqlite3_int64 szAlloc; /* Total space set aside for lookaside memory */ + int nBig; /* Number of full-size slots */ + int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */ if( sqlite3LookasideUsed(db,0)>0 ){ return SQLITE_BUSY; @@ -182043,17 +188353,22 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ sqlite3_free(db->lookaside.pStart); } /* The size of a lookaside slot after ROUNDDOWN8 needs to be larger - ** than a pointer to be useful. + ** than a pointer and small enough to fit in a u16. */ - sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */ + sz = ROUNDDOWN8(sz); if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0; - if( cnt<0 ) cnt = 0; - if( sz==0 || cnt==0 ){ + if( sz>65528 ) sz = 65528; + /* Count must be at least 1 to be useful, but not so large as to use + ** more than 0x7fff0000 total bytes for lookaside. */ + if( cnt<1 ) cnt = 0; + if( sz>0 && cnt>(0x7fff0000/sz) ) cnt = 0x7fff0000/sz; + szAlloc = (i64)sz*(i64)cnt; + if( szAlloc==0 ){ sz = 0; pStart = 0; }else if( pBuf==0 ){ sqlite3BeginBenignMalloc(); - pStart = sqlite3Malloc( szAlloc ); /* IMP: R-61949-35727 */ + pStart = sqlite3Malloc( szAlloc ); sqlite3EndBenignMalloc(); if( pStart ) szAlloc = sqlite3MallocSize(pStart); }else{ @@ -182062,10 +188377,10 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE if( sz>=LOOKASIDE_SMALL*3 ){ nBig = szAlloc/(3*LOOKASIDE_SMALL+sz); - nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL; + nSm = (szAlloc - (i64)sz*(i64)nBig)/LOOKASIDE_SMALL; }else if( sz>=LOOKASIDE_SMALL*2 ){ nBig = szAlloc/(LOOKASIDE_SMALL+sz); - nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL; + nSm = (szAlloc - (i64)sz*(i64)nBig)/LOOKASIDE_SMALL; }else #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ if( sz>0 ){ @@ -182217,10 +188532,18 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ rc = setupLookaside(db, pBuf, sz, cnt); break; } + case SQLITE_DBCONFIG_FP_DIGITS: { + int nIn = va_arg(ap, int); + int *pOut = va_arg(ap, int*); + if( nIn>3 && nIn<24 ) db->nFpDigit = (u8)nIn; + if( pOut ) *pOut = db->nFpDigit; + rc = SQLITE_OK; + break; + } default: { static const struct { int op; /* The opcode */ - u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */ + u64 mask; /* Mask of the bit in sqlite3.flags to set/clear */ } aFlagOp[] = { { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys }, { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger }, @@ -182241,6 +188564,9 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ { SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema }, { SQLITE_DBCONFIG_STMT_SCANSTATUS, SQLITE_StmtScanStatus }, { SQLITE_DBCONFIG_REVERSE_SCANORDER, SQLITE_ReverseOrder }, + { SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE, SQLITE_AttachCreate }, + { SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE, SQLITE_AttachWrite }, + { SQLITE_DBCONFIG_ENABLE_COMMENTS, SQLITE_Comments }, }; unsigned int i; rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ @@ -182346,13 +188672,17 @@ static int nocaseCollatingFunc( ** Return the ROWID of the most recent insert */ SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){ + i64 iRet; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - return db->lastRowid; + sqlite3_mutex_enter(db->mutex); + iRet = db->lastRowid; + sqlite3_mutex_leave(db->mutex); + return iRet; } /* @@ -182374,13 +188704,17 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid) ** Return the number of changes in the most recent call to sqlite3_exec(). */ SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3 *db){ + i64 iRet; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - return db->nChange; + sqlite3_mutex_enter(db->mutex); + iRet = db->nChange; + sqlite3_mutex_leave(db->mutex); + return iRet; } SQLITE_API int sqlite3_changes(sqlite3 *db){ return (int)sqlite3_changes64(db); @@ -182390,13 +188724,17 @@ SQLITE_API int sqlite3_changes(sqlite3 *db){ ** Return the number of changes since the database handle was opened. */ SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3 *db){ + i64 iRet; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - return db->nTotalChange; + sqlite3_mutex_enter(db->mutex); + iRet = db->nTotalChange; + sqlite3_mutex_leave(db->mutex); + return iRet; } SQLITE_API int sqlite3_total_changes(sqlite3 *db){ return (int)sqlite3_total_changes64(db); @@ -182637,6 +188975,7 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ /* Clear the TEMP schema separately and last */ if( db->aDb[1].pSchema ){ sqlite3SchemaClear(db->aDb[1].pSchema); + assert( db->aDb[1].pSchema->trigHash.count==0 ); } sqlite3VtabUnlockList(db); @@ -182684,10 +189023,6 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ sqlite3ValueFree(db->pErr); sqlite3CloseExtensions(db); -#if SQLITE_USER_AUTHENTICATION - sqlite3_free(db->auth.zAuthUser); - sqlite3_free(db->auth.zAuthPW); -#endif db->eOpenState = SQLITE_STATE_ERROR; @@ -182776,6 +189111,9 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){ case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; case SQLITE_ERROR_SNAPSHOT: zName = "SQLITE_ERROR_SNAPSHOT"; break; + case SQLITE_ERROR_RETRY: zName = "SQLITE_ERROR_RETRY"; break; + case SQLITE_ERROR_MISSING_COLLSEQ: + zName = "SQLITE_ERROR_MISSING_COLLSEQ"; break; case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; case SQLITE_PERM: zName = "SQLITE_PERM"; break; case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; @@ -183031,6 +189369,9 @@ SQLITE_API int sqlite3_busy_handler( db->busyHandler.pBusyArg = pArg; db->busyHandler.nBusy = 0; db->busyTimeout = 0; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + db->setlkTimeout = 0; +#endif sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -183076,13 +189417,52 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif + sqlite3_mutex_enter(db->mutex); if( ms>0 ){ sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback, (void*)db); db->busyTimeout = ms; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + db->setlkTimeout = ms; +#endif }else{ sqlite3_busy_handler(db, 0, 0); } + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +/* +** Set the setlk timeout value. +*/ +SQLITE_API int sqlite3_setlk_timeout(sqlite3 *db, int ms, int flags){ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + int iDb; + int bBOC = ((flags & SQLITE_SETLK_BLOCK_ON_CONNECT) ? 1 : 0); +#endif +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + if( ms<-1 ) return SQLITE_RANGE; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + sqlite3_mutex_enter(db->mutex); + db->setlkTimeout = ms; + db->setlkFlags = flags; + sqlite3BtreeEnterAll(db); + for(iDb=0; iDbnDb; iDb++){ + Btree *pBt = db->aDb[iDb].pBt; + if( pBt ){ + sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pBt)); + sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, (void*)&bBOC); + } + } + sqlite3BtreeLeaveAll(db); + sqlite3_mutex_leave(db->mutex); +#endif +#if !defined(SQLITE_ENABLE_API_ARMOR) && !defined(SQLITE_ENABLE_SETLK_TIMEOUT) + UNUSED_PARAMETER(db); + UNUSED_PARAMETER(flags); +#endif return SQLITE_OK; } @@ -183729,6 +190109,9 @@ SQLITE_API void *sqlite3_wal_hook( sqlite3_mutex_leave(db->mutex); return pRet; #else + UNUSED_PARAMETER(db); + UNUSED_PARAMETER(xCallback); + UNUSED_PARAMETER(pArg); return 0; #endif } @@ -183744,6 +190127,11 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( int *pnCkpt /* OUT: Total number of frames checkpointed */ ){ #ifdef SQLITE_OMIT_WAL + UNUSED_PARAMETER(db); + UNUSED_PARAMETER(zDb); + UNUSED_PARAMETER(eMode); + UNUSED_PARAMETER(pnLog); + UNUSED_PARAMETER(pnCkpt); return SQLITE_OK; #else int rc; /* Return code */ @@ -183757,11 +190145,12 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( if( pnLog ) *pnLog = -1; if( pnCkpt ) *pnCkpt = -1; + assert( SQLITE_CHECKPOINT_NOOP==-1 ); assert( SQLITE_CHECKPOINT_PASSIVE==0 ); assert( SQLITE_CHECKPOINT_FULL==1 ); assert( SQLITE_CHECKPOINT_RESTART==2 ); assert( SQLITE_CHECKPOINT_TRUNCATE==3 ); - if( eModeSQLITE_CHECKPOINT_TRUNCATE ){ + if( eModeSQLITE_CHECKPOINT_TRUNCATE ){ /* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint ** mode: */ return SQLITE_MISUSE_BKPT; @@ -183917,14 +190306,39 @@ SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){ return z; } +/* +** Set the error code and error message associated with the database handle. +** +** This routine is intended to be called by outside extensions (ex: the +** Session extension). Internal logic should invoke sqlite3Error() or +** sqlite3ErrorWithMsg() directly. +*/ +SQLITE_API int sqlite3_set_errmsg(sqlite3 *db, int errcode, const char *zMsg){ + int rc = SQLITE_OK; + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } + sqlite3_mutex_enter(db->mutex); + if( zMsg ){ + sqlite3ErrorWithMsg(db, errcode, "%s", zMsg); + }else{ + sqlite3Error(db, errcode); + } + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + /* ** Return the byte offset of the most recent error */ SQLITE_API int sqlite3_error_offset(sqlite3 *db){ int iOffset = -1; - if( db && sqlite3SafetyCheckSickOrOk(db) && db->errCode ){ + if( db && sqlite3SafetyCheckSickOrOk(db) ){ sqlite3_mutex_enter(db->mutex); - iOffset = db->errByteOffset; + if( db->errCode ){ + iOffset = db->errByteOffset; + } sqlite3_mutex_leave(db->mutex); } return iOffset; @@ -183978,25 +190392,43 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){ ** passed to this function, we assume a malloc() failed during sqlite3_open(). */ SQLITE_API int sqlite3_errcode(sqlite3 *db){ - if( db && !sqlite3SafetyCheckSickOrOk(db) ){ + int iRet; + if( !db ) return SQLITE_NOMEM_BKPT; + if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } - if( !db || db->mallocFailed ){ - return SQLITE_NOMEM_BKPT; + sqlite3_mutex_enter(db->mutex); + if( db->mallocFailed ){ + iRet = SQLITE_NOMEM_BKPT; + }else{ + iRet = db->errCode & db->errMask; } - return db->errCode & db->errMask; + sqlite3_mutex_leave(db->mutex); + return iRet; } SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){ - if( db && !sqlite3SafetyCheckSickOrOk(db) ){ + int iRet; + if( !db ) return SQLITE_NOMEM_BKPT; + if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } - if( !db || db->mallocFailed ){ - return SQLITE_NOMEM_BKPT; + sqlite3_mutex_enter(db->mutex); + if( db->mallocFailed ){ + iRet = SQLITE_NOMEM_BKPT; + }else{ + iRet = db->errCode; } - return db->errCode; + sqlite3_mutex_leave(db->mutex); + return iRet; } SQLITE_API int sqlite3_system_errno(sqlite3 *db){ - return db ? db->iSysErrno : 0; + int iRet = 0; + if( db ){ + sqlite3_mutex_enter(db->mutex); + iRet = db->iSysErrno; + sqlite3_mutex_leave(db->mutex); + } + return iRet; } /* @@ -184102,6 +190534,7 @@ static const int aHardLimit[] = { SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ SQLITE_MAX_TRIGGER_DEPTH, SQLITE_MAX_WORKER_THREADS, + SQLITE_MAX_PARSER_DEPTH, }; /* @@ -184116,14 +190549,17 @@ static const int aHardLimit[] = { #if SQLITE_MAX_SQL_LENGTH>SQLITE_MAX_LENGTH # error SQLITE_MAX_SQL_LENGTH must not be greater than SQLITE_MAX_LENGTH #endif +#if SQLITE_MAX_SQL_LENGTH>2147482624 /* 1024 less than 2^31 */ +# error SQLITE_MAX_SQL_LENGTH must not be greater than 2147482624 +#endif #if SQLITE_MAX_COMPOUND_SELECT<2 # error SQLITE_MAX_COMPOUND_SELECT must be at least 2 #endif #if SQLITE_MAX_VDBE_OP<40 # error SQLITE_MAX_VDBE_OP must be at least 40 #endif -#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127 -# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127 +#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>32767 +# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 32767 #endif #if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125 # error SQLITE_MAX_ATTACHED must be between 0 and 125 @@ -184171,6 +190607,7 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ assert( aHardLimit[SQLITE_LIMIT_SQL_LENGTH]==SQLITE_MAX_SQL_LENGTH ); assert( aHardLimit[SQLITE_LIMIT_COLUMN]==SQLITE_MAX_COLUMN ); assert( aHardLimit[SQLITE_LIMIT_EXPR_DEPTH]==SQLITE_MAX_EXPR_DEPTH ); + assert( aHardLimit[SQLITE_LIMIT_PARSER_DEPTH]==SQLITE_MAX_PARSER_DEPTH ); assert( aHardLimit[SQLITE_LIMIT_COMPOUND_SELECT]==SQLITE_MAX_COMPOUND_SELECT); assert( aHardLimit[SQLITE_LIMIT_VDBE_OP]==SQLITE_MAX_VDBE_OP ); assert( aHardLimit[SQLITE_LIMIT_FUNCTION_ARG]==SQLITE_MAX_FUNCTION_ARG ); @@ -184180,21 +190617,23 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER); assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH ); assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS ); - assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-1) ); + assert( SQLITE_LIMIT_PARSER_DEPTH==(SQLITE_N_LIMIT-1) ); if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ return -1; } + sqlite3_mutex_enter(db->mutex); oldLimit = db->aLimit[limitId]; if( newLimit>=0 ){ /* IMP: R-52476-28732 */ if( newLimit>aHardLimit[limitId] ){ newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */ - }else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){ - newLimit = 1; + }else if( newLimitaLimit[limitId] = newLimit; } + sqlite3_mutex_leave(db->mutex); return oldLimit; /* IMP: R-53341-35419 */ } @@ -184237,7 +190676,7 @@ SQLITE_PRIVATE int sqlite3ParseUri( const char *zVfs = zDefaultVfs; char *zFile; char c; - int nUri = sqlite3Strlen30(zUri); + i64 nUri = strlen(zUri); assert( *pzErrMsg==0 ); @@ -184247,8 +190686,8 @@ SQLITE_PRIVATE int sqlite3ParseUri( ){ char *zOpt; int eState; /* Parser state when parsing URI */ - int iIn; /* Input character index */ - int iOut = 0; /* Output character index */ + i64 iIn; /* Input character index */ + i64 iOut = 0; /* Output character index */ u64 nByte = nUri+8; /* Bytes of space to allocate */ /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen @@ -184282,7 +190721,7 @@ SQLITE_PRIVATE int sqlite3ParseUri( while( zUri[iIn] && zUri[iIn]!='/' ) iIn++; if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){ *pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s", - iIn-7, &zUri[7]); + (int)(iIn-7), &zUri[7]); rc = SQLITE_ERROR; goto parse_uri_out; } @@ -184357,11 +190796,11 @@ SQLITE_PRIVATE int sqlite3ParseUri( ** here. Options that are interpreted here include "vfs" and those that ** correspond to flags that may be passed to the sqlite3_open_v2() ** method. */ - zOpt = &zFile[sqlite3Strlen30(zFile)+1]; + zOpt = &zFile[strlen(zFile)+1]; while( zOpt[0] ){ - int nOpt = sqlite3Strlen30(zOpt); + i64 nOpt = strlen(zOpt); char *zVal = &zOpt[nOpt+1]; - int nVal = sqlite3Strlen30(zVal); + i64 nVal = strlen(zVal); if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){ zVfs = zVal; @@ -184407,7 +190846,7 @@ SQLITE_PRIVATE int sqlite3ParseUri( int mode = 0; for(i=0; aMode[i].z; i++){ const char *z = aMode[i].z; - if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){ + if( nVal==(i64)strlen(z) && 0==memcmp(zVal, z, nVal) ){ mode = aMode[i].mode; break; } @@ -184547,7 +190986,7 @@ static int openDatabase( db = sqlite3MallocZero( sizeof(sqlite3) ); if( db==0 ) goto opendb_out; if( isThreadsafe -#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +#if defined(SQLITE_THREAD_MISUSE_WARNINGS) || sqlite3GlobalConfig.bCoreMutex #endif ){ @@ -184568,6 +191007,7 @@ static int openDatabase( db->aDb = db->aDbStatic; db->lookaside.bDisable = 1; db->lookaside.sz = 0; + db->nFpDigit = 17; assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); @@ -184589,6 +191029,9 @@ static int openDatabase( | SQLITE_EnableTrigger | SQLITE_EnableView | SQLITE_CacheSpill + | SQLITE_AttachCreate + | SQLITE_AttachWrite + | SQLITE_Comments #if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0 | SQLITE_TrustedSchema #endif @@ -185015,6 +191458,12 @@ SQLITE_API int sqlite3_collation_needed16( */ SQLITE_API void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){ DbClientData *p; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zName || !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif sqlite3_mutex_enter(db->mutex); for(p=db->pDbData; p; p=p->pNext){ if( strcmp(p->zName, zName)==0 ){ @@ -185056,7 +191505,7 @@ SQLITE_API int sqlite3_set_clientdata( return SQLITE_OK; }else{ size_t n = strlen(zName); - p = sqlite3_malloc64( sizeof(DbClientData)+n+1 ); + p = sqlite3_malloc64( SZ_DBCLIENTDATA(n+1) ); if( p==0 ){ if( xDestructor ) xDestructor(pData); sqlite3_mutex_leave(db->mutex); @@ -185090,13 +191539,17 @@ SQLITE_API int sqlite3_global_recover(void){ ** by the next COMMIT or ROLLBACK. */ SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){ + int iRet; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - return db->autoCommit; + sqlite3_mutex_enter(db->mutex); + iRet = db->autoCommit; + sqlite3_mutex_leave(db->mutex); + return iRet; } /* @@ -185210,13 +191663,10 @@ SQLITE_API int sqlite3_table_column_metadata( if( zColumnName==0 ){ /* Query for existence of table only */ }else{ - for(iCol=0; iColnCol; iCol++){ + iCol = sqlite3ColumnIndex(pTab, zColumnName); + if( iCol>=0 ){ pCol = &pTab->aCol[iCol]; - if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){ - break; - } - } - if( iCol==pTab->nCol ){ + }else{ if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){ iCol = pTab->iPKey; pCol = iCol>=0 ? &pTab->aCol[iCol] : 0; @@ -185425,8 +191875,8 @@ SQLITE_API int sqlite3_test_control(int op, ...){ /* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b); ** ** If b is true, then activate the SQLITE_FkNoAction setting. If b is - ** false then clearn that setting. If the SQLITE_FkNoAction setting is - ** abled, all foreign key ON DELETE and ON UPDATE actions behave as if + ** false then clear that setting. If the SQLITE_FkNoAction setting is + ** enabled, all foreign key ON DELETE and ON UPDATE actions behave as if ** they were NO ACTION, regardless of how they are defined. ** ** NB: One must usually run "PRAGMA writable_schema=RESET" after @@ -185543,7 +191993,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){ /* Invoke these debugging routines so that the compiler does not ** issue "defined but not used" warnings. */ if( x==9999 ){ - sqlite3ShowExpr(0); sqlite3ShowExpr(0); sqlite3ShowExprList(0); sqlite3ShowIdList(0); @@ -185750,13 +192199,15 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } - /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum); + /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, mode, tnum); ** ** This test control is used to create imposter tables. "db" is a pointer ** to the database connection. dbName is the database name (ex: "main" or - ** "temp") which will receive the imposter. "onOff" turns imposter mode on - ** or off. "tnum" is the root page of the b-tree to which the imposter - ** table should connect. + ** "temp") which will receive the imposter. "mode" turns imposter mode on + ** or off. mode==0 means imposter mode is off. mode==1 means imposter mode + ** is on. mode==2 means imposter mode is on but results in an imposter + ** table that is read-only unless writable_schema is on. "tnum" is the + ** root page of the b-tree to which the imposter table should connect. ** ** Enable imposter mode only when the schema has already been parsed. Then ** run a single CREATE TABLE statement to construct the imposter table in @@ -185874,6 +192325,17 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } + /* sqlite3_test_control(SQLITE_TESTCTRL_ATOF, const char *z, double *p); + ** + ** Test access to the sqlite3AtoF() routine. + */ + case SQLITE_TESTCTRL_ATOF: { + const char *z = va_arg(ap,const char*); + double *pR = va_arg(ap,double*); + rc = sqlite3AtoF(z,pR); + break; + } + #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue) ** @@ -186090,6 +192552,7 @@ SQLITE_API const char *sqlite3_filename_journal(const char *zFilename){ } SQLITE_API const char *sqlite3_filename_wal(const char *zFilename){ #ifdef SQLITE_OMIT_WAL + UNUSED_PARAMETER(zFilename); return 0; #else zFilename = sqlite3_filename_journal(zFilename); @@ -186111,17 +192574,19 @@ SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ ** of range. */ SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N){ + const char *zRet = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - if( N<0 || N>=db->nDb ){ - return 0; - }else{ - return db->aDb[N].zDbSName; + sqlite3_mutex_enter(db->mutex); + if( N>=0 && NnDb ){ + zRet = db->aDb[N].zDbSName; } + sqlite3_mutex_leave(db->mutex); + return zRet; } /* @@ -186774,7 +193239,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){ ** Here, array { X } means zero or more occurrences of X, adjacent in ** memory. A "position" is an index of a token in the token stream ** generated by the tokenizer. Note that POS_END and POS_COLUMN occur -** in the same logical place as the position element, and act as sentinals +** in the same logical place as the position element, and act as sentinels ** ending a position list array. POS_END is 0. POS_COLUMN is 1. ** The positions numbers are not stored literally but rather as two more ** than the difference from the prior position, or the just the position plus @@ -186993,10 +193458,20 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){ #ifndef _FTSINT_H #define _FTSINT_H +/* +** Activate assert() only if SQLITE_TEST is enabled. +*/ #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif +/* #include */ +/* #include */ +/* #include */ +/* #include */ +/* #include */ +/* #include */ + /* FTS3/FTS4 require virtual tables */ #ifdef SQLITE_OMIT_VIRTUALTABLE # undef SQLITE_ENABLE_FTS3 @@ -187439,13 +193914,6 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */ */ #define UNUSED_PARAMETER(x) (void)(x) -/* -** Activate assert() only if SQLITE_TEST is enabled. -*/ -#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) -# define NDEBUG 1 -#endif - /* ** The TESTONLY macro is used to enclose variable declarations or ** other bits of code that are needed to support the arguments @@ -187460,7 +193928,29 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */ #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) -#define deliberate_fall_through +#if !defined(deliberate_fall_through) +# if defined(__has_attribute) +# if __has_attribute(fallthrough) +# define deliberate_fall_through __attribute__((fallthrough)); +# endif +# endif +#endif +#if !defined(deliberate_fall_through) +# define deliberate_fall_through +#endif + +/* +** Macros needed to provide flexible arrays in a portable way +*/ +#ifndef offsetof +# define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0)) +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY +#else +# define FLEXARRAY 1 +#endif + #endif /* SQLITE_AMALGAMATION */ @@ -187566,7 +194056,7 @@ struct Fts3Table { #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - /* True to disable the incremental doclist optimization. This is controled + /* True to disable the incremental doclist optimization. This is controlled ** by special insert command 'test-no-incr-doclist'. */ int bNoIncrDoclist; @@ -187618,7 +194108,7 @@ struct Fts3Cursor { /* ** The Fts3Cursor.eSearch member is always set to one of the following. -** Actualy, Fts3Cursor.eSearch can be greater than or equal to +** Actually, Fts3Cursor.eSearch can be greater than or equal to ** FTS3_FULLTEXT_SEARCH. If so, then Fts3Cursor.eSearch - 2 is the index ** of the column to be searched. For example, in ** @@ -187691,9 +194181,13 @@ struct Fts3Phrase { */ int nToken; /* Number of tokens in the phrase */ int iColumn; /* Index of column this phrase must match */ - Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */ + Fts3PhraseToken aToken[FLEXARRAY]; /* One for each token in the phrase */ }; +/* Size (in bytes) of an Fts3Phrase object large enough to hold N tokens */ +#define SZ_FTS3PHRASE(N) \ + (offsetof(Fts3Phrase,aToken)+(N)*sizeof(Fts3PhraseToken)) + /* ** A tree of these objects forms the RHS of a MATCH operator. ** @@ -187841,6 +194335,15 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table*,int,int); (*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \ ) +SQLITE_PRIVATE int sqlite3Fts3PrepareStmt( + Fts3Table *p, /* Prepare for this connection */ + const char *zSql, /* SQL to prepare */ + int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */ + int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */ + sqlite3_stmt **pp /* OUT: Prepared statement */ +); + + /* fts3.c */ SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char**,const char*,...); SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64); @@ -187900,6 +194403,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext( SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **); SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *); SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); +SQLITE_PRIVATE int sqlite3Fts3MsrCancel(Fts3Cursor*, Fts3Expr*); /* fts3_tokenize_vtab.c */ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *, void(*xDestroy)(void*)); @@ -187926,12 +194430,6 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk); # define SQLITE_CORE 1 #endif -/* #include */ -/* #include */ -/* #include */ -/* #include */ -/* #include */ -/* #include */ /* #include "fts3.h" */ #ifndef SQLITE_CORE @@ -187939,6 +194437,12 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk); SQLITE_EXTENSION_INIT1 #endif + +/* +** Assume any b-tree layer with more levels than this is corrupt. +*/ +#define FTS3_MAX_BTREE_HEIGHT 48 + typedef struct Fts3HashWrapper Fts3HashWrapper; struct Fts3HashWrapper { Fts3Hash hash; /* Hash table */ @@ -189453,9 +195957,7 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){ zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); if( !zSql ) return SQLITE_NOMEM; p->bLock++; - rc = sqlite3_prepare_v3( - p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 - ); + rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt); p->bLock--; sqlite3_free(zSql); } @@ -189657,7 +196159,11 @@ static int fts3SelectLeaf( assert( piLeaf || piLeaf2 ); fts3GetVarint32(zNode, &iHeight); - rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2); + if( iHeight>FTS3_MAX_BTREE_HEIGHT ){ + rc = FTS_CORRUPT_VTAB; + }else{ + rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2); + } assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) ); if( rc==SQLITE_OK && iHeight>1 ){ @@ -189702,8 +196208,13 @@ static void fts3PutDeltaVarint( sqlite3_int64 iVal /* Write this value to the list */ ){ assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) ); - *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev); - *piPrev = iVal; + if( iVal-(*piPrev)>=0 ){ + /* Refuse to write a negative delta integer. This only happens with a + ** corrupt db (see the assert above) and can cause buffer overwrites + ** in some cases. */ + *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev); + *piPrev = iVal; + } } /* @@ -189975,10 +196486,15 @@ static int fts3PoslistPhraseMerge( if( *p1==POS_COLUMN ){ p1++; p1 += fts3GetVarint32(p1, &iCol1); + /* iCol1==0 indicates corruption. Column 0 does not have a POS_COLUMN + ** entry, so this is actually end-of-doclist. */ + if( iCol1==0 ) return 0; } if( *p2==POS_COLUMN ){ p2++; p2 += fts3GetVarint32(p2, &iCol2); + /* As above, iCol2==0 indicates corruption. */ + if( iCol2==0 ) return 0; } while( 1 ){ @@ -190265,7 +196781,7 @@ static int fts3DoclistOrMerge( ** sizes of the two inputs, plus enough space for exactly one of the input ** docids to grow. ** - ** A symetric argument may be made if the doclists are in descending + ** A symmetric argument may be made if the doclists are in descending ** order. */ aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING); @@ -191025,9 +197541,7 @@ static int fts3FilterMethod( } if( zSql ){ p->bLock++; - rc = sqlite3_prepare_v3( - p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 - ); + rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt); p->bLock--; sqlite3_free(zSql); }else{ @@ -191650,6 +198164,7 @@ static int fts3IntegrityMethod( UNUSED_PARAMETER(isQuick); rc = sqlite3Fts3IntegrityCheck(p, &bOk); + assert( pVtab->zErrMsg==0 || rc!=SQLITE_OK ); assert( rc!=SQLITE_CORRUPT_VTAB ); if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){ *pzErr = sqlite3_mprintf("unable to validate the inverted index for" @@ -192053,6 +198568,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ char *p1; char *p2; char *aOut; + i64 nAlloc = (i64)nPoslist*2 + FTS3_BUFFER_PADDING; if( nMaxUndeferred>iPrev ){ p1 = aPoslist; @@ -192064,7 +198580,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ nDistance = iPrev - nMaxUndeferred; } - aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING); + aOut = (char *)sqlite3Fts3MallocZero(nAlloc); if( !aOut ){ sqlite3_free(aPoslist); return SQLITE_NOMEM; @@ -192363,7 +198879,7 @@ static int incrPhraseTokenNext( ** ** * does not contain any deferred tokens. ** -** Advance it to the next matching documnent in the database and populate +** Advance it to the next matching document in the database and populate ** the Fts3Doclist.pList and nList fields. ** ** If there is no "next" entry and no error occurs, then *pbEof is set to @@ -193149,7 +199665,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ nTmp += p->pRight->pPhrase->doclist.nList; } nTmp += p->pPhrase->doclist.nList; - aTmp = sqlite3_malloc64(nTmp*2); + aTmp = sqlite3_malloc64(nTmp*2 + FTS3_VARINT_MAX); if( !aTmp ){ *pRc = SQLITE_NOMEM; res = 0; @@ -193370,7 +199886,7 @@ static int fts3EvalNext(Fts3Cursor *pCsr){ } /* -** Restart interation for expression pExpr so that the next call to +** Restart iteration for expression pExpr so that the next call to ** fts3EvalNext() visits the first row. Do not allow incremental ** loading or merging of phrase doclists for this iteration. ** @@ -193413,6 +199929,24 @@ static void fts3EvalRestart( } } +/* +** Expression node pExpr is an MSR phrase. This function restarts pExpr +** so that it is a regular phrase query, not an MSR. SQLITE_OK is returned +** if successful, or an SQLite error code otherwise. +*/ +SQLITE_PRIVATE int sqlite3Fts3MsrCancel(Fts3Cursor *pCsr, Fts3Expr *pExpr){ + int rc = SQLITE_OK; + if( pExpr->bEof==0 ){ + i64 iDocid = pExpr->iDocid; + fts3EvalRestart(pCsr, pExpr, &rc); + while( rc==SQLITE_OK && pExpr->iDocid!=iDocid ){ + fts3EvalNextRow(pCsr, pExpr, &rc); + if( pExpr->bEof ) rc = FTS_CORRUPT_VTAB; + } + } + return rc; +} + /* ** After allocating the Fts3Expr.aMI[] array for each phrase in the ** expression rooted at pExpr, the cursor iterates through all rows matched @@ -193800,7 +200334,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){ } #endif -#if !SQLITE_CORE +#if !defined(SQLITE_CORE) /* ** Initialize API pointer table, if required. */ @@ -194148,7 +200682,7 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){ pCsr->aStat[1].nDoc++; } eState = 2; - /* fall through */ + /* no break */ deliberate_fall_through case 2: if( v==0 ){ /* 0x00. Next integer will be a docid. */ @@ -194164,7 +200698,7 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){ /* State 3. The integer just read is a column number. */ default: assert( eState==3 ); iCol = (int)v; - if( iCol<1 ){ + if( iCol<1 || iCol>(pFts3->nColumn+1) ){ rc = SQLITE_CORRUPT_VTAB; break; } @@ -194544,6 +201078,23 @@ SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer( */ static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *); +/* +** Search buffer z[], size n, for a '"' character. Or, if enable_parenthesis +** is defined, search for '(' and ')' as well. Return the index of the first +** such character in the buffer. If there is no such character, return -1. +*/ +static int findBarredChar(const char *z, int n){ + int ii; + for(ii=0; iiiLangid, z, i, &pCursor); + *pnConsumed = n; + rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor); if( rc==SQLITE_OK ){ const char *zToken; int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; @@ -194585,7 +201129,18 @@ static int getNextToken( rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); if( rc==SQLITE_OK ){ - nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; + /* Check that this tokenization did not gobble up any " characters. Or, + ** if enable_parenthesis is true, that it did not gobble up any + ** open or close parenthesis characters either. If it did, call + ** getNextToken() again, but pass only that part of the input buffer + ** up to the first such character. */ + int iBarred = findBarredChar(z, iEnd); + if( iBarred>=0 ){ + pModule->xClose(pCursor); + return getNextToken(pParse, iCol, z, iBarred, ppExpr, pnConsumed); + } + + nByte = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1) + nToken; pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte); if( !pRet ){ rc = SQLITE_NOMEM; @@ -194595,7 +201150,7 @@ static int getNextToken( pRet->pPhrase->nToken = 1; pRet->pPhrase->iColumn = iCol; pRet->pPhrase->aToken[0].n = nToken; - pRet->pPhrase->aToken[0].z = (char *)&pRet->pPhrase[1]; + pRet->pPhrase->aToken[0].z = (char*)&pRet->pPhrase->aToken[1]; memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken); if( iEnd=0 ){ + *pnConsumed = iBarred; + } rc = SQLITE_OK; } @@ -194666,9 +201225,9 @@ static int getNextString( Fts3Expr *p = 0; sqlite3_tokenizer_cursor *pCursor = 0; char *zTemp = 0; - int nTemp = 0; + i64 nTemp = 0; - const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase); + const int nSpace = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1); int nToken = 0; /* The final Fts3Expr data structure, including the Fts3Phrase, @@ -194702,10 +201261,11 @@ static int getNextString( Fts3PhraseToken *pToken; p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken)); - if( !p ) goto no_mem; - zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte); - if( !zTemp ) goto no_mem; + if( !zTemp || !p ){ + rc = SQLITE_NOMEM; + goto getnextstring_out; + } assert( nToken==ii ); pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii]; @@ -194720,9 +201280,6 @@ static int getNextString( nToken = ii+1; } } - - pModule->xClose(pCursor); - pCursor = 0; } if( rc==SQLITE_DONE ){ @@ -194730,7 +201287,10 @@ static int getNextString( char *zBuf = 0; p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp); - if( !p ) goto no_mem; + if( !p ){ + rc = SQLITE_NOMEM; + goto getnextstring_out; + } memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p); p->eType = FTSQUERY_PHRASE; p->pPhrase = (Fts3Phrase *)&p[1]; @@ -194738,11 +201298,9 @@ static int getNextString( p->pPhrase->nToken = nToken; zBuf = (char *)&p->pPhrase->aToken[nToken]; + assert( nTemp==0 || zTemp ); if( zTemp ){ memcpy(zBuf, zTemp, nTemp); - sqlite3_free(zTemp); - }else{ - assert( nTemp==0 ); } for(jj=0; jjpPhrase->nToken; jj++){ @@ -194752,17 +201310,17 @@ static int getNextString( rc = SQLITE_OK; } - *ppExpr = p; - return rc; -no_mem: - + getnextstring_out: if( pCursor ){ pModule->xClose(pCursor); } sqlite3_free(zTemp); - sqlite3_free(p); - *ppExpr = 0; - return SQLITE_NOMEM; + if( rc!=SQLITE_OK ){ + sqlite3_free(p); + p = 0; + } + *ppExpr = p; + return rc; } /* @@ -194830,6 +201388,7 @@ static int getNextNode( assert( nKey==4 ); if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){ nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear); + if( nNear>=1000000000 ) nNear = 1000000000; } } @@ -195041,7 +201600,7 @@ static int fts3ExprParse( /* The isRequirePhrase variable is set to true if a phrase or ** an expression contained in parenthesis is required. If a - ** binary operator (AND, OR, NOT or NEAR) is encounted when + ** binary operator (AND, OR, NOT or NEAR) is encountered when ** isRequirePhrase is set, this is a syntax error. */ if( !isPhrase && isRequirePhrase ){ @@ -195623,7 +202182,6 @@ static void fts3ExprTestCommon( } if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ - sqlite3Fts3ExprFree(pExpr); sqlite3_result_error(context, "Error parsing expression", -1); }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){ sqlite3_result_error_nomem(context); @@ -195866,7 +202424,7 @@ static void fts3HashInsertElement( } -/* Resize the hash table so that it cantains "new_size" buckets. +/* Resize the hash table so that it contains "new_size" buckets. ** "new_size" must be a power of 2. The hash table might fail ** to resize if sqliteMalloc() fails. ** @@ -196321,7 +202879,7 @@ static int star_oh(const char *z){ /* ** If the word ends with zFrom and xCond() is true for the stem -** of the word that preceeds the zFrom ending, then change the +** of the word that precedes the zFrom ending, then change the ** ending to zTo. ** ** The input word *pz and zFrom are both in reverse order. zTo @@ -197832,7 +204390,7 @@ static int fts3tokFilterMethod( fts3tokResetCursor(pCsr); if( idxNum==1 ){ const char *zByte = (const char *)sqlite3_value_text(apVal[0]); - int nByte = sqlite3_value_bytes(apVal[0]); + sqlite3_int64 nByte = sqlite3_value_bytes(apVal[0]); pCsr->zInput = sqlite3_malloc64(nByte+1); if( pCsr->zInput==0 ){ rc = SQLITE_NOMEM; @@ -198046,9 +204604,9 @@ typedef struct SegmentWriter SegmentWriter; ** incrementally. See function fts3PendingListAppend() for details. */ struct PendingList { - int nData; + sqlite3_int64 nData; char *aData; - int nSpace; + sqlite3_int64 nSpace; sqlite3_int64 iLastDocid; sqlite3_int64 iLastCol; sqlite3_int64 iLastPos; @@ -198221,6 +204779,24 @@ struct SegmentNode { #define SQL_UPDATE_LEVEL_IDX 38 #define SQL_UPDATE_LEVEL 39 +/* +** Wrapper around sqlite3_prepare_v3() to ensure that SQLITE_PREPARE_FROM_DDL +** is always set. +*/ +SQLITE_PRIVATE int sqlite3Fts3PrepareStmt( + Fts3Table *p, /* Prepare for this connection */ + const char *zSql, /* SQL to prepare */ + int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */ + int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */ + sqlite3_stmt **pp /* OUT: Prepared statement */ +){ + int f = SQLITE_PREPARE_FROM_DDL + |((bAllowVtab==0) ? SQLITE_PREPARE_NO_VTAB : 0) + |(bPersist ? SQLITE_PREPARE_PERSISTENT : 0); + + return sqlite3_prepare_v3(p->db, zSql, -1, f, pp, NULL); +} + /* ** This function is used to obtain an SQLite prepared statement handle ** for the statement identified by the second argument. If successful, @@ -198346,12 +204922,12 @@ static int fts3SqlStmt( pStmt = p->aStmt[eStmt]; if( !pStmt ){ - int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB; + int bAllowVtab = 0; char *zSql; if( eStmt==SQL_CONTENT_INSERT ){ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ - f &= ~SQLITE_PREPARE_NO_VTAB; + bAllowVtab = 1; zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); }else{ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); @@ -198359,7 +204935,7 @@ static int fts3SqlStmt( if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL); + rc = sqlite3Fts3PrepareStmt(p, zSql, 1, bAllowVtab, &pStmt); sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); p->aStmt[eStmt] = pStmt; @@ -198708,7 +205284,9 @@ static int fts3PendingTermsAddOne( pList = (PendingList *)fts3HashFind(pHash, zToken, nToken); if( pList ){ - p->nPendingData -= (pList->nData + nToken + sizeof(Fts3HashElem)); + assert( (i64)pList->nData+(i64)nToken+(i64)sizeof(Fts3HashElem) + <= (i64)p->nPendingData ); + p->nPendingData -= (int)(pList->nData + nToken + sizeof(Fts3HashElem)); } if( fts3PendingListAppend(&pList, p->iPrevDocid, iCol, iPos, &rc) ){ if( pList==fts3HashInsert(pHash, zToken, nToken, pList) ){ @@ -198721,7 +205299,9 @@ static int fts3PendingTermsAddOne( } } if( rc==SQLITE_OK ){ - p->nPendingData += (pList->nData + nToken + sizeof(Fts3HashElem)); + assert( (i64)p->nPendingData + pList->nData + nToken + + sizeof(Fts3HashElem) <= 0x3fffffff ); + p->nPendingData += (int)(pList->nData + nToken + sizeof(Fts3HashElem)); } return rc; } @@ -201055,6 +207635,10 @@ static void fts3ReadEndBlockField( for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){ iVal = iVal*10 + (zText[i] - '0'); } + + /* This if() clause is just to avoid an integer overflow. The record is + ** corrupt in this case. */ + if( (i64)iVal==SMALLEST_INT64 ) iMul = 1; *pnByte = ((i64)iVal * (i64)iMul); } } @@ -201522,7 +208106,7 @@ static int fts3DoRebuild(Fts3Table *p){ if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt); sqlite3_free(zSql); } @@ -201662,8 +208246,8 @@ struct NodeWriter { ** to an appendable b-tree segment. */ struct IncrmergeWriter { - int nLeafEst; /* Space allocated for leaf blocks */ - int nWork; /* Number of leaf pages flushed */ + i64 nLeafEst; /* Space allocated for leaf blocks */ + i64 nWork; /* Number of leaf pages flushed */ sqlite3_int64 iAbsLevel; /* Absolute level of input segments */ int iIdx; /* Index of *output* segment in iAbsLevel+1 */ sqlite3_int64 iStart; /* Block number of first allocated block */ @@ -201904,7 +208488,7 @@ static int fts3IncrmergePush( ** ** It is assumed that the buffer associated with pNode is already large ** enough to accommodate the new entry. The buffer associated with pPrev -** is extended by this function if requrired. +** is extended by this function if required. ** ** If an error (i.e. OOM condition) occurs, an SQLite error code is ** returned. Otherwise, SQLITE_OK. @@ -202281,7 +208865,7 @@ static int fts3IncrmergeLoad( return FTS_CORRUPT_VTAB; } - pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT; + pWriter->nLeafEst = (int)(((iEnd - iStart)+1)/FTS_MAX_APPENDABLE_HEIGHT); pWriter->iStart = iStart; pWriter->iEnd = iEnd; pWriter->iAbsLevel = iAbsLevel; @@ -202409,7 +208993,7 @@ static int fts3IncrmergeWriter( ){ int rc; /* Return Code */ int i; /* Iterator variable */ - int nLeafEst = 0; /* Blocks allocated for leaf nodes */ + i64 nLeafEst = 0; /* Blocks allocated for leaf nodes */ sqlite3_stmt *pLeafEst = 0; /* SQL used to determine nLeafEst */ sqlite3_stmt *pFirstBlock = 0; /* SQL used to determine first block */ @@ -202419,7 +209003,7 @@ static int fts3IncrmergeWriter( sqlite3_bind_int64(pLeafEst, 1, iAbsLevel); sqlite3_bind_int64(pLeafEst, 2, pCsr->nSegment); if( SQLITE_ROW==sqlite3_step(pLeafEst) ){ - nLeafEst = sqlite3_column_int(pLeafEst, 0); + nLeafEst = sqlite3_column_int64(pLeafEst, 0); } rc = sqlite3_reset(pLeafEst); } @@ -203275,7 +209859,7 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){ if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt); sqlite3_free(zSql); } @@ -203405,7 +209989,7 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ v = atoi(&zVal[9]); if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v; rc = SQLITE_OK; - }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){ + }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 11) ){ v = atoi(&zVal[11]); if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v; rc = SQLITE_OK; @@ -203567,7 +210151,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken( /* ** SQLite value pRowid contains the rowid of a row that may or may not be ** present in the FTS3 table. If it is, delete it and adjust the contents -** of subsiduary data structures accordingly. +** of subsidiary data structures accordingly. */ static int fts3DeleteByRowid( Fts3Table *p, @@ -203802,10 +210386,6 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){ /* #include */ /* #include */ -#ifndef SQLITE_AMALGAMATION -typedef sqlite3_int64 i64; -#endif - /* ** Characters that may appear in the second argument to matchinfo(). */ @@ -203893,9 +210473,13 @@ struct MatchinfoBuffer { int nElem; int bGlobal; /* Set if global data is loaded */ char *zMatchinfo; - u32 aMatchinfo[1]; + u32 aMI[FLEXARRAY]; }; +/* Size (in bytes) of a MatchinfoBuffer sufficient for N elements */ +#define SZ_MATCHINFOBUFFER(N) \ + (offsetof(MatchinfoBuffer,aMI)+(((N)+1)/2)*sizeof(u64)) + /* ** The snippet() and offsets() functions both return text values. An instance @@ -203920,13 +210504,13 @@ struct StrBuffer { static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ MatchinfoBuffer *pRet; sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1) - + sizeof(MatchinfoBuffer); + + SZ_MATCHINFOBUFFER(1); sqlite3_int64 nStr = strlen(zMatchinfo); pRet = sqlite3Fts3MallocZero(nByte + nStr+1); if( pRet ){ - pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; - pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + pRet->aMI[0] = (u8*)(&pRet->aMI[1]) - (u8*)pRet; + pRet->aMI[1+nElem] = pRet->aMI[0] + sizeof(u32)*((int)nElem+1); pRet->nElem = (int)nElem; pRet->zMatchinfo = ((char*)pRet) + nByte; @@ -203940,10 +210524,10 @@ static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ static void fts3MIBufferFree(void *p){ MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]); - assert( (u32*)p==&pBuf->aMatchinfo[1] - || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2] + assert( (u32*)p==&pBuf->aMI[1] + || (u32*)p==&pBuf->aMI[pBuf->nElem+2] ); - if( (u32*)p==&pBuf->aMatchinfo[1] ){ + if( (u32*)p==&pBuf->aMI[1] ){ pBuf->aRef[1] = 0; }else{ pBuf->aRef[2] = 0; @@ -203960,18 +210544,18 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ if( p->aRef[1]==0 ){ p->aRef[1] = 1; - aOut = &p->aMatchinfo[1]; + aOut = &p->aMI[1]; xRet = fts3MIBufferFree; } else if( p->aRef[2]==0 ){ p->aRef[2] = 1; - aOut = &p->aMatchinfo[p->nElem+2]; + aOut = &p->aMI[p->nElem+2]; xRet = fts3MIBufferFree; }else{ aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32)); if( aOut ){ xRet = sqlite3_free; - if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32)); + if( p->bGlobal ) memcpy(aOut, &p->aMI[1], p->nElem*sizeof(u32)); } } @@ -203981,7 +210565,7 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){ p->bGlobal = 1; - memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32)); + memcpy(&p->aMI[2+p->nElem], &p->aMI[1], p->nElem*sizeof(u32)); } /* @@ -204396,11 +210980,11 @@ static int fts3StringAppend( } /* If there is insufficient space allocated at StrBuffer.z, use realloc() - ** to grow the buffer until so that it is big enough to accomadate the + ** to grow the buffer until so that it is big enough to accommodate the ** appended data. */ - if( pStr->n+nAppend+1>=pStr->nAlloc ){ - sqlite3_int64 nAlloc = pStr->nAlloc+(sqlite3_int64)nAppend+100; + if( (i64)pStr->n+(i64)nAppend+1>=(i64)pStr->nAlloc ){ + i64 nAlloc = pStr->nAlloc+(i64)nAppend+100; char *zNew = sqlite3_realloc64(pStr->z, nAlloc); if( !zNew ){ return SQLITE_NOMEM; @@ -204672,7 +211256,7 @@ static int fts3ExprLHits( if( p->flag==FTS3_MATCHINFO_LHITS ){ p->aMatchinfo[iStart + iCol] = (u32)nHit; }else if( nHit ){ - p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F)); + p->aMatchinfo[iStart + iCol/32] |= (1U << (iCol&0x1F)); } } assert( *pIter==0x00 || *pIter==0x01 ); @@ -204808,16 +211392,16 @@ static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ break; case FTS3_MATCHINFO_LHITS: - nVal = pInfo->nCol * pInfo->nPhrase; + nVal = (size_t)pInfo->nCol * pInfo->nPhrase; break; case FTS3_MATCHINFO_LHITS_BM: - nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32); + nVal = (size_t)pInfo->nPhrase * ((pInfo->nCol + 31) / 32); break; default: assert( cArg==FTS3_MATCHINFO_HITS ); - nVal = pInfo->nCol * pInfo->nPhrase * 3; + nVal = (size_t)pInfo->nCol * pInfo->nPhrase * 3; break; } @@ -205371,6 +211955,22 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){ return rc; } +/* +** If expression pExpr is a phrase expression that uses an MSR query, +** restart it as a regular, non-incremental query. Return SQLITE_OK +** if successful, or an SQLite error code otherwise. +*/ +static int fts3ExprRestartIfCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ + TermOffsetCtx *p = (TermOffsetCtx*)ctx; + int rc = SQLITE_OK; + UNUSED_PARAMETER(iPhrase); + if( pExpr->pPhrase && pExpr->pPhrase->bIncr ){ + rc = sqlite3Fts3MsrCancel(p->pCsr, pExpr); + pExpr->pPhrase->bIncr = 0; + } + return rc; +} + /* ** Implementation of offsets() function. */ @@ -205407,6 +212007,12 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets( sCtx.iDocid = pCsr->iPrevId; sCtx.pCsr = pCsr; + /* If a query restart will be required, do it here, rather than later of + ** after pointers to poslist buffers that may be invalidated by a restart + ** have been saved. */ + rc = sqlite3Fts3ExprIterate(pCsr->pExpr, fts3ExprRestartIfCb, (void*)&sCtx); + if( rc!=SQLITE_OK ) goto offsets_out; + /* Loop through the table columns, appending offset information to ** string-buffer res for each column. */ @@ -206353,8 +212959,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ ** Beginning with version 3.45.0 (circa 2024-01-01), these routines also ** accept BLOB values that have JSON encoded using a binary representation ** called "JSONB". The name JSONB comes from PostgreSQL, however the on-disk -** format SQLite JSONB is completely different and incompatible with -** PostgreSQL JSONB. +** format for SQLite-JSONB is completely different and incompatible with +** PostgreSQL-JSONB. ** ** Decoding and interpreting JSONB is still O(N) where N is the size of ** the input, the same as text JSON. However, the constant of proportionality @@ -206411,7 +213017,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ ** ** The payload size need not be expressed in its minimal form. For example, ** if the payload size is 10, the size can be expressed in any of 5 different -** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte, +** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by one 0x0a byte, ** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by ** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and ** a single byte of 0x0a. The shorter forms are preferred, of course, but @@ -206421,7 +213027,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ ** the size when it becomes known, resulting in a non-minimal encoding. ** ** The value (X>>4)==15 is not actually used in the current implementation -** (as SQLite is currently unable handle BLOBs larger than about 2GB) +** (as SQLite is currently unable to handle BLOBs larger than about 2GB) ** but is included in the design to allow for future enhancements. ** ** The payload follows the header. NULL, TRUE, and FALSE have no payload and @@ -206481,23 +213087,47 @@ static const char * const jsonbType[] = { ** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). */ static const char jsonIsSpace[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#ifdef SQLITE_ASCII +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */ +#endif +#ifdef SQLITE_EBCDIC +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */ +#endif + }; #define jsonIsspace(x) (jsonIsSpace[(unsigned char)x]) @@ -206505,7 +213135,13 @@ static const char jsonIsSpace[] = { ** The set of all space characters recognized by jsonIsspace(). ** Useful as the second argument to strspn(). */ +#ifdef SQLITE_ASCII static const char jsonSpaces[] = "\011\012\015\040"; +#endif +#ifdef SQLITE_EBCDIC +static const char jsonSpaces[] = "\005\045\015\100"; +#endif + /* ** Characters that are special to JSON. Control characters, @@ -206514,23 +213150,46 @@ static const char jsonSpaces[] = "\011\012\015\040"; ** it in the set of special characters. */ static const char jsonIsOk[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +#ifdef SQLITE_ASCII +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 2 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 5 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */ +#endif +#ifdef SQLITE_EBCDIC +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 3 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, /* 7 */ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */ +#endif }; /* Objects */ @@ -206590,7 +213249,8 @@ struct JsonString { /* Allowed values for JsonString.eErr */ #define JSTRING_OOM 0x01 /* Out of memory */ #define JSTRING_MALFORMED 0x02 /* Malformed JSONB */ -#define JSTRING_ERR 0x04 /* Error already sent to sqlite3_result */ +#define JSTRING_TOODEEP 0x04 /* JSON nested too deep */ +#define JSTRING_ERR 0x08 /* Error already sent to sqlite3_result */ /* The "subtype" set for text JSON values passed through using ** sqlite3_result_subtype() and sqlite3_value_subtype(). @@ -206605,7 +213265,10 @@ struct JsonString { #define JSON_SQL 0x02 /* Result is always SQL */ #define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */ #define JSON_ISSET 0x04 /* json_set(), not json_insert() */ -#define JSON_BLOB 0x08 /* Use the BLOB output format */ +#define JSON_AINS 0x08 /* json_array_insert(), not json_insert() */ +#define JSON_BLOB 0x10 /* Use the BLOB output format */ + +#define JSON_INSERT_TYPE(X) (((X)&0xC)>>2) /* A parsed JSON value. Lifecycle: @@ -206651,6 +213314,7 @@ struct JsonParse { #define JEDIT_REPL 2 /* Overwrite if exists */ #define JEDIT_INS 3 /* Insert if not exists */ #define JEDIT_SET 4 /* Insert or overwrite */ +#define JEDIT_AINS 5 /* array_insert() */ /* ** Maximum nesting depth of JSON for this implementation. @@ -206675,8 +213339,8 @@ struct JsonParse { ** Forward references **************************************************************************/ static void jsonReturnStringAsBlob(JsonString*); -static int jsonFuncArgMightBeBinary(sqlite3_value *pJson); -static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*); +static int jsonArgIsJsonb(sqlite3_value *pJson, JsonParse *p); +static u32 jsonTranslateBlobToText(JsonParse*,u32,JsonString*); static void jsonReturnParse(sqlite3_context*,JsonParse*); static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32); static void jsonParseFree(JsonParse*); @@ -206749,7 +213413,7 @@ static int jsonCacheInsert( ** most-recently used entry if it isn't so already. ** ** The JsonParse object returned still belongs to the Cache and might -** be deleted at any moment. If the caller whants the JsonParse to +** be deleted at any moment. If the caller wants the JsonParse to ** linger, it needs to increment the nPJRef reference counter. */ static JsonParse *jsonCacheSearch( @@ -206834,6 +213498,15 @@ static void jsonStringOom(JsonString *p){ jsonStringReset(p); } +/* Report JSON nested too deep +*/ +static void jsonStringTooDeep(JsonString *p){ + p->eErr |= JSTRING_TOODEEP; + assert( p->pCtx!=0 ); + sqlite3_result_error(p->pCtx, "JSON nested too deep", -1); + jsonStringReset(p); +} + /* Enlarge pJson->zBuf so that it can hold at least N more bytes. ** Return zero on success. Return non-zero on an OOM error */ @@ -207073,7 +213746,7 @@ static void jsonAppendSqlValue( break; } case SQLITE_FLOAT: { - jsonPrintf(100, p, "%!0.15g", sqlite3_value_double(pValue)); + jsonPrintf(100, p, "%!0.17g", sqlite3_value_double(pValue)); break; } case SQLITE_INTEGER: { @@ -207093,11 +213766,9 @@ static void jsonAppendSqlValue( break; } default: { - if( jsonFuncArgMightBeBinary(pValue) ){ - JsonParse px; - memset(&px, 0, sizeof(px)); - px.aBlob = (u8*)sqlite3_value_blob(pValue); - px.nBlob = sqlite3_value_bytes(pValue); + JsonParse px; + memset(&px, 0, sizeof(px)); + if( jsonArgIsJsonb(pValue, &px) ){ jsonTranslateBlobToText(&px, 0, p); }else if( p->eErr==0 ){ sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); @@ -207125,6 +213796,7 @@ static void jsonReturnString( ){ assert( (pParse!=0)==(ctx!=0) ); assert( ctx==0 || ctx==p->pCtx ); + jsonStringTerminate(p); if( p->eErr==0 ){ int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(p->pCtx)); if( flags & JSON_BLOB ){ @@ -207132,7 +213804,7 @@ static void jsonReturnString( }else if( p->bStatic ){ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, SQLITE_TRANSIENT, SQLITE_UTF8); - }else if( jsonStringTerminate(p) ){ + }else{ if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){ int rc; pParse->zJson = sqlite3RCStrRef(p->zBuf); @@ -207148,11 +213820,11 @@ static void jsonReturnString( sqlite3_result_text64(p->pCtx, sqlite3RCStrRef(p->zBuf), p->nUsed, sqlite3RCStrUnref, SQLITE_UTF8); - }else{ - sqlite3_result_error_nomem(p->pCtx); } }else if( p->eErr & JSTRING_OOM ){ sqlite3_result_error_nomem(p->pCtx); + }else if( p->eErr & JSTRING_TOODEEP ){ + /* error already in p->pCtx */ }else if( p->eErr & JSTRING_MALFORMED ){ sqlite3_result_error(p->pCtx, "malformed JSON", -1); } @@ -207416,7 +214088,7 @@ static void jsonWrongNumArgs( */ static int jsonBlobExpand(JsonParse *pParse, u32 N){ u8 *aNew; - u32 t; + u64 t; assert( N>pParse->nBlobAlloc ); if( pParse->nBlobAlloc==0 ){ t = 100; @@ -207426,8 +214098,9 @@ static int jsonBlobExpand(JsonParse *pParse, u32 N){ if( tdb, pParse->aBlob, t); if( aNew==0 ){ pParse->oom = 1; return 1; } + assert( t<0x7fffffff ); pParse->aBlob = aNew; - pParse->nBlobAlloc = t; + pParse->nBlobAlloc = (u32)t; return 0; } @@ -207482,11 +214155,11 @@ static void jsonBlobAppendOneByte(JsonParse *pParse, u8 c){ /* Slow version of jsonBlobAppendNode() that first resizes the ** pParse->aBlob structure. */ -static void jsonBlobAppendNode(JsonParse*,u8,u32,const void*); +static void jsonBlobAppendNode(JsonParse*,u8,u64,const void*); static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode( JsonParse *pParse, u8 eType, - u32 szPayload, + u64 szPayload, const void *aPayload ){ if( jsonBlobExpand(pParse, pParse->nBlob+szPayload+9) ) return; @@ -207494,7 +214167,7 @@ static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode( } -/* Append an node type byte together with the payload size and +/* Append a node type byte together with the payload size and ** possibly also the payload. ** ** If aPayload is not NULL, then it is a pointer to the payload which @@ -207506,7 +214179,7 @@ static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode( static void jsonBlobAppendNode( JsonParse *pParse, /* The JsonParse object under construction */ u8 eType, /* Node type. One of JSONB_* */ - u32 szPayload, /* Number of bytes of payload */ + u64 szPayload, /* Number of bytes of payload */ const void *aPayload /* The payload. Might be NULL */ ){ u8 *a; @@ -207563,8 +214236,10 @@ static int jsonBlobChangePayloadSize( nExtra = 1; }else if( szType==13 ){ nExtra = 2; - }else{ + }else if( szType==14 ){ nExtra = 4; + }else{ + nExtra = 8; } if( szPayload<=11 ){ nNeeded = 0; @@ -208034,7 +214709,12 @@ static int jsonTranslateTextToBlob(JsonParse *pParse, u32 i){ || c=='n' || c=='r' || c=='t' || (c=='u' && jsonIs4Hex(&z[j+1])) ){ if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ; - }else if( c=='\'' || c=='0' || c=='v' || c=='\n' + }else if( c=='\'' || c=='v' || c=='\n' +#ifdef SQLITE_BUG_COMPATIBLE_20250510 + || (c=='0') /* Legacy bug compatible */ +#else + || (c=='0' && !sqlite3Isdigit(z[j+1])) /* Correct implementation */ +#endif || (0xe2==(u8)c && 0x80==(u8)z[j+1] && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])) || (c=='x' && jsonIs2Hex(&z[j+1])) ){ @@ -208355,12 +215035,8 @@ static int jsonConvertTextToBlob( */ static void jsonReturnStringAsBlob(JsonString *pStr){ JsonParse px; + assert( pStr->eErr==0 ); memset(&px, 0, sizeof(px)); - jsonStringTerminate(pStr); - if( pStr->eErr ){ - sqlite3_result_error_nomem(pStr->pCtx); - return; - } px.zJson = pStr->zBuf; px.nJson = pStr->nUsed; px.db = sqlite3_context_db_handle(pStr->pCtx); @@ -208384,12 +215060,10 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ u8 x; u32 sz; u32 n; - if( NEVER(i>pParse->nBlob) ){ + if( i>=pParse->nBlob ){ *pSz = 0; return 0; - } - x = pParse->aBlob[i]>>4; - if( x<=11 ){ + }else if( (x = pParse->aBlob[i]>>4)<=11 ){ sz = x; n = 1; }else if( x==12 ){ @@ -208424,15 +215098,15 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ *pSz = 0; return 0; } - sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + + sz = ((u32)pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8]; n = 9; } if( (i64)i+sz+n > pParse->nBlob && (i64)i+sz+n > pParse->nBlob-pParse->delta ){ - sz = 0; - n = 0; + *pSz = 0; + return 0; } *pSz = sz; return n; @@ -208453,7 +215127,7 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ ** The pOut->eErr JSTRING_OOM flag is set on a OOM. */ static u32 jsonTranslateBlobToText( - const JsonParse *pParse, /* the complete parse of the JSON */ + JsonParse *pParse, /* the complete parse of the JSON */ u32 i, /* Start rendering at this index */ JsonString *pOut /* Write JSON here */ ){ @@ -208514,7 +215188,8 @@ static u32 jsonTranslateBlobToText( if( sz==0 ) goto malformed_jsonb; if( zIn[0]=='-' ){ jsonAppendChar(pOut, '-'); - k++; + if( sz<=1 ) goto malformed_jsonb; + k = 1; } if( zIn[k]=='.' ){ jsonAppendChar(pOut, '0'); @@ -208529,9 +215204,12 @@ static u32 jsonTranslateBlobToText( } case JSONB_TEXT: case JSONB_TEXTJ: { - jsonAppendChar(pOut, '"'); - jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz); - jsonAppendChar(pOut, '"'); + if( pOut->nUsed+sz+2<=pOut->nAlloc || jsonStringGrow(pOut, sz+2)==0 ){ + pOut->zBuf[pOut->nUsed] = '"'; + memcpy(pOut->zBuf+pOut->nUsed+1,(const char*)&pParse->aBlob[i+n],sz); + pOut->zBuf[pOut->nUsed+sz+1] = '"'; + pOut->nUsed += sz+2; + } break; } case JSONB_TEXT5: { @@ -208574,7 +215252,7 @@ static u32 jsonTranslateBlobToText( jsonAppendChar(pOut, '\''); break; case 'v': - jsonAppendRawNZ(pOut, "\\u0009", 6); + jsonAppendRawNZ(pOut, "\\u000b", 6); break; case 'x': if( sz2<4 ){ @@ -208632,10 +215310,14 @@ static u32 jsonTranslateBlobToText( jsonAppendChar(pOut, '['); j = i+n; iEnd = j+sz; + if( ++pParse->iDepth > JSON_MAX_DEPTH ){ + jsonStringTooDeep(pOut); + } while( jeErr==0 ){ j = jsonTranslateBlobToText(pParse, j, pOut); jsonAppendChar(pOut, ','); } + pParse->iDepth--; if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED; if( sz>0 ) jsonStringTrimOneChar(pOut); jsonAppendChar(pOut, ']'); @@ -208646,10 +215328,14 @@ static u32 jsonTranslateBlobToText( jsonAppendChar(pOut, '{'); j = i+n; iEnd = j+sz; + if( ++pParse->iDepth > JSON_MAX_DEPTH ){ + jsonStringTooDeep(pOut); + } while( jeErr==0 ){ j = jsonTranslateBlobToText(pParse, j, pOut); jsonAppendChar(pOut, (x++ & 1) ? ',' : ':'); } + pParse->iDepth--; if( (x & 1)!=0 || j>iEnd ) pOut->eErr |= JSTRING_MALFORMED; if( sz>0 ) jsonStringTrimOneChar(pOut); jsonAppendChar(pOut, '}'); @@ -208706,7 +215392,7 @@ static u32 jsonTranslateBlobToPrettyText( u32 i /* Start rendering at this index */ ){ u32 sz, n, j, iEnd; - const JsonParse *pParse = pPretty->pParse; + JsonParse *pParse = pPretty->pParse; JsonString *pOut = pPretty->pOut; n = jsonbPayloadSize(pParse, i, &sz); if( n==0 ){ @@ -208721,6 +215407,9 @@ static u32 jsonTranslateBlobToPrettyText( if( jnIndent++; + if( pPretty->nIndent >= JSON_MAX_DEPTH ){ + jsonStringTooDeep(pOut); + } while( pOut->eErr==0 ){ jsonPrettyIndent(pPretty); j = jsonTranslateBlobToPrettyText(pPretty, j); @@ -208742,6 +215431,10 @@ static u32 jsonTranslateBlobToPrettyText( if( jnIndent++; + if( pPretty->nIndent >= JSON_MAX_DEPTH ){ + jsonStringTooDeep(pOut); + } + pParse->iDepth = pPretty->nIndent; while( pOut->eErr==0 ){ jsonPrettyIndent(pPretty); j = jsonTranslateBlobToText(pParse, j, pOut); @@ -208770,33 +215463,6 @@ static u32 jsonTranslateBlobToPrettyText( return i; } - -/* Return true if the input pJson -** -** For performance reasons, this routine does not do a detailed check of the -** input BLOB to ensure that it is well-formed. Hence, false positives are -** possible. False negatives should never occur, however. -*/ -static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){ - u32 sz, n; - const u8 *aBlob; - int nBlob; - JsonParse s; - if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0; - aBlob = sqlite3_value_blob(pJson); - nBlob = sqlite3_value_bytes(pJson); - if( nBlob<1 ) return 0; - if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0; - memset(&s, 0, sizeof(s)); - s.aBlob = (u8*)aBlob; - s.nBlob = nBlob; - n = jsonbPayloadSize(&s, 0, &sz); - if( n==0 ) return 0; - if( sz+n!=(u32)nBlob ) return 0; - if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0; - return sz+n==(u32)nBlob; -} - /* ** Given that a JSONB_ARRAY object starts at offset i, return ** the number of entries in that array. @@ -208829,6 +215495,82 @@ static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){ pParse->delta += jsonBlobChangePayloadSize(pParse, iRoot, sz); } +/* +** If the JSONB at aIns[0..nIns-1] can be expanded (by denormalizing the +** size field) by d bytes, then write the expansion into aOut[] and +** return true. In this way, an overwrite happens without changing the +** size of the JSONB, which reduces memcpy() operations and also make it +** faster and easier to update the B-Tree entry that contains the JSONB +** in the database. +** +** If the expansion of aIns[] by d bytes cannot be (easily) accomplished +** then return false. +** +** The d parameter is guaranteed to be between 1 and 8. +** +** This routine is an optimization. A correct answer is obtained if it +** always leaves the output unchanged and returns false. +*/ +static int jsonBlobOverwrite( + u8 *aOut, /* Overwrite here */ + const u8 *aIns, /* New content */ + u32 nIns, /* Bytes of new content */ + u32 d /* Need to expand new content by this much */ +){ + u32 szPayload; /* Bytes of payload */ + u32 i; /* New header size, after expansion & a loop counter */ + u8 szHdr; /* Size of header before expansion */ + + /* Lookup table for finding the upper 4 bits of the first byte of the + ** expanded aIns[], based on the size of the expanded aIns[] header: + ** + ** 2 3 4 5 6 7 8 9 */ + static const u8 aType[] = { 0xc0, 0xd0, 0, 0xe0, 0, 0, 0, 0xf0 }; + + if( (aIns[0]&0x0f)<=2 ) return 0; /* Cannot enlarge NULL, true, false */ + switch( aIns[0]>>4 ){ + default: { /* aIns[] header size 1 */ + if( ((1<=2 && i<=9 && aType[i-2]!=0 ); + aOut[0] = (aIns[0] & 0x0f) | aType[i-2]; + memcpy(&aOut[i], &aIns[szHdr], nIns-szHdr); + szPayload = nIns - szHdr; + while( 1/*edit-by-break*/ ){ + i--; + aOut[i] = szPayload & 0xff; + if( i==1 ) break; + szPayload >>= 8; + } + assert( (szPayload>>8)==0 ); + return 1; +} + /* ** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of ** content beginning at iDel, and replacing them with nIns bytes of @@ -208850,6 +215592,12 @@ static void jsonBlobEdit( u32 nIns /* Bytes of content to insert */ ){ i64 d = (i64)nIns - (i64)nDel; + assert( pParse->nBlob >= (u64)iDel + (u64)nDel ); + if( d<0 && d>=(-8) && aIns!=0 + && jsonBlobOverwrite(&pParse->aBlob[iDel], aIns, nIns, (int)-d) + ){ + return; + } if( d!=0 ){ if( pParse->nBlob + d > pParse->nBlobAlloc ){ jsonBlobExpand(pParse, pParse->nBlob+d); @@ -208861,7 +215609,9 @@ static void jsonBlobEdit( pParse->nBlob += d; pParse->delta += d; } - if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns); + if( nIns && aIns ){ + memcpy(&pParse->aBlob[iDel], aIns, nIns); + } } /* @@ -208946,7 +215696,21 @@ static u32 jsonUnescapeOneChar(const char *z, u32 n, u32 *piOut){ case 'r': { *piOut = '\r'; return 2; } case 't': { *piOut = '\t'; return 2; } case 'v': { *piOut = '\v'; return 2; } - case '0': { *piOut = 0; return 2; } + case '0': { + /* JSON5 requires that the \0 escape not be followed by a digit. + ** But SQLite did not enforce this restriction in versions 3.42.0 + ** through 3.49.2. That was a bug. But some applications might have + ** come to depend on that bug. Use the SQLITE_BUG_COMPATIBLE_20250510 + ** option to restore the old buggy behavior. */ +#ifdef SQLITE_BUG_COMPATIBLE_20250510 + /* Legacy bug-compatible behavior */ + *piOut = 0; +#else + /* Correct behavior */ + *piOut = (n>2 && sqlite3Isdigit(z[2])) ? JSON_INVALID_CHAR : 0; +#endif + return 2; + } case '\'': case '"': case '/': @@ -209071,7 +215835,9 @@ static int jsonLabelCompare( */ #define JSON_LOOKUP_ERROR 0xffffffff #define JSON_LOOKUP_NOTFOUND 0xfffffffe -#define JSON_LOOKUP_PATHERROR 0xfffffffd +#define JSON_LOOKUP_NOTARRAY 0xfffffffd +#define JSON_LOOKUP_TOODEEP 0xfffffffc +#define JSON_LOOKUP_PATHERROR 0xfffffffb #define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR) /* Forward declaration */ @@ -209100,7 +215866,7 @@ static u32 jsonLookupStep(JsonParse*,u32,const char*,u32); static u32 jsonCreateEditSubstructure( JsonParse *pParse, /* The original JSONB that is being edited */ JsonParse *pIns, /* Populate this with the blob data to insert */ - const char *zTail /* Tail of the path that determins substructure */ + const char *zTail /* Tail of the path that determines substructure */ ){ static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT }; int rc; @@ -209118,7 +215884,12 @@ static u32 jsonCreateEditSubstructure( pIns->eEdit = pParse->eEdit; pIns->nIns = pParse->nIns; pIns->aIns = pParse->aIns; + pIns->iDepth = pParse->iDepth+1; + if( pIns->iDepth >= JSON_MAX_DEPTH ){ + return JSON_LOOKUP_TOODEEP; + } rc = jsonLookupStep(pIns, 0, zTail, 0); + pParse->iDepth--; pParse->oom |= pIns->oom; } return rc; /* Error code only */ @@ -209135,9 +215906,9 @@ static u32 jsonCreateEditSubstructure( ** Return one of the JSON_LOOKUP error codes if problems are seen. ** ** This routine will also modify the blob. If pParse->eEdit is one of -** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be -** made to the selected value. If an edit is performed, then the return -** value does not necessarily point to the select element. If an edit +** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, JEDIT_SET, or JEDIT_AINS, then changes +** might be made to the selected value. If an edit is performed, then the +** return value does not necessarily point to the select element. If an edit ** is performed, the return value is only useful for detecting error ** conditions. */ @@ -209163,6 +215934,13 @@ static u32 jsonLookupStep( jsonBlobEdit(pParse, iRoot, sz, 0, 0); }else if( pParse->eEdit==JEDIT_INS ){ /* Already exists, so json_insert() is a no-op */ + }else if( pParse->eEdit==JEDIT_AINS ){ + /* json_array_insert() */ + if( zPath[-1]!=']' ){ + return JSON_LOOKUP_NOTARRAY; + }else{ + jsonBlobEdit(pParse, iRoot, 0, pParse->aIns, pParse->nIns); + } }else{ /* json_set() or json_replace() */ jsonBlobEdit(pParse, iRoot, sz, pParse->aIns, pParse->nIns); @@ -209217,7 +215995,11 @@ static u32 jsonLookupStep( n = jsonbPayloadSize(pParse, v, &sz); if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR; assert( j>0 ); + if( ++pParse->iDepth >= JSON_MAX_DEPTH ){ + return JSON_LOOKUP_TOODEEP; + } rc = jsonLookupStep(pParse, v, &zPath[i], j); + pParse->iDepth--; if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); return rc; } @@ -209234,6 +216016,10 @@ static u32 jsonLookupStep( JsonParse ix; /* Header of the label to be inserted */ testcase( pParse->eEdit==JEDIT_INS ); testcase( pParse->eEdit==JEDIT_SET ); + testcase( pParse->eEdit==JEDIT_AINS ); + if( pParse->eEdit==JEDIT_AINS && sqlite3_strglob("*]",&zPath[i])!=0 ){ + return JSON_LOOKUP_NOTARRAY; + } memset(&ix, 0, sizeof(ix)); ix.db = pParse->db; jsonBlobAppendNode(&ix, rawKey?JSONB_TEXTRAW:JSONB_TEXT5, nKey, 0); @@ -209261,28 +216047,32 @@ static u32 jsonLookupStep( return rc; } }else if( zPath[0]=='[' ){ + u64 kk = 0; x = pParse->aBlob[iRoot] & 0x0f; if( x!=JSONB_ARRAY ) return JSON_LOOKUP_NOTFOUND; n = jsonbPayloadSize(pParse, iRoot, &sz); - k = 0; i = 1; while( sqlite3Isdigit(zPath[i]) ){ - k = k*10 + zPath[i] - '0'; + if( kk<0xffffffff ) kk = kk*10 + zPath[i] - '0'; + /* ^^^^^^^^^^--- Allow kk to be bigger than any JSON array so that + ** we get NOTFOUND instead of PATHERROR, without overflowing kk. */ i++; } if( i<2 || zPath[i]!=']' ){ if( zPath[1]=='#' ){ - k = jsonbArrayCount(pParse, iRoot); + kk = jsonbArrayCount(pParse, iRoot); i = 2; if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){ - unsigned int nn = 0; + u64 nn = 0; i = 3; do{ - nn = nn*10 + zPath[i] - '0'; + if( nn<0xffffffff ) nn = nn*10 + zPath[i] - '0'; + /* ^^^^^^^^^^--- Allow nn to be bigger than any JSON array to + ** get NOTFOUND instead of PATHERROR, without overflowing nn. */ i++; }while( sqlite3Isdigit(zPath[i]) ); - if( nn>k ) return JSON_LOOKUP_NOTFOUND; - k -= nn; + if( nn>kk ) return JSON_LOOKUP_NOTFOUND; + kk -= nn; } if( zPath[i]!=']' ){ return JSON_LOOKUP_PATHERROR; @@ -209294,21 +216084,26 @@ static u32 jsonLookupStep( j = iRoot+n; iEnd = j+sz; while( jiDepth >= JSON_MAX_DEPTH ){ + return JSON_LOOKUP_TOODEEP; + } rc = jsonLookupStep(pParse, j, &zPath[i+1], 0); + pParse->iDepth--; if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); return rc; } - k--; + kk--; n = jsonbPayloadSize(pParse, j, &sz); if( n==0 ) return JSON_LOOKUP_ERROR; j += n+sz; } if( j>iEnd ) return JSON_LOOKUP_ERROR; - if( k>0 ) return JSON_LOOKUP_NOTFOUND; + if( kk>0 ) return JSON_LOOKUP_NOTFOUND; if( pParse->eEdit>=JEDIT_INS ){ JsonParse v; testcase( pParse->eEdit==JEDIT_INS ); + testcase( pParse->eEdit==JEDIT_AINS ); testcase( pParse->eEdit==JEDIT_SET ); rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]); if( !JSON_LOOKUP_ISERROR(rc) @@ -209354,19 +216149,27 @@ static void jsonReturnTextJsonFromBlob( ** ** If the value is a primitive, return it as an SQL value. ** If the value is an array or object, return it as either -** JSON text or the BLOB encoding, depending on the JSON_B flag -** on the userdata. +** JSON text or the BLOB encoding, depending on the eMode flag +** as follows: +** +** eMode==0 JSONB if the JSON_B flag is set in userdata or +** text if the JSON_B flag is omitted from userdata. +** +** eMode==1 Text +** +** eMode==2 JSONB */ static void jsonReturnFromBlob( JsonParse *pParse, /* Complete JSON parse tree */ u32 i, /* Index of the node */ sqlite3_context *pCtx, /* Return value for this function */ - int textOnly /* return text JSON. Disregard user-data */ + int eMode /* Format of return: text of JSONB */ ){ u32 n, sz; int rc; sqlite3 *db = sqlite3_context_db_handle(pCtx); + assert( eMode>=0 && eMode<=2 ); n = jsonbPayloadSize(pParse, i, &sz); if( n==0 ){ sqlite3_result_error(pCtx, "malformed JSON", -1); @@ -209407,7 +216210,19 @@ static void jsonReturnFromBlob( rc = sqlite3DecOrHexToI64(z, &iRes); sqlite3DbFree(db, z); if( rc==0 ){ - sqlite3_result_int64(pCtx, bNeg ? -iRes : iRes); + if( iRes<0 ){ + /* A hexadecimal literal with 16 significant digits and with the + ** high-order bit set is a negative integer in SQLite (and hence + ** iRes comes back as negative) but should be interpreted as a + ** positive value if it occurs within JSON. The value is too + ** large to appear as an SQLite integer so it must be converted + ** into floating point. */ + double r; + r = (double)*(sqlite3_uint64*)&iRes; + sqlite3_result_double(pCtx, bNeg ? -r : r); + }else{ + sqlite3_result_int64(pCtx, bNeg ? -iRes : iRes); + } }else if( rc==3 && bNeg ){ sqlite3_result_int64(pCtx, SMALLEST_INT64); }else if( rc==1 ){ @@ -209426,7 +216241,7 @@ static void jsonReturnFromBlob( to_double: z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz); if( z==0 ) goto returnfromblob_oom; - rc = sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); + rc = sqlite3AtoF(z, &r); sqlite3DbFree(db, z); if( rc<=0 ) goto returnfromblob_malformed; sqlite3_result_double(pCtx, r); @@ -209446,7 +216261,7 @@ static void jsonReturnFromBlob( char *zOut; u32 nOut = sz; z = (const char*)&pParse->aBlob[i+n]; - zOut = sqlite3DbMallocRaw(db, nOut+1); + zOut = sqlite3DbMallocRaw(db, ((u64)nOut)+1); if( zOut==0 ) goto returnfromblob_oom; for(iIn=iOut=0; iInaBlob[i], sz+n, SQLITE_TRANSIENT); }else{ jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n); @@ -209541,10 +216362,7 @@ static int jsonFunctionArgToBlob( return 0; } case SQLITE_BLOB: { - if( jsonFuncArgMightBeBinary(pArg) ){ - pParse->aBlob = (u8*)sqlite3_value_blob(pArg); - pParse->nBlob = sqlite3_value_bytes(pArg); - }else{ + if( !jsonArgIsJsonb(pArg, pParse) ){ sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1); return 1; } @@ -209603,16 +216421,35 @@ static int jsonFunctionArgToBlob( } /* -** Generate a bad path error. +** Generate a path error. +** +** The specifics of the error are determined by the rc argument. +** +** rc error +** ----------------- ---------------------- +** JSON_LOOKUP_ARRAY "not an array" +** JSON_LOOKUP_TOODEEP "JSON nested too deep" +** JSON_LOOKUP_ERROR "malformed JSON" +** otherwise... "bad JSON path" ** ** If ctx is not NULL then push the error message into ctx and return NULL. ** If ctx is NULL, then return the text of the error message. */ static char *jsonBadPathError( sqlite3_context *ctx, /* The function call containing the error */ - const char *zPath /* The path with the problem */ + const char *zPath, /* The path with the problem */ + int rc /* Maybe JSON_LOOKUP_NOTARRAY */ ){ - char *zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath); + char *zMsg; + if( rc==(int)JSON_LOOKUP_NOTARRAY ){ + zMsg = sqlite3_mprintf("not an array element: %Q", zPath); + }else if( rc==(int)JSON_LOOKUP_ERROR ){ + zMsg = sqlite3_mprintf("malformed JSON"); + }else if( rc==(int)JSON_LOOKUP_TOODEEP ){ + zMsg = sqlite3_mprintf("JSON path too deep"); + }else{ + zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath); + } if( ctx==0 ) return zMsg; if( zMsg ){ sqlite3_result_error(ctx, zMsg, -1); @@ -209624,18 +216461,18 @@ static char *jsonBadPathError( } /* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent -** arguments come in parse where each pair contains a JSON path and +** arguments come in pairs where each pair contains a JSON path and ** content to insert or set at that patch. Do the updates ** and return the result. ** ** The specific operation is determined by eEdit, which can be one -** of JEDIT_INS, JEDIT_REPL, or JEDIT_SET. +** of JEDIT_INS, JEDIT_REPL, JEDIT_SET, or JEDIT_AINS. */ static void jsonInsertIntoBlob( sqlite3_context *ctx, int argc, sqlite3_value **argv, - int eEdit /* JEDIT_INS, JEDIT_REPL, or JEDIT_SET */ + int eEdit /* JEDIT_INS, JEDIT_REPL, JEDIT_SET, JEDIT_AINS */ ){ int i; u32 rc = 0; @@ -209672,6 +216509,7 @@ static void jsonInsertIntoBlob( p->nIns = ax.nBlob; p->aIns = ax.aBlob; p->delta = 0; + p->iDepth = 0; rc = jsonLookupStep(p, 0, zPath+1, 0); } jsonParseReset(&ax); @@ -209684,38 +216522,53 @@ static void jsonInsertIntoBlob( jsonInsertIntoBlob_patherror: jsonParseFree(p); - if( rc==JSON_LOOKUP_ERROR ){ - sqlite3_result_error(ctx, "malformed JSON", -1); - }else{ - jsonBadPathError(ctx, zPath); - } + jsonBadPathError(ctx, zPath, rc); return; } /* ** If pArg is a blob that seems like a JSONB blob, then initialize ** p to point to that JSONB and return TRUE. If pArg does not seem like -** a JSONB blob, then return FALSE; -** -** This routine is only called if it is already known that pArg is a -** blob. The only open question is whether or not the blob appears -** to be a JSONB blob. +** a JSONB blob, then return FALSE. +** +** For small BLOBs (having no more than 7 bytes of payload) a full +** validity check is done. So for small BLOBs this routine only returns +** true if the value is guaranteed to be a valid JSONB. For larger BLOBs +** (8 byte or more of payload) only the size of the outermost element is +** checked to verify that the BLOB is superficially valid JSONB. +** +** A full JSONB validation is done on smaller BLOBs because those BLOBs might +** also be text JSON that has been incorrectly cast into a BLOB. +** (See tag-20240123-a and https://sqlite.org/forum/forumpost/012136abd5) +** If the BLOB is 9 bytes are larger, then it is not possible for the +** superficial size check done here to pass if the input is really text +** JSON so we do not need to look deeper in that case. +** +** Why we only need to do full JSONB validation for smaller BLOBs: +** +** The first byte of valid JSON text must be one of: '{', '[', '"', ' ', '\n', +** '\r', '\t', '-', or a digit '0' through '9'. Of these, only a subset +** can also be the first byte of JSONB: '{', '[', and digits '3' +** through '9'. In every one of those cases, the payload size is 7 bytes +** or less. So if we do full JSONB validation for every BLOB where the +** payload is less than 7 bytes, we will never get a false positive for +** JSONB on an input that is really text JSON. */ static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){ u32 n, sz = 0; + u8 c; + if( sqlite3_value_type(pArg)!=SQLITE_BLOB ) return 0; p->aBlob = (u8*)sqlite3_value_blob(pArg); p->nBlob = (u32)sqlite3_value_bytes(pArg); - if( p->nBlob==0 ){ - p->aBlob = 0; - return 0; - } - if( NEVER(p->aBlob==0) ){ - return 0; - } - if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT + if( p->nBlob>0 + && ALWAYS(p->aBlob!=0) + && ((c = p->aBlob[0]) & 0x0f)<=JSONB_OBJECT && (n = jsonbPayloadSize(p, 0, &sz))>0 && sz+n==p->nBlob - && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0) + && ((c & 0x0f)>JSONB_FALSE || sz==0) + && (sz>7 + || (c!=0x7b && c!=0x5b && !sqlite3Isdigit(c)) + || jsonbValidityCheck(p, 0, p->nBlob, 1)==0) ){ return 1; } @@ -209793,7 +216646,7 @@ static JsonParse *jsonParseFuncArg( ** JSON functions were suppose to work. From the beginning, blob was ** reserved for expansion and a blob value should have raised an error. ** But it did not, due to a bug. And many applications came to depend - ** upon this buggy behavior, espeically when using the CLI and reading + ** upon this buggy behavior, especially when using the CLI and reading ** JSON text using readfile(), which returns a blob. For this reason ** we will continue to support the bug moving forward. ** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d @@ -210109,10 +216962,8 @@ static void jsonArrayLengthFunc( if( JSON_LOOKUP_ISERROR(i) ){ if( i==JSON_LOOKUP_NOTFOUND ){ /* no-op */ - }else if( i==JSON_LOOKUP_PATHERROR ){ - jsonBadPathError(ctx, zPath); }else{ - sqlite3_result_error(ctx, "malformed JSON", -1); + jsonBadPathError(ctx, zPath, i); } eErr = 1; i = 0; @@ -210215,7 +217066,7 @@ static void jsonExtractFunc( j = jsonLookupStep(p, 0, jx.zBuf, 0); jsonStringReset(&jx); }else{ - jsonBadPathError(ctx, zPath); + jsonBadPathError(ctx, zPath, 0); goto json_extract_error; } if( jnBlob ){ @@ -210246,11 +217097,8 @@ static void jsonExtractFunc( jsonAppendSeparator(&jx); jsonAppendRawNZ(&jx, "null", 4); } - }else if( j==JSON_LOOKUP_ERROR ){ - sqlite3_result_error(ctx, "malformed JSON", -1); - goto json_extract_error; }else{ - jsonBadPathError(ctx, zPath); + jsonBadPathError(ctx, zPath, j); goto json_extract_error; } } @@ -210274,6 +217122,7 @@ static void jsonExtractFunc( #define JSON_MERGE_BADTARGET 1 /* Malformed TARGET blob */ #define JSON_MERGE_BADPATCH 2 /* Malformed PATCH blob */ #define JSON_MERGE_OOM 3 /* Out-of-memory condition */ +#define JSON_MERGE_TOODEEP 4 /* Nested too deep */ /* ** RFC-7396 MergePatch for two JSONB blobs. @@ -210325,7 +217174,8 @@ static int jsonMergePatch( JsonParse *pTarget, /* The JSON parser that contains the TARGET */ u32 iTarget, /* Index of TARGET in pTarget->aBlob[] */ const JsonParse *pPatch, /* The PATCH */ - u32 iPatch /* Index of PATCH in pPatch->aBlob[] */ + u32 iPatch, /* Index of PATCH in pPatch->aBlob[] */ + u32 iDepth /* Nesting depth */ ){ u8 x; /* Type of a single node */ u32 n, sz=0; /* Return values from jsonbPayloadSize() */ @@ -210434,7 +217284,8 @@ static int jsonMergePatch( /* Algorithm line 12 */ int rc, savedDelta = pTarget->delta; pTarget->delta = 0; - rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue); + if( iDepth>=JSON_MAX_DEPTH ) return JSON_MERGE_TOODEEP; + rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue, iDepth+1); if( rc ) return rc; pTarget->delta += savedDelta; } @@ -210455,7 +217306,8 @@ static int jsonMergePatch( pTarget->aBlob[iTEnd+szNew] = 0x00; savedDelta = pTarget->delta; pTarget->delta = 0; - rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue); + if( iDepth>=JSON_MAX_DEPTH ) return JSON_MERGE_TOODEEP; + rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue,iDepth+1); if( rc ) return rc; pTarget->delta += savedDelta; } @@ -210486,11 +217338,13 @@ static void jsonPatchFunc( if( pTarget==0 ) return; pPatch = jsonParseFuncArg(ctx, argv[1], 0); if( pPatch ){ - rc = jsonMergePatch(pTarget, 0, pPatch, 0); + rc = jsonMergePatch(pTarget, 0, pPatch, 0, 0); if( rc==JSON_MERGE_OK ){ jsonReturnParse(ctx, pTarget); }else if( rc==JSON_MERGE_OOM ){ sqlite3_result_error_nomem(ctx); + }else if( rc==JSON_MERGE_TOODEEP ){ + sqlite3_result_error(ctx, "JSON nested too deep", -1); }else{ sqlite3_result_error(ctx, "malformed JSON", -1); } @@ -210578,10 +217432,8 @@ static void jsonRemoveFunc( if( JSON_LOOKUP_ISERROR(rc) ){ if( rc==JSON_LOOKUP_NOTFOUND ){ continue; /* No-op */ - }else if( rc==JSON_LOOKUP_PATHERROR ){ - jsonBadPathError(ctx, zPath); }else{ - sqlite3_result_error(ctx, "malformed JSON", -1); + jsonBadPathError(ctx, zPath, rc); } goto json_remove_done; } @@ -210591,7 +217443,7 @@ static void jsonRemoveFunc( return; json_remove_patherror: - jsonBadPathError(ctx, zPath); + jsonBadPathError(ctx, zPath, 0); json_remove_done: jsonParseFree(p); @@ -210635,16 +217487,18 @@ static void jsonSetFunc( int argc, sqlite3_value **argv ){ - int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); - int bIsSet = (flags&JSON_ISSET)!=0; + int eInsType = JSON_INSERT_TYPE(flags); + static const char *azInsType[] = { "insert", "set", "array_insert" }; + static const u8 aEditType[] = { JEDIT_INS, JEDIT_SET, JEDIT_AINS }; if( argc<1 ) return; + assert( eInsType>=0 && eInsType<=2 ); if( (argc&1)==0 ) { - jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); + jsonWrongNumArgs(ctx, azInsType[eInsType]); return; } - jsonInsertIntoBlob(ctx, argc, argv, bIsSet ? JEDIT_SET : JEDIT_INS); + jsonInsertIntoBlob(ctx, argc, argv, aEditType[eInsType]); } /* @@ -210669,17 +217523,15 @@ static void jsonTypeFunc( zPath = (const char*)sqlite3_value_text(argv[1]); if( zPath==0 ) goto json_type_done; if( zPath[0]!='$' ){ - jsonBadPathError(ctx, zPath); + jsonBadPathError(ctx, zPath, 0); goto json_type_done; } i = jsonLookupStep(p, 0, zPath+1, 0); if( JSON_LOOKUP_ISERROR(i) ){ if( i==JSON_LOOKUP_NOTFOUND ){ /* no-op */ - }else if( i==JSON_LOOKUP_PATHERROR ){ - jsonBadPathError(ctx, zPath); }else{ - sqlite3_result_error(ctx, "malformed JSON", -1); + jsonBadPathError(ctx, zPath, i); } goto json_type_done; } @@ -210808,21 +217660,17 @@ static void jsonValidFunc( return; } case SQLITE_BLOB: { - if( jsonFuncArgMightBeBinary(argv[0]) ){ + JsonParse py; + memset(&py, 0, sizeof(py)); + if( jsonArgIsJsonb(argv[0], &py) ){ if( flags & 0x04 ){ /* Superficial checking only - accomplished by the - ** jsonFuncArgMightBeBinary() call above. */ + ** jsonArgIsJsonb() call above. */ res = 1; }else if( flags & 0x08 ){ /* Strict checking. Check by translating BLOB->TEXT->BLOB. If ** no errors occur, call that a "strict check". */ - JsonParse px; - u32 iErr; - memset(&px, 0, sizeof(px)); - px.aBlob = (u8*)sqlite3_value_blob(argv[0]); - px.nBlob = sqlite3_value_bytes(argv[0]); - iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1); - res = iErr==0; + res = 0==jsonbValidityCheck(&py, 0, py.nBlob, 1); } break; } @@ -210880,9 +217728,7 @@ static void jsonErrorFunc( UNUSED_PARAMETER(argc); memset(&s, 0, sizeof(s)); s.db = sqlite3_context_db_handle(ctx); - if( jsonFuncArgMightBeBinary(argv[0]) ){ - s.aBlob = (u8*)sqlite3_value_blob(argv[0]); - s.nBlob = sqlite3_value_bytes(argv[0]); + if( jsonArgIsJsonb(argv[0], &s) ){ iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1); }else{ s.zJson = (char*)sqlite3_value_text(argv[0]); @@ -210939,12 +217785,12 @@ static void jsonArrayStep( } static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; + int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ - int flags; pStr->pCtx = ctx; - jsonAppendChar(pStr, ']'); - flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); + jsonAppendRawNZ(pStr, "]", 2); + jsonStringTrimOneChar(pStr); if( pStr->eErr ){ jsonReturnString(pStr, 0, 0); return; @@ -210965,6 +217811,9 @@ static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); jsonStringTrimOneChar(pStr); } + }else if( flags & JSON_BLOB ){ + static const u8 emptyArray = 0x0b; + sqlite3_result_blob(ctx, &emptyArray, 1, SQLITE_STATIC); }else{ sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); } @@ -210998,11 +217847,9 @@ static void jsonGroupInverse( UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); -#ifdef NEVER /* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will ** always have been called to initialize it */ if( NEVER(!pStr) ) return; -#endif z = pStr->zBuf; for(i=1; inUsed && ((c = z[i])!=',' || inStr || nNest); i++){ if( c=='"' ){ @@ -211031,6 +217878,13 @@ static void jsonGroupInverse( ** json_group_obj(NAME,VALUE) ** ** Return a JSON object composed of all names and values in the aggregate. +** +** Rows for which NAME is NULL do not result in a new entry. However, we +** do initially insert a "@" entry into the growing string for each null entry +** and change the first character of the string to "@" to signal that the +** string contains null entries. The "@" markers are needed in order to +** correctly process xInverse() requests. The initial "@" is converted +** back into "{" and the "@" null values are removed by jsonObjectCompute(). */ static void jsonObjectStep( sqlite3_context *ctx, @@ -211043,6 +217897,8 @@ static void jsonObjectStep( UNUSED_PARAMETER(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ + z = (const char*)sqlite3_value_text(argv[0]); + n = sqlite3Strlen30(z); if( pStr->zBuf==0 ){ jsonStringInit(pStr, ctx); jsonAppendChar(pStr, '{'); @@ -211050,32 +217906,79 @@ static void jsonObjectStep( jsonAppendChar(pStr, ','); } pStr->pCtx = ctx; - z = (const char*)sqlite3_value_text(argv[0]); - n = sqlite3Strlen30(z); - jsonAppendString(pStr, z, n); - jsonAppendChar(pStr, ':'); - jsonAppendSqlValue(pStr, argv[1]); + if( z!=0 ){ + jsonAppendString(pStr, z, n); + jsonAppendChar(pStr, ':'); + jsonAppendSqlValue(pStr, argv[1]); + }else{ + pStr->zBuf[0] = '@'; + jsonAppendRawNZ(pStr, "@", 1); + } } } static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; + int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ - int flags; - jsonAppendChar(pStr, '}'); + JsonString *pOgStr = pStr; + JsonString tmpStr; + jsonAppendRawNZ(pOgStr, "}", 2); /* Ensure it is zero-terminated */ + jsonStringTrimOneChar(pOgStr); /* Remove the zero terminator */ pStr->pCtx = ctx; - flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); if( pStr->eErr ){ jsonReturnString(pStr, 0, 0); return; - }else if( flags & JSON_BLOB ){ + } + if( pStr->zBuf[0]!='{' ){ + /* The string contains null entries that need to be removed */ + u64 i, j; + int inStr = 0; + if( !isFinal ){ + /* Work with a temporary copy of the string if this is not the + ** final result */ + jsonStringInit(&tmpStr, ctx); + jsonAppendRawNZ(&tmpStr, pStr->zBuf, pStr->nUsed+1); + pStr = &tmpStr; + if( pStr->eErr ){ + jsonReturnString(pStr, 0, 0); + return; + } + jsonStringTrimOneChar(pStr); /* Remove zero terminator */ + } + /* Fix up the string by changing the initial "@" flag back to + ** to "{" and removing all subsequence "@" entries, with their + ** associated comma delimeters. */ + pStr->zBuf[0] = '{'; + for(i=j=1; inUsed; i++){ + char c = pStr->zBuf[i]; + if( c=='"' ){ + inStr = !inStr; + pStr->zBuf[j++] = '"'; + }else if( c=='\\' ){ + pStr->zBuf[j++] = '\\'; + pStr->zBuf[j++] = pStr->zBuf[++i]; + }else if( c=='@' && !inStr ){ + assert( i+1nUsed ); + if( pStr->zBuf[i+1]==',' ){ + i++; + }else if( pStr->zBuf[j-1]==',' ){ + j--; + } + }else{ + pStr->zBuf[j++] = c; + } + } + pStr->zBuf[j] = 0; /* Restore zero terminator */ + pStr->nUsed = j; /* Truncate the string */ + } + if( flags & JSON_BLOB ){ jsonReturnStringAsBlob(pStr); if( isFinal ){ if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf); }else{ - jsonStringTrimOneChar(pStr); + jsonStringTrimOneChar(pOgStr); } - return; }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, pStr->bStatic ? SQLITE_TRANSIENT : @@ -211083,8 +217986,12 @@ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); - jsonStringTrimOneChar(pStr); + jsonStringTrimOneChar(pOgStr); } + if( pStr!=pOgStr ) jsonStringReset(pStr); + }else if( flags & JSON_BLOB ){ + static const unsigned char emptyObject = 0x0c; + sqlite3_result_blob(ctx, &emptyObject, 1, SQLITE_STATIC); }else{ sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); } @@ -211121,6 +218028,7 @@ struct JsonEachCursor { u32 nRoot; /* Size of the root path in bytes */ u8 eType; /* Type of the container for element i */ u8 bRecursive; /* True for json_tree(). False for json_each() */ + u8 eMode; /* 1 for json_each(). 2 for jsonb_each() */ u32 nParent; /* Current nesting depth */ u32 nParentAlloc; /* Space allocated for aParent[] */ JsonParent *aParent; /* Parent elements of i */ @@ -211132,6 +218040,8 @@ typedef struct JsonEachConnection JsonEachConnection; struct JsonEachConnection { sqlite3_vtab base; /* Base class - must be first */ sqlite3 *db; /* Database connection */ + u8 eMode; /* 1 for json_each(). 2 for jsonb_each() */ + u8 bRecursive; /* True for json_tree(). False for json_each() */ }; @@ -211174,6 +218084,8 @@ static int jsonEachConnect( if( pNew==0 ) return SQLITE_NOMEM; sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); pNew->db = db; + pNew->eMode = argv[0][4]=='b' ? 2 : 1; + pNew->bRecursive = argv[0][4+pNew->eMode]=='t'; } return rc; } @@ -211185,8 +218097,8 @@ static int jsonEachDisconnect(sqlite3_vtab *pVtab){ return SQLITE_OK; } -/* constructor for a JsonEachCursor object for json_each(). */ -static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ +/* constructor for a JsonEachCursor object for json_each()/json_tree(). */ +static int jsonEachOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ JsonEachConnection *pVtab = (JsonEachConnection*)p; JsonEachCursor *pCur; @@ -211194,21 +218106,13 @@ static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ pCur = sqlite3DbMallocZero(pVtab->db, sizeof(*pCur)); if( pCur==0 ) return SQLITE_NOMEM; pCur->db = pVtab->db; + pCur->eMode = pVtab->eMode; + pCur->bRecursive = pVtab->bRecursive; jsonStringZero(&pCur->path); *ppCursor = &pCur->base; return SQLITE_OK; } -/* constructor for a JsonEachCursor object for json_tree(). */ -static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - int rc = jsonEachOpenEach(p, ppCursor); - if( rc==SQLITE_OK ){ - JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; - pCur->bRecursive = 1; - } - return rc; -} - /* Reset a JsonEachCursor back to its original state. Free any memory ** held. */ static void jsonEachCursorReset(JsonEachCursor *p){ @@ -211249,7 +218153,9 @@ static int jsonSkipLabel(JsonEachCursor *p){ if( p->eType==JSONB_OBJECT ){ u32 sz = 0; u32 n = jsonbPayloadSize(&p->sParse, p->i, &sz); - return p->i + n + sz; + sz += p->i + n; + if( sz >= p->sParse.nBlob ) sz = p->i; + return sz; }else{ return p->i; } @@ -211413,7 +218319,7 @@ static int jsonEachColumn( } case JEACH_VALUE: { u32 i = jsonSkipLabel(p); - jsonReturnFromBlob(&p->sParse, i, ctx, 1); + jsonReturnFromBlob(&p->sParse, i, ctx, p->eMode); if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){ sqlite3_result_subtype(ctx, JSON_SUBTYPE); } @@ -211567,9 +218473,8 @@ static int jsonEachFilter( memset(&p->sParse, 0, sizeof(p->sParse)); p->sParse.nJPRef = 1; p->sParse.db = p->db; - if( jsonFuncArgMightBeBinary(argv[0]) ){ - p->sParse.nBlob = sqlite3_value_bytes(argv[0]); - p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]); + if( jsonArgIsJsonb(argv[0], &p->sParse) ){ + /* We have JSONB */ }else{ p->sParse.zJson = (char*)sqlite3_value_text(argv[0]); p->sParse.nJson = sqlite3_value_bytes(argv[0]); @@ -211589,7 +218494,7 @@ static int jsonEachFilter( if( zRoot==0 ) return SQLITE_OK; if( zRoot[0]!='$' ){ sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); + cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot, 0); jsonEachCursorReset(p); return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; } @@ -211607,7 +218512,7 @@ static int jsonEachFilter( return SQLITE_OK; } sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); + cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot, 0); jsonEachCursorReset(p); return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; } @@ -211658,36 +218563,7 @@ static sqlite3_module jsonEachModule = { jsonEachBestIndex, /* xBestIndex */ jsonEachDisconnect, /* xDisconnect */ 0, /* xDestroy */ - jsonEachOpenEach, /* xOpen - open a cursor */ - jsonEachClose, /* xClose - close a cursor */ - jsonEachFilter, /* xFilter - configure scan constraints */ - jsonEachNext, /* xNext - advance a cursor */ - jsonEachEof, /* xEof - check for end of scan */ - jsonEachColumn, /* xColumn - read data */ - jsonEachRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0, /* xRollbackTo */ - 0, /* xShadowName */ - 0 /* xIntegrity */ -}; - -/* The methods of the json_tree virtual table. */ -static sqlite3_module jsonTreeModule = { - 0, /* iVersion */ - 0, /* xCreate */ - jsonEachConnect, /* xConnect */ - jsonEachBestIndex, /* xBestIndex */ - jsonEachDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - jsonEachOpenTree, /* xOpen - open a cursor */ + jsonEachOpen, /* xOpen - open a cursor */ jsonEachClose, /* xClose - close a cursor */ jsonEachFilter, /* xFilter - configure scan constraints */ jsonEachNext, /* xNext - advance a cursor */ @@ -211726,6 +218602,8 @@ SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){ JFUNCTION(jsonb, 1,1,0, 0,1,0, jsonRemoveFunc), JFUNCTION(json_array, -1,0,1, 1,0,0, jsonArrayFunc), JFUNCTION(jsonb_array, -1,0,1, 1,1,0, jsonArrayFunc), + JFUNCTION(json_array_insert, -1,1,1, 1,0,JSON_AINS, jsonSetFunc), + JFUNCTION(jsonb_array_insert,-1,1,0, 1,1,JSON_AINS, jsonSetFunc), JFUNCTION(json_array_length, 1,1,0, 0,0,0, jsonArrayLengthFunc), JFUNCTION(json_array_length, 2,1,0, 0,0,0, jsonArrayLengthFunc), JFUNCTION(json_error_position,1,1,0, 0,0,0, jsonErrorFunc), @@ -211776,22 +218654,21 @@ SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) /* -** Register the JSON table-valued functions +** Register the JSON table-valued function named zName and return a +** pointer to its Module object. Return NULL if something goes wrong. */ -SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3 *db){ - int rc = SQLITE_OK; - static const struct { - const char *zName; - sqlite3_module *pModule; - } aMod[] = { - { "json_each", &jsonEachModule }, - { "json_tree", &jsonTreeModule }, - }; +SQLITE_PRIVATE Module *sqlite3JsonVtabRegister(sqlite3 *db, const char *zName){ unsigned int i; - for(i=0; iaModule, zName)==0 ); + for(i=0; i */ /* ** If building separately, we will need some setup that is normally @@ -211893,6 +218772,14 @@ typedef unsigned int u32; # define ALWAYS(X) (X) # define NEVER(X) (X) #endif +#ifndef offsetof +# define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0)) +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY +#else +# define FLEXARRAY 1 +#endif #endif /* !defined(SQLITE_AMALGAMATION) */ /* Macro to check for 4-byte alignment. Only used inside of assert() */ @@ -211955,7 +218842,7 @@ struct Rtree { u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ u8 nBytesPerCell; /* Bytes consumed per cell */ u8 inWrTrans; /* True if inside write transaction */ - u8 nAux; /* # of auxiliary columns in %_rowid */ + u16 nAux; /* # of auxiliary columns in %_rowid */ #ifdef SQLITE_ENABLE_GEOPOLY u8 nAuxNotNull; /* Number of initial not-null aux columns */ #endif @@ -212095,7 +218982,7 @@ struct RtreeCursor { sqlite3_stmt *pReadAux; /* Statement to read aux-data */ RtreeSearchPoint sPoint; /* Cached next search point */ RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */ - u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */ + u32 anQueue[RTREE_MAX_DEPTH+2]; /* Number of queued entries by iLevel */ }; /* Return the Rtree of a RtreeCursor */ @@ -212213,9 +219100,13 @@ struct RtreeMatchArg { RtreeGeomCallback cb; /* Info about the callback functions */ int nParam; /* Number of parameters to the SQL function */ sqlite3_value **apSqlParam; /* Original SQL parameter values */ - RtreeDValue aParam[1]; /* Values for parameters to the SQL function */ + RtreeDValue aParam[FLEXARRAY]; /* Values for parameters to the SQL function */ }; +/* Size of an RtreeMatchArg object with N parameters */ +#define SZ_RTREEMATCHARG(N) \ + (offsetof(RtreeMatchArg,aParam)+(N)*sizeof(RtreeDValue)) + #ifndef MAX # define MAX(x,y) ((x) < (y) ? (y) : (x)) #endif @@ -212546,6 +219437,9 @@ static int nodeAcquire( rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } + }else if( iNode<=0 ){ + RTREE_IS_CORRUPT(pRtree); + rc = SQLITE_CORRUPT_VTAB; }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){ pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode)+pRtree->iNodeSize); if( !pNode ){ @@ -212571,7 +219465,7 @@ static int nodeAcquire( */ if( rc==SQLITE_OK && pNode && iNode==1 ){ pRtree->iDepth = readInt16(pNode->zData); - if( pRtree->iDepth>RTREE_MAX_DEPTH ){ + if( pRtree->iDepth>=RTREE_MAX_DEPTH ){ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } @@ -212822,7 +219716,17 @@ static void rtreeRelease(Rtree *pRtree){ pRtree->inWrTrans = 0; assert( pRtree->nCursor==0 ); nodeBlobReset(pRtree); - assert( pRtree->nNodeRef==0 || pRtree->bCorrupt ); + if( pRtree->nNodeRef ){ + int i; + assert( pRtree->bCorrupt ); + for(i=0; iaHash[i] ){ + RtreeNode *pNext = pRtree->aHash[i]->pNext; + sqlite3_free(pRtree->aHash[i]); + pRtree->aHash[i] = pNext; + } + } + } sqlite3_finalize(pRtree->pWriteNode); sqlite3_finalize(pRtree->pDeleteNode); sqlite3_finalize(pRtree->pReadRowid); @@ -212920,6 +219824,12 @@ static void resetCursor(RtreeCursor *pCsr){ pCsr->base.pVtab = (sqlite3_vtab*)pRtree; pCsr->pReadAux = pStmt; + /* The following will only fail if the previous sqlite3_step() call failed, + ** in which case the error has already been caught. This statement never + ** encounters an error within an sqlite3_column_xxx() function, as it + ** calls sqlite3_column_value(), which does not use malloc(). So it is safe + ** to ignore the error code here. */ + sqlite3_reset(pStmt); } /* @@ -213171,7 +220081,7 @@ static int nodeRowidIndex( ){ int ii; int nCell = NCELL(pNode); - assert( nCell<200 ); + assert( nCell<65536 && nCell>=0 ); for(ii=0; iiRTREE_MAXCELLS ){ + RTREE_IS_CORRUPT(pRtree); + return SQLITE_CORRUPT_VTAB; + } pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell); while( p->iCell100) ){ + if( cnt>100 ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } @@ -214466,15 +221379,6 @@ static int SplitNode( rc = updateMapping(pRtree, pCell->iRowid, pLeft, iHeight); } - if( rc==SQLITE_OK ){ - rc = nodeRelease(pRtree, pRight); - pRight = 0; - } - if( rc==SQLITE_OK ){ - rc = nodeRelease(pRtree, pLeft); - pLeft = 0; - } - splitnode_out: nodeRelease(pRtree, pRight); nodeRelease(pRtree, pLeft); @@ -214659,7 +221563,7 @@ static int rtreeInsertCell( rc = SplitNode(pRtree, pNode, pCell, iHeight); }else{ rc = AdjustTree(pRtree, pNode, pCell); - if( ALWAYS(rc==SQLITE_OK) ){ + if( rc==SQLITE_OK ){ if( iHeight==0 ){ rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode); }else{ @@ -215419,7 +222323,7 @@ static int rtreeInit( "Auxiliary rtree columns must be last" /* 4 */ }; - assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */ + assert( RTREE_MAX_AUX_COLUMN<256 ); if( argc<6 || argc>RTREE_MAX_AUX_COLUMN+3 ){ *pzErr = sqlite3_mprintf("%s", aErrMsg[2 + (argc>=6)]); return SQLITE_ERROR; @@ -215554,7 +222458,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ if( node.zData==0 ) return; nData = sqlite3_value_bytes(apArg[1]); if( nData<4 ) return; - if( nDataz, &r, j, SQLITE_UTF8); + (void)sqlite3AtoF((const char*)p->z, &r); *pVal = r; #else *pVal = (GeoCoord)atof((const char*)p->z); @@ -216858,7 +223762,7 @@ static void geopolyBBoxFinal( ** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2). ** Returns: ** -** +2 x0,y0 is on the line segement +** +2 x0,y0 is on the line segment ** ** +1 x0,y0 is beneath line segment ** @@ -216964,7 +223868,7 @@ static void geopolyWithinFunc( sqlite3_free(p2); } -/* Objects used by the overlap algorihm. */ +/* Objects used by the overlap algorithm. */ typedef struct GeoEvent GeoEvent; typedef struct GeoSegment GeoSegment; typedef struct GeoOverlap GeoOverlap; @@ -217338,6 +224242,11 @@ static int geopolyInit( int ii; (void)pAux; + if( argc>=RTREE_MAX_AUX_COLUMN+4 ){ + *pzErr = sqlite3_mprintf("Too many columns for a geopoly table"); + return SQLITE_ERROR; + } + sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); @@ -218011,8 +224920,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ sqlite3_int64 nBlob; int memErr = 0; - nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue) - + nArg*sizeof(sqlite3_value*); + nBlob = SZ_RTREEMATCHARG(nArg) + nArg*sizeof(sqlite3_value*); pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob); if( !pBlob ){ sqlite3_result_error_nomem(ctx); @@ -218091,7 +224999,7 @@ SQLITE_API int sqlite3_rtree_query_callback( ); } -#if !SQLITE_CORE +#ifndef SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif @@ -218473,7 +225381,7 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ const UChar *zInput; /* Pointer to input string */ UChar *zOutput = 0; /* Pointer to output buffer */ int nInput; /* Size of utf-16 input string in bytes */ - int nOut; /* Size of output buffer in bytes */ + sqlite3_int64 nOut; /* Size of output buffer in bytes */ int cnt; int bToUpper; /* True for toupper(), false for tolower() */ UErrorCode status; @@ -218496,7 +225404,7 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ } for(cnt=0; cnt<2; cnt++){ - UChar *zNew = sqlite3_realloc(zOutput, nOut); + UChar *zNew = sqlite3_realloc64(zOutput, nOut); if( zNew==0 ){ sqlite3_free(zOutput); sqlite3_result_error_nomem(p); @@ -218505,9 +225413,9 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ zOutput = zNew; status = U_ZERO_ERROR; if( bToUpper ){ - nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); + nOut = 2LL*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); }else{ - nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); + nOut = 2LL*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); } if( U_SUCCESS(status) ){ @@ -218682,7 +225590,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ return rc; } -#if !SQLITE_CORE +#ifndef SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif @@ -219107,7 +226015,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** ** "RBU" stands for "Resumable Bulk Update". As in a large database update ** transmitted via a wireless network to a mobile device. A transaction -** applied using this extension is hence refered to as an "RBU update". +** applied using this extension is hence referred to as an "RBU update". ** ** ** LIMITATIONS @@ -219404,7 +226312,7 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open( ** the next call to sqlite3rbu_vacuum() opens a handle that starts a ** new RBU vacuum operation. ** -** As with sqlite3rbu_open(), Zipvfs users should rever to the comment +** As with sqlite3rbu_open(), Zipvfs users should refer to the comment ** describing the sqlite3rbu_create_vfs() API function below for ** a description of the complications associated with using RBU with ** zipvfs databases. @@ -219500,7 +226408,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu); ** ** If the RBU update has been completely applied, mark the RBU database ** as fully applied. Otherwise, assuming no error has occurred, save the -** current state of the RBU update appliation to the RBU database. +** current state of the RBU update application to the RBU database. ** ** If an error has already occurred as part of an sqlite3rbu_step() ** or sqlite3rbu_open() call, or if one occurs within this function, an @@ -220120,16 +227028,26 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; unsigned int v = 0; int c; unsigned char *z = (unsigned char*)*pz; - unsigned char *zStart = z; - while( (c = zValue[0x7f&*(z++)])>=0 ){ - v = (v<<6) + c; + unsigned char *zEnd = z + (*pLen); + while( z=0 ){ + v = (v<<6) + c; + z++; } - z--; - *pLen -= (int)(z - zStart); + + *pLen -= (int)(z - (unsigned char*)*pz); *pz = (char*)z; return v; } @@ -220198,21 +227116,22 @@ static int rbuDeltaApply( int lenDelta, /* Length of the delta */ char *zOut /* Write the output into this preallocated buffer */ ){ - unsigned int limit; - unsigned int total = 0; + sqlite3_uint64 limit; + sqlite3_uint64 total = 0; #if RBU_ENABLE_DELTA_CKSUM char *zOrigOut = zOut; #endif limit = rbuDeltaGetInt(&zDelta, &lenDelta); - if( *zDelta!='\n' ){ + if( lenDelta<=0 || *zDelta!='\n' ){ /* ERROR: size integer not terminated by "\n" */ return -1; } - zDelta++; lenDelta--; - while( *zDelta && lenDelta>0 ){ + zDelta++; lenDelta--; /* Skip the \n */ + while( lenDelta>0 && zDelta[0] ){ unsigned int cnt, ofst; cnt = rbuDeltaGetInt(&zDelta, &lenDelta); + if( lenDelta<=0 ) return -1; switch( zDelta[0] ){ case '@': { zDelta++; lenDelta--; @@ -220227,7 +227146,7 @@ static int rbuDeltaApply( /* ERROR: copy exceeds output file size */ return -1; } - if( (int)(ofst+cnt) > lenSrc ){ + if( (u64)ofst+(u64)cnt > (u64)lenSrc ){ /* ERROR: copy extends past end of input */ return -1; } @@ -220242,7 +227161,7 @@ static int rbuDeltaApply( /* ERROR: insert command gives an output larger than predicted */ return -1; } - if( (int)cnt>lenDelta ){ + if( cnt>lenDelta ){ /* ERROR: insert count exceeds size of delta */ return -1; } @@ -220280,7 +227199,7 @@ static int rbuDeltaApply( static int rbuDeltaOutputSize(const char *zDelta, int lenDelta){ int size; size = rbuDeltaGetInt(&zDelta, &lenDelta); - if( *zDelta!='\n' ){ + if( lenDelta<=0 || *zDelta!='\n' ){ /* ERROR: size integer not terminated by "\n" */ return -1; } @@ -220328,7 +227247,7 @@ static void rbuFossilDeltaFunc( return; } - aOut = sqlite3_malloc(nOut+1); + aOut = sqlite3_malloc64((i64)nOut+1); if( aOut==0 ){ sqlite3_result_error_nomem(context); }else{ @@ -221873,8 +228792,8 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ /* If necessary, grow the pIter->aIdxCol[] array */ if( iIdxCol==nIdxAlloc ){ - RbuSpan *aIdxCol = (RbuSpan*)sqlite3_realloc( - pIter->aIdxCol, (nIdxAlloc+16)*sizeof(RbuSpan) + RbuSpan *aIdxCol = (RbuSpan*)sqlite3_realloc64( + pIter->aIdxCol, nIdxAlloc*sizeof(RbuSpan) + 16*sizeof(RbuSpan) ); if( aIdxCol==0 ){ rc = SQLITE_NOMEM; @@ -222255,13 +229174,13 @@ static int rbuGetUpdateStmt( char *zUpdate = 0; pUp->zMask = (char*)&pUp[1]; - memcpy(pUp->zMask, zMask, pIter->nTblCol); pUp->pNext = pIter->pRbuUpdate; pIter->pRbuUpdate = pUp; if( zSet ){ const char *zPrefix = ""; - + assert( p->rc==SQLITE_OK ); + memcpy(pUp->zMask, zMask, pIter->nTblCol); if( pIter->eType!=RBU_PK_VTAB ) zPrefix = "rbu_imp_"; zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s", zPrefix, pIter->zTbl, zSet, zWhere @@ -222351,6 +229270,9 @@ static RbuState *rbuLoadState(sqlite3rbu *p){ case RBU_STATE_ROW: pRet->nRow = sqlite3_column_int(pStmt, 1); + if( pRet->nRow<0 ){ + rc = SQLITE_CORRUPT; + } break; case RBU_STATE_PROGRESS: @@ -224426,7 +231348,7 @@ static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ /* If this is an RBU vacuum operation and this is the target database, ** pretend that it has at least one page. Otherwise, SQLite will not - ** check for the existance of a *-wal file. rbuVfsRead() contains + ** check for the existence of a *-wal file. rbuVfsRead() contains ** similar logic. */ if( rc==SQLITE_OK && *pSize==0 && p->pRbu && rbuIsVacuum(p->pRbu) @@ -226009,8 +232931,8 @@ typedef struct DbpageCursor DbpageCursor; struct DbpageCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ - int pgno; /* Current page number */ - int mxPgno; /* Last page to visit on this scan */ + Pgno pgno; /* Current page number */ + Pgno mxPgno; /* Last page to visit on this scan */ Pager *pPager; /* Pager being read/written */ DbPage *pPage1; /* Page 1 of the database */ int iDb; /* Index of database to analyze */ @@ -226147,7 +233069,7 @@ static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ }else{ memset(pCsr, 0, sizeof(DbpageCursor)); pCsr->base.pVtab = pVTab; - pCsr->pgno = -1; + pCsr->pgno = 0; } *ppCursor = (sqlite3_vtab_cursor *)pCsr; @@ -226200,7 +233122,8 @@ static int dbpageFilter( sqlite3 *db = pTab->db; Btree *pBt; - (void)idxStr; + UNUSED_PARAMETER(idxStr); + UNUSED_PARAMETER(argc); /* Default setting is no rows of result */ pCsr->pgno = 1; @@ -226221,12 +233144,13 @@ static int dbpageFilter( pCsr->szPage = sqlite3BtreeGetPageSize(pBt); pCsr->mxPgno = sqlite3BtreeLastPage(pBt); if( idxNum & 1 ){ + i64 iPg = sqlite3_value_int64(argv[idxNum>>1]); assert( argc>(idxNum>>1) ); - pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]); - if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){ + if( iPg<1 || iPg>pCsr->mxPgno ){ pCsr->pgno = 1; pCsr->mxPgno = 0; }else{ + pCsr->pgno = (Pgno)iPg; pCsr->mxPgno = pCsr->pgno; } }else{ @@ -226246,12 +233170,12 @@ static int dbpageColumn( int rc = SQLITE_OK; switch( i ){ case 0: { /* pgno */ - sqlite3_result_int(ctx, pCsr->pgno); + sqlite3_result_int64(ctx, (sqlite3_int64)pCsr->pgno); break; } case 1: { /* data */ DbPage *pDbPage = 0; - if( pCsr->pgno==((PENDING_BYTE/pCsr->szPage)+1) ){ + if( pCsr->pgno==(Pgno)((PENDING_BYTE/pCsr->szPage)+1) ){ /* The pending byte page. Assume it is zeroed out. Attempting to ** request this page from the page is an SQLITE_CORRUPT error. */ sqlite3_result_zeroblob(ctx, pCsr->szPage); @@ -226280,6 +233204,24 @@ static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ return SQLITE_OK; } +/* +** Open write transactions. Since we do not know in advance which database +** files will be written by the sqlite_dbpage virtual table, start a write +** transaction on them all. +** +** Return SQLITE_OK if successful, or an SQLite error code otherwise. +*/ +static int dbpageBeginTrans(DbpageTable *pTab){ + sqlite3 *db = pTab->db; + int rc = SQLITE_OK; + int i; + for(i=0; rc==SQLITE_OK && inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt ) rc = sqlite3BtreeBeginTrans(pBt, 1, 0); + } + return rc; +} + static int dbpageUpdate( sqlite3_vtab *pVtab, int argc, @@ -226307,10 +233249,10 @@ static int dbpageUpdate( goto update_fail; } if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ - pgno = (Pgno)sqlite3_value_int(argv[2]); + pgno = (Pgno)sqlite3_value_int64(argv[2]); isInsert = 1; }else{ - pgno = sqlite3_value_int(argv[0]); + pgno = (Pgno)sqlite3_value_int64(argv[0]); if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){ zErr = "cannot insert"; goto update_fail; @@ -226340,13 +233282,19 @@ static int dbpageUpdate( /* "INSERT INTO dbpage($PGNO,NULL)" causes page number $PGNO and ** all subsequent pages to be deleted. */ pTab->iDbTrunc = iDb; - pgno--; - pTab->pgnoTrunc = pgno; + pTab->pgnoTrunc = pgno-1; + pgno = 1; }else{ zErr = "bad page value"; goto update_fail; } } + + if( dbpageBeginTrans(pTab)!=SQLITE_OK ){ + zErr = "failed to open transaction"; + goto update_fail; + } + pPager = sqlite3BtreePager(pBt); rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0); if( rc==SQLITE_OK ){ @@ -226357,27 +233305,21 @@ static int dbpageUpdate( pTab->pgnoTrunc = 0; } } + if( rc!=SQLITE_OK ){ + pTab->pgnoTrunc = 0; + } sqlite3PagerUnref(pDbPage); return rc; update_fail: + pTab->pgnoTrunc = 0; sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = sqlite3_mprintf("%s", zErr); return SQLITE_ERROR; } -/* Since we do not know in advance which database files will be -** written by the sqlite_dbpage virtual table, start a write transaction -** on them all. -*/ static int dbpageBegin(sqlite3_vtab *pVtab){ DbpageTable *pTab = (DbpageTable *)pVtab; - sqlite3 *db = pTab->db; - int i; - for(i=0; inDb; i++){ - Btree *pBt = db->aDb[i].pBt; - if( pBt ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0); - } pTab->pgnoTrunc = 0; return SQLITE_OK; } @@ -226389,7 +233331,11 @@ static int dbpageSync(sqlite3_vtab *pVtab){ if( pTab->pgnoTrunc>0 ){ Btree *pBt = pTab->db->aDb[pTab->iDbTrunc].pBt; Pager *pPager = sqlite3BtreePager(pBt); - sqlite3PagerTruncateImage(pPager, pTab->pgnoTrunc); + sqlite3BtreeEnter(pBt); + if( pTab->pgnoTruncpgnoTrunc); + } + sqlite3BtreeLeave(pBt); } pTab->pgnoTrunc = 0; return SQLITE_OK; @@ -226409,7 +233355,7 @@ static int dbpageRollbackTo(sqlite3_vtab *pVtab, int notUsed1){ */ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ static sqlite3_module dbpage_module = { - 0, /* iVersion */ + 2, /* iVersion */ dbpageConnect, /* xCreate */ dbpageConnect, /* xConnect */ dbpageBestIndex, /* xBestIndex */ @@ -226442,6 +233388,567 @@ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; } #endif /* SQLITE_ENABLE_DBSTAT_VTAB */ /************** End of dbpage.c **********************************************/ +/************** Begin file carray.c ******************************************/ +/* +** 2016-06-29 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file implements a table-valued-function that +** returns the values in a C-language array. +** Examples: +** +** SELECT * FROM carray($ptr,5) +** +** The query above returns 5 integers contained in a C-language array +** at the address $ptr. $ptr is a pointer to the array of integers. +** The pointer value must be assigned to $ptr using the +** sqlite3_bind_pointer() interface with a pointer type of "carray". +** For example: +** +** static int aX[] = { 53, 9, 17, 2231, 4, 99 }; +** int i = sqlite3_bind_parameter_index(pStmt, "$ptr"); +** sqlite3_bind_pointer(pStmt, i, aX, "carray", 0); +** +** There is an optional third parameter to determine the datatype of +** the C-language array. Allowed values of the third parameter are +** 'int32', 'int64', 'double', 'char*', 'struct iovec'. Example: +** +** SELECT * FROM carray($ptr,10,'char*'); +** +** The default value of the third parameter is 'int32'. +** +** HOW IT WORKS +** +** The carray "function" is really a virtual table with the +** following schema: +** +** CREATE TABLE carray( +** value, +** pointer HIDDEN, +** count HIDDEN, +** ctype TEXT HIDDEN +** ); +** +** If the hidden columns "pointer" and "count" are unconstrained, then +** the virtual table has no rows. Otherwise, the virtual table interprets +** the integer value of "pointer" as a pointer to the array and "count" +** as the number of elements in the array. The virtual table steps through +** the array, element by element. +*/ +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_CARRAY) +/* #include "sqliteInt.h" */ +#if defined(_WIN32) || defined(__RTP__) || defined(_WRS_KERNEL) + struct iovec { + void *iov_base; + size_t iov_len; + }; +#else +# include +#endif + +/* +** Names of allowed datatypes +*/ +static const char *azCarrayType[] = { + "int32", "int64", "double", "char*", "struct iovec" +}; + +/* +** Structure used to hold the sqlite3_carray_bind() information +*/ +typedef struct carray_bind carray_bind; +struct carray_bind { + void *aData; /* The data */ + int nData; /* Number of elements */ + int mFlags; /* Control flags */ + void (*xDel)(void*); /* Destructor for aData */ + void *pDel; /* Alternative argument to xDel() */ +}; + + +/* carray_cursor is a subclass of sqlite3_vtab_cursor which will +** serve as the underlying representation of a cursor that scans +** over rows of the result +*/ +typedef struct carray_cursor carray_cursor; +struct carray_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + sqlite3_int64 iRowid; /* The rowid */ + void *pPtr; /* Pointer to the array of values */ + sqlite3_int64 iCnt; /* Number of integers in the array */ + unsigned char eType; /* One of the CARRAY_type values */ +}; + +/* +** The carrayConnect() method is invoked to create a new +** carray_vtab that describes the carray virtual table. +** +** Think of this routine as the constructor for carray_vtab objects. +** +** All this routine needs to do is: +** +** (1) Allocate the carray_vtab object and initialize all fields. +** +** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the +** result set of queries against carray will look like. +*/ +static int carrayConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + sqlite3_vtab *pNew; + int rc; + +/* Column numbers */ +#define CARRAY_COLUMN_VALUE 0 +#define CARRAY_COLUMN_POINTER 1 +#define CARRAY_COLUMN_COUNT 2 +#define CARRAY_COLUMN_CTYPE 3 + + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)"); + if( rc==SQLITE_OK ){ + pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + } + return rc; +} + +/* +** This method is the destructor for carray_cursor objects. +*/ +static int carrayDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} + +/* +** Constructor for a new carray_cursor object. +*/ +static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + carray_cursor *pCur; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Destructor for a carray_cursor. +*/ +static int carrayClose(sqlite3_vtab_cursor *cur){ + sqlite3_free(cur); + return SQLITE_OK; +} + + +/* +** Advance a carray_cursor to its next row of output. +*/ +static int carrayNext(sqlite3_vtab_cursor *cur){ + carray_cursor *pCur = (carray_cursor*)cur; + pCur->iRowid++; + return SQLITE_OK; +} + +/* +** Return values of columns for the row at which the carray_cursor +** is currently pointing. +*/ +static int carrayColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + carray_cursor *pCur = (carray_cursor*)cur; + sqlite3_int64 x = 0; + switch( i ){ + case CARRAY_COLUMN_POINTER: return SQLITE_OK; + case CARRAY_COLUMN_COUNT: x = pCur->iCnt; break; + case CARRAY_COLUMN_CTYPE: { + sqlite3_result_text(ctx, azCarrayType[pCur->eType], -1, SQLITE_STATIC); + return SQLITE_OK; + } + default: { + switch( pCur->eType ){ + case CARRAY_INT32: { + int *p = (int*)pCur->pPtr; + sqlite3_result_int(ctx, p[pCur->iRowid-1]); + return SQLITE_OK; + } + case CARRAY_INT64: { + sqlite3_int64 *p = (sqlite3_int64*)pCur->pPtr; + sqlite3_result_int64(ctx, p[pCur->iRowid-1]); + return SQLITE_OK; + } + case CARRAY_DOUBLE: { + double *p = (double*)pCur->pPtr; + sqlite3_result_double(ctx, p[pCur->iRowid-1]); + return SQLITE_OK; + } + case CARRAY_TEXT: { + const char **p = (const char**)pCur->pPtr; + sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT); + return SQLITE_OK; + } + default: { + const struct iovec *p = (struct iovec*)pCur->pPtr; + assert( pCur->eType==CARRAY_BLOB ); + sqlite3_result_blob(ctx, p[pCur->iRowid-1].iov_base, + (int)p[pCur->iRowid-1].iov_len, SQLITE_TRANSIENT); + return SQLITE_OK; + } + } + } + } + sqlite3_result_int64(ctx, x); + return SQLITE_OK; +} + +/* +** Return the rowid for the current row. In this implementation, the +** rowid is the same as the output value. +*/ +static int carrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + carray_cursor *pCur = (carray_cursor*)cur; + *pRowid = pCur->iRowid; + return SQLITE_OK; +} + +/* +** Return TRUE if the cursor has been moved off of the last +** row of output. +*/ +static int carrayEof(sqlite3_vtab_cursor *cur){ + carray_cursor *pCur = (carray_cursor*)cur; + return pCur->iRowid>pCur->iCnt; +} + +/* +** This method is called to "rewind" the carray_cursor object back +** to the first row of output. +*/ +static int carrayFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + carray_cursor *pCur = (carray_cursor *)pVtabCursor; + pCur->pPtr = 0; + pCur->iCnt = 0; + switch( idxNum ){ + case 1: { + carray_bind *pBind = sqlite3_value_pointer(argv[0], "carray-bind"); + if( pBind==0 ) break; + pCur->pPtr = pBind->aData; + pCur->iCnt = pBind->nData; + pCur->eType = pBind->mFlags & 0x07; + break; + } + case 2: + case 3: { + pCur->pPtr = sqlite3_value_pointer(argv[0], "carray"); + pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0; + if( idxNum<3 ){ + pCur->eType = CARRAY_INT32; + }else{ + unsigned char i; + const char *zType = (const char*)sqlite3_value_text(argv[2]); + for(i=0; i=sizeof(azCarrayType)/sizeof(azCarrayType[0]) ){ + pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf( + "unknown datatype: %Q", zType); + return SQLITE_ERROR; + }else{ + pCur->eType = i; + } + } + break; + } + } + pCur->iRowid = 1; + return SQLITE_OK; +} + +/* +** SQLite will invoke this method one or more times while planning a query +** that uses the carray virtual table. This routine needs to create +** a query plan for each invocation and compute an estimated cost for that +** plan. +** +** In this implementation idxNum is used to represent the +** query plan. idxStr is unused. +** +** idxNum is: +** +** 1 If only the pointer= constraint exists. In this case, the +** parameter must be bound using sqlite3_carray_bind(). +** +** 2 if the pointer= and count= constraints exist. +** +** 3 if the ctype= constraint also exists. +** +** idxNum is 0 otherwise and carray becomes an empty table. +*/ +static int carrayBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + int i; /* Loop over constraints */ + int ptrIdx = -1; /* Index of the pointer= constraint, or -1 if none */ + int cntIdx = -1; /* Index of the count= constraint, or -1 if none */ + int ctypeIdx = -1; /* Index of the ctype= constraint, or -1 if none */ + unsigned seen = 0; /* Bitmask of == constrainted columns */ + + const struct sqlite3_index_constraint *pConstraint; + pConstraint = pIdxInfo->aConstraint; + for(i=0; inConstraint; i++, pConstraint++){ + if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; + if( pConstraint->iColumn>=0 ) seen |= 1 << pConstraint->iColumn; + if( pConstraint->usable==0 ) continue; + switch( pConstraint->iColumn ){ + case CARRAY_COLUMN_POINTER: + ptrIdx = i; + break; + case CARRAY_COLUMN_COUNT: + cntIdx = i; + break; + case CARRAY_COLUMN_CTYPE: + ctypeIdx = i; + break; + } + } + if( ptrIdx>=0 ){ + pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1; + pIdxInfo->aConstraintUsage[ptrIdx].omit = 1; + pIdxInfo->estimatedCost = (double)1; + pIdxInfo->estimatedRows = 100; + pIdxInfo->idxNum = 1; + if( cntIdx>=0 ){ + pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2; + pIdxInfo->aConstraintUsage[cntIdx].omit = 1; + pIdxInfo->idxNum = 2; + if( ctypeIdx>=0 ){ + pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3; + pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1; + pIdxInfo->idxNum = 3; + }else if( seen & (1<estimatedCost = (double)2147483647; + pIdxInfo->estimatedRows = 2147483647; + pIdxInfo->idxNum = 0; + } + return SQLITE_OK; +} + +/* +** This following structure defines all the methods for the +** carray virtual table. +*/ +static sqlite3_module carrayModule = { + 0, /* iVersion */ + 0, /* xCreate */ + carrayConnect, /* xConnect */ + carrayBestIndex, /* xBestIndex */ + carrayDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + carrayOpen, /* xOpen - open a cursor */ + carrayClose, /* xClose - close a cursor */ + carrayFilter, /* xFilter - configure scan constraints */ + carrayNext, /* xNext - advance a cursor */ + carrayEof, /* xEof - check for end of scan */ + carrayColumn, /* xColumn - read data */ + carrayRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0, /* xShadow */ + 0 /* xIntegrity */ +}; + +/* +** Destructor for the carray_bind object +*/ +static void carrayBindDel(void *pPtr){ + carray_bind *p = (carray_bind*)pPtr; + if( p->xDel!=SQLITE_STATIC ){ + p->xDel(p->pDel); + } + sqlite3_free(p); +} + +/* +** Invoke this interface in order to bind to the single-argument +** version of CARRAY(). +** +** pStmt The prepared statement to which to bind +** idx The index of the parameter of pStmt to which to bind +** aData The data to be bound +** nData The number of elements in aData +** mFlags One of SQLITE_CARRAY_xxxx indicating datatype of aData +** xDestroy Destructor for pDestroy or aData if pDestroy==NULL. +** pDestroy Invoke xDestroy on this pointer if not NULL +** +** The destructor is called pDestroy if pDestroy!=NULL, or against +** aData if pDestroy==NULL. +*/ +SQLITE_API int sqlite3_carray_bind_v2( + sqlite3_stmt *pStmt, + int idx, + void *aData, + int nData, + int mFlags, + void (*xDestroy)(void*), + void *pDestroy +){ + carray_bind *pNew = 0; + int i; + int rc = SQLITE_OK; + + /* Ensure that the mFlags value is acceptable. */ + assert( CARRAY_INT32==0 && CARRAY_INT64==1 && CARRAY_DOUBLE==2 ); + assert( CARRAY_TEXT==3 && CARRAY_BLOB==4 ); + if( mFlagsCARRAY_BLOB ){ + rc = SQLITE_ERROR; + goto carray_bind_error; + } + + pNew = sqlite3_malloc64(sizeof(*pNew)); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + goto carray_bind_error; + } + + pNew->nData = nData; + pNew->mFlags = mFlags; + if( xDestroy==SQLITE_TRANSIENT ){ + sqlite3_int64 sz = nData; + switch( mFlags ){ + case CARRAY_INT32: sz *= 4; break; + case CARRAY_INT64: sz *= 8; break; + case CARRAY_DOUBLE: sz *= 8; break; + case CARRAY_TEXT: sz *= sizeof(char*); break; + default: sz *= sizeof(struct iovec); break; + } + if( mFlags==CARRAY_TEXT ){ + for(i=0; iaData = sqlite3_malloc64( sz ); + if( pNew->aData==0 ){ + rc = SQLITE_NOMEM; + goto carray_bind_error; + } + + if( mFlags==CARRAY_TEXT ){ + char **az = (char**)pNew->aData; + char *z = (char*)&az[nData]; + for(i=0; iaData; + unsigned char *z = (unsigned char*)&p[nData]; + for(i=0; iaData, aData, sz); + } + pNew->xDel = sqlite3_free; + pNew->pDel = pNew->aData; + }else{ + pNew->aData = aData; + pNew->xDel = xDestroy; + pNew->pDel = pDestroy; + } + return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel); + + carray_bind_error: + if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){ + xDestroy(pDestroy); + } + sqlite3_free(pNew); + return rc; +} + +/* +** Invoke this interface in order to bind to the single-argument +** version of CARRAY(). Same as sqlite3_carray_bind_v2() with the +** pDestroy parameter set to NULL. +*/ +SQLITE_API int sqlite3_carray_bind( + sqlite3_stmt *pStmt, + int idx, + void *aData, + int nData, + int mFlags, + void (*xDestroy)(void*) +){ + return sqlite3_carray_bind_v2(pStmt,idx,aData,nData,mFlags,xDestroy,aData); +} + +/* +** Invoke this routine to register the carray() function. +*/ +SQLITE_PRIVATE Module *sqlite3CarrayRegister(sqlite3 *db){ + return sqlite3VtabCreateModule(db, "carray", &carrayModule, 0, 0); +} + +#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_CARRAY) */ + +/************** End of carray.c **********************************************/ /************** Begin file sqlite3session.c **********************************/ #if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) @@ -226584,11 +234091,13 @@ struct sqlite3_changeset_iter { struct SessionTable { SessionTable *pNext; char *zName; /* Local name of table */ - int nCol; /* Number of columns in table zName */ + int nCol; /* Number of non-hidden columns */ + int nTotalCol; /* Number of columns including hidden */ int bStat1; /* True if this is sqlite_stat1 */ int bRowid; /* True if this table uses rowid for PK */ const char **azCol; /* Column names */ const char **azDflt; /* Default value expressions */ + int *aiIdx; /* Index to pass to xNew/xOld */ u8 *abPK; /* Array of primary key flags */ int nEntry; /* Total number of entries in hash table */ int nChange; /* Size of apChange[] array */ @@ -226792,6 +234301,21 @@ static int sessionVarintGet(const u8 *aBuf, int *piVal){ return getVarint32(aBuf, *piVal); } +/* +** Read a varint value from buffer aBuf[], size nBuf bytes, into *piVal. +** Return the number of bytes read. +*/ +static int sessionVarintGetSafe(const u8 *aBuf, int nBuf, int *piVal){ + u8 aCopy[9]; + const u8 *aRead = aBuf; + memset(aCopy, 0, sizeof(aCopy)); + if( nBuf> 0) & 0xFF; } +/* +** Write a double value to the buffer aBuf[]. +*/ +static void sessionPutDouble(u8 *aBuf, double r){ + /* TODO: SQLite does something special to deal with mixed-endian + ** floating point values (e.g. ARM7). This code probably should + ** too. */ + u64 i; + assert( sizeof(double)==8 && sizeof(u64)==8 ); + memcpy(&i, &r, 8); + sessionPutI64(aBuf, i); +} + /* ** This function is used to serialize the contents of value pValue (see ** comment titled "RECORD FORMAT" above). @@ -226857,16 +234394,13 @@ static int sessionSerializeValue( /* TODO: SQLite does something special to deal with mixed-endian ** floating point values (e.g. ARM7). This code probably should ** too. */ - u64 i; if( eType==SQLITE_INTEGER ){ - i = (u64)sqlite3_value_int64(pValue); + u64 i = (u64)sqlite3_value_int64(pValue); + sessionPutI64(&aBuf[1], i); }else{ - double r; - assert( sizeof(double)==8 && sizeof(u64)==8 ); - r = sqlite3_value_double(pValue); - memcpy(&i, &r, 8); + double r = sqlite3_value_double(pValue); + sessionPutDouble(&aBuf[1], r); } - sessionPutI64(&aBuf[1], i); } nByte = 9; break; @@ -226991,22 +234525,22 @@ static int sessionPreupdateHash( unsigned int h = 0; /* Hash value to return */ int i; /* Used to iterate through columns */ + assert( pTab->nTotalCol==pSession->hook.xCount(pSession->hook.pCtx) ); if( pTab->bRowid ){ - assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) ); h = sessionHashAppendI64(h, iRowid); }else{ assert( *pbNullPK==0 ); - assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) ); for(i=0; inCol; i++){ if( pTab->abPK[i] ){ int rc; int eType; sqlite3_value *pVal; + int iIdx = pTab->aiIdx[i]; if( bNew ){ - rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal); + rc = pSession->hook.xNew(pSession->hook.pCtx, iIdx, &pVal); }else{ - rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal); + rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &pVal); } if( rc!=SQLITE_OK ) return rc; @@ -227056,10 +234590,11 @@ static int sessionSerialLen(const u8 *a){ int n; assert( a!=0 ); e = *a; - if( e==0 || e==0xFF ) return 1; - if( e==SQLITE_NULL ) return 1; if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9; - return sessionVarintGet(&a[1], &n) + 1 + n; + if( e==SQLITE_TEXT || e==SQLITE_BLOB ){ + return sessionVarintGet(&a[1], &n) + 1 + n; + } + return 1; } /* @@ -227082,31 +234617,31 @@ static unsigned int sessionChangeHash( u8 *a = aRecord; /* Used to iterate through change record */ for(i=0; inCol; i++){ - int eType = *a; int isPK = pTab->abPK[i]; if( bPkOnly && isPK==0 ) continue; - /* It is not possible for eType to be SQLITE_NULL here. The session - ** module does not record changes for rows with NULL values stored in - ** primary key columns. */ - assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT - || eType==SQLITE_TEXT || eType==SQLITE_BLOB - || eType==SQLITE_NULL || eType==0 - ); - assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) ); - if( isPK ){ - a++; + int eType = *a++; + + assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT + || eType==SQLITE_TEXT || eType==SQLITE_BLOB + || eType==SQLITE_NULL || eType==0 + ); + h = sessionHashAppendType(h, eType); if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ h = sessionHashAppendI64(h, sessionGetI64(a)); a += 8; - }else{ + }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ int n; a += sessionVarintGet(a, &n); h = sessionHashAppendBlob(h, n, a); a += n; } + /* It should not be possible for eType to be SQLITE_NULL or 0x00 here, + ** as the session module does not record changes for rows with NULL + ** values stored in primary key columns. But a corrupt changesets + ** may contain such a value. */ }else{ a += sessionSerialLen(a); } @@ -227343,6 +234878,7 @@ static int sessionPreupdateEqual( sqlite3_value *pVal; /* Value returned by preupdate_new/old */ int rc; /* Error code from preupdate_new/old */ int eType = *a++; /* Type of value from change record */ + int iIdx = pTab->aiIdx[iCol]; /* The following calls to preupdate_new() and preupdate_old() can not ** fail. This is because they cache their return values, and by the @@ -227351,10 +234887,10 @@ static int sessionPreupdateEqual( ** this (that the method has already been called). */ if( op==SQLITE_INSERT ){ /* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */ - rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal); + rc = pSession->hook.xNew(pSession->hook.pCtx, iIdx, &pVal); }else{ /* assert( db->pPreUpdate->pUnpacked ); */ - rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal); + rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &pVal); } assert( rc==SQLITE_OK ); (void)rc; /* Suppress warning about unused variable */ @@ -227479,9 +235015,11 @@ static int sessionTableInfo( const char *zDb, /* Name of attached database (e.g. "main") */ const char *zThis, /* Table name */ int *pnCol, /* OUT: number of columns */ + int *pnTotalCol, /* OUT: number of hidden columns */ const char **pzTab, /* OUT: Copy of zThis */ const char ***pazCol, /* OUT: Array of column names for table */ const char ***pazDflt, /* OUT: Array of default value expressions */ + int **paiIdx, /* OUT: Array of xNew/xOld indexes */ u8 **pabPK, /* OUT: Array of booleans - true for PK col */ int *pbRowid /* OUT: True if only PK is a rowid */ ){ @@ -227496,6 +235034,7 @@ static int sessionTableInfo( char **azCol = 0; char **azDflt = 0; u8 *abPK = 0; + int *aiIdx = 0; int bRowid = 0; /* Set to true to use rowid as PK */ assert( pazCol && pabPK ); @@ -227503,6 +235042,8 @@ static int sessionTableInfo( *pazCol = 0; *pabPK = 0; *pnCol = 0; + if( pnTotalCol ) *pnTotalCol = 0; + if( paiIdx ) *paiIdx = 0; if( pzTab ) *pzTab = 0; if( pazDflt ) *pazDflt = 0; @@ -227512,9 +235053,9 @@ static int sessionTableInfo( if( rc==SQLITE_OK ){ /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */ zPragma = sqlite3_mprintf( - "SELECT 0, 'tbl', '', 0, '', 1 UNION ALL " - "SELECT 1, 'idx', '', 0, '', 2 UNION ALL " - "SELECT 2, 'stat', '', 0, '', 0" + "SELECT 0, 'tbl', '', 0, '', 1, 0 UNION ALL " + "SELECT 1, 'idx', '', 0, '', 2, 0 UNION ALL " + "SELECT 2, 'stat', '', 0, '', 0, 0" ); }else if( rc==SQLITE_ERROR ){ zPragma = sqlite3_mprintf(""); @@ -227522,7 +235063,7 @@ static int sessionTableInfo( return rc; } }else{ - zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); + zPragma = sqlite3_mprintf("PRAGMA '%q'.table_xinfo('%q')", zDb, zThis); } if( !zPragma ){ return SQLITE_NOMEM; @@ -227539,7 +235080,9 @@ static int sessionTableInfo( while( SQLITE_ROW==sqlite3_step(pStmt) ){ nByte += sqlite3_column_bytes(pStmt, 1); /* name */ nByte += sqlite3_column_bytes(pStmt, 4); /* dflt_value */ - nDbCol++; + if( sqlite3_column_int(pStmt, 6)==0 ){ /* !hidden */ + nDbCol++; + } if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; /* pk */ } if( nDbCol==0 ) bRowid = 0; @@ -227548,7 +235091,7 @@ static int sessionTableInfo( rc = sqlite3_reset(pStmt); if( rc==SQLITE_OK ){ - nByte += nDbCol * (sizeof(const char *)*2 + sizeof(u8) + 1 + 1); + nByte += nDbCol * (sizeof(const char *)*2 +sizeof(int)+sizeof(u8) + 1 + 1); pAlloc = sessionMalloc64(pSession, nByte); if( pAlloc==0 ){ rc = SQLITE_NOMEM; @@ -227559,8 +235102,8 @@ static int sessionTableInfo( if( rc==SQLITE_OK ){ azCol = (char **)pAlloc; azDflt = (char**)&azCol[nDbCol]; - pAlloc = (u8 *)&azDflt[nDbCol]; - abPK = (u8 *)pAlloc; + aiIdx = (int*)&azDflt[nDbCol]; + abPK = (u8 *)&aiIdx[nDbCol]; pAlloc = &abPK[nDbCol]; if( pzTab ){ memcpy(pAlloc, zThis, nThis+1); @@ -227575,27 +235118,32 @@ static int sessionTableInfo( azCol[i] = (char*)pAlloc; pAlloc += nName+1; abPK[i] = 1; + aiIdx[i] = -1; i++; } while( SQLITE_ROW==sqlite3_step(pStmt) ){ - int nName = sqlite3_column_bytes(pStmt, 1); - int nDflt = sqlite3_column_bytes(pStmt, 4); - const unsigned char *zName = sqlite3_column_text(pStmt, 1); - const unsigned char *zDflt = sqlite3_column_text(pStmt, 4); - - if( zName==0 ) break; - memcpy(pAlloc, zName, nName+1); - azCol[i] = (char *)pAlloc; - pAlloc += nName+1; - if( zDflt ){ - memcpy(pAlloc, zDflt, nDflt+1); - azDflt[i] = (char *)pAlloc; - pAlloc += nDflt+1; - }else{ - azDflt[i] = 0; + if( sqlite3_column_int(pStmt, 6)==0 ){ /* !hidden */ + int nName = sqlite3_column_bytes(pStmt, 1); + int nDflt = sqlite3_column_bytes(pStmt, 4); + const unsigned char *zName = sqlite3_column_text(pStmt, 1); + const unsigned char *zDflt = sqlite3_column_text(pStmt, 4); + + if( zName==0 ) break; + memcpy(pAlloc, zName, nName+1); + azCol[i] = (char *)pAlloc; + pAlloc += nName+1; + if( zDflt ){ + memcpy(pAlloc, zDflt, nDflt+1); + azDflt[i] = (char *)pAlloc; + pAlloc += nDflt+1; + }else{ + azDflt[i] = 0; + } + abPK[i] = sqlite3_column_int(pStmt, 5); + aiIdx[i] = sqlite3_column_int(pStmt, 0); + i++; } - abPK[i] = sqlite3_column_int(pStmt, 5); - i++; + if( pnTotalCol ) (*pnTotalCol)++; } rc = sqlite3_reset(pStmt); } @@ -227608,6 +235156,7 @@ static int sessionTableInfo( if( pazDflt ) *pazDflt = (const char**)azDflt; *pabPK = abPK; *pnCol = nDbCol; + if( paiIdx ) *paiIdx = aiIdx; }else{ sessionFree(pSession, azCol); } @@ -227619,7 +235168,7 @@ static int sessionTableInfo( /* ** This function is called to initialize the SessionTable.nCol, azCol[] ** abPK[] and azDflt[] members of SessionTable object pTab. If these -** fields are already initilialized, this function is a no-op. +** fields are already initialized, this function is a no-op. ** ** If an error occurs, an error code is stored in sqlite3_session.rc and ** non-zero returned. Or, if no error occurs but the table has no primary @@ -227638,8 +235187,11 @@ static int sessionInitTable( if( pTab->nCol==0 ){ u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); + sqlite3_free(pTab->azCol); + pTab->abPK = 0; rc = sessionTableInfo(pSession, db, zDb, - pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->azDflt, &abPK, + pTab->zName, &pTab->nCol, &pTab->nTotalCol, 0, &pTab->azCol, + &pTab->azDflt, &pTab->aiIdx, &abPK, ((pSession==0 || pSession->bImplicitPK) ? &pTab->bRowid : 0) ); if( rc==SQLITE_OK ){ @@ -227674,15 +235226,17 @@ static int sessionInitTable( */ static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){ int nCol = 0; + int nTotalCol = 0; const char **azCol = 0; const char **azDflt = 0; + int *aiIdx = 0; u8 *abPK = 0; int bRowid = 0; assert( pSession->rc==SQLITE_OK ); pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb, - pTab->zName, &nCol, 0, &azCol, &azDflt, &abPK, + pTab->zName, &nCol, &nTotalCol, 0, &azCol, &azDflt, &aiIdx, &abPK, (pSession->bImplicitPK ? &bRowid : 0) ); if( pSession->rc==SQLITE_OK ){ @@ -227705,8 +235259,10 @@ static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){ const char **a = pTab->azCol; pTab->azCol = azCol; pTab->nCol = nCol; + pTab->nTotalCol = nTotalCol; pTab->azDflt = azDflt; pTab->abPK = abPK; + pTab->aiIdx = aiIdx; azCol = a; } if( pSession->bEnableSize ){ @@ -227777,9 +235333,7 @@ static void sessionUpdateOneChange( case SQLITE_FLOAT: { double rVal = sqlite3_column_double(pDflt, iField); - i64 iVal = 0; - memcpy(&iVal, &rVal, sizeof(rVal)); - sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal); + sessionPutDouble(&pNew->aRecord[pNew->nRecord], rVal); pNew->nRecord += 8; break; } @@ -227875,7 +235429,7 @@ static void sessionAppendStr( int *pRc ){ int nStr = sqlite3Strlen30(zStr); - if( 0==sessionBufferGrow(p, nStr+1, pRc) ){ + if( 0==sessionBufferGrow(p, (i64)nStr+1, pRc) ){ memcpy(&p->aBuf[p->nBuf], zStr, nStr); p->nBuf += nStr; p->aBuf[p->nBuf] = 0x00; @@ -227943,6 +235497,16 @@ static int sessionPrepareDfltStmt( return rc; } +/* +** Finalize statement pStmt. If (*pRc) is SQLITE_OK when this function is +** called, set it to the results of the sqlite3_finalize() call. Or, if +** it is already set to an error code, leave it as is. +*/ +static void sessionFinalizeStmt(sqlite3_stmt *pStmt, int *pRc){ + int rc = sqlite3_finalize(pStmt); + if( *pRc==SQLITE_OK ) *pRc = rc; +} + /* ** Table pTab has one or more existing change-records with old.* records ** with fewer than pTab->nCol columns. This function updates all such @@ -227965,9 +235529,8 @@ static int sessionUpdateChanges(sqlite3_session *pSession, SessionTable *pTab){ } } + sessionFinalizeStmt(pStmt, &rc); pSession->rc = rc; - rc = sqlite3_finalize(pStmt); - if( pSession->rc==SQLITE_OK ) pSession->rc = rc; return pSession->rc; } @@ -228024,7 +235587,7 @@ static int sessionUpdateMaxSize( int ii; for(ii=0; iinCol; ii++){ sqlite3_value *p = 0; - pSession->hook.xNew(pSession->hook.pCtx, ii, &p); + pSession->hook.xNew(pSession->hook.pCtx, pTab->aiIdx[ii], &p); sessionSerializeValue(0, p, &nNew); } } @@ -228044,8 +235607,9 @@ static int sessionUpdateMaxSize( int bChanged = 1; int nOld = 0; int eType; + int iIdx = pTab->aiIdx[ii]; sqlite3_value *p = 0; - pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p); + pSession->hook.xNew(pSession->hook.pCtx, iIdx, &p); if( p==0 ){ return SQLITE_NOMEM; } @@ -228142,11 +235706,11 @@ static void sessionPreupdateOneChange( /* Check the number of columns in this xPreUpdate call matches the ** number of columns in the table. */ nExpect = pSession->hook.xCount(pSession->hook.pCtx); - if( (pTab->nCol-pTab->bRowid)nTotalColnCol-pTab->bRowid)!=nExpect ){ + if( pTab->nTotalCol!=nExpect ){ pSession->rc = SQLITE_SCHEMA; return; } @@ -228203,14 +235767,15 @@ static void sessionPreupdateOneChange( /* Figure out how large an allocation is required */ nByte = sizeof(SessionChange); - for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ + for(i=pTab->bRowid; inCol; i++){ + int iIdx = pTab->aiIdx[i]; sqlite3_value *p = 0; if( op!=SQLITE_INSERT ){ /* This may fail if the column has a non-NULL default and was added ** using ALTER TABLE ADD COLUMN after this record was created. */ - rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p); + rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &p); }else if( pTab->abPK[i] ){ - TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p); + TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx,iIdx,&p); assert( trc==SQLITE_OK ); } @@ -228245,12 +235810,13 @@ static void sessionPreupdateOneChange( sessionPutI64(&pC->aRecord[1], iRowid); nByte = 9; } - for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ + for(i=pTab->bRowid; inCol; i++){ sqlite3_value *p = 0; + int iIdx = pTab->aiIdx[i]; if( op!=SQLITE_INSERT ){ - pSession->hook.xOld(pSession->hook.pCtx, i, &p); + pSession->hook.xOld(pSession->hook.pCtx, iIdx, &p); }else if( pTab->abPK[i] ){ - pSession->hook.xNew(pSession->hook.pCtx, i, &p); + pSession->hook.xNew(pSession->hook.pCtx, iIdx, &p); } sessionSerializeValue(&pC->aRecord[nByte], p, &nByte); } @@ -228532,7 +236098,7 @@ static int sessionDiffFindNew( rc = SQLITE_NOMEM; }else{ sqlite3_stmt *pStmt; - rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0); + rc = sqlite3_prepare_v2(pSession->db, zStmt, -1, &pStmt, 0); if( rc==SQLITE_OK ){ SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx; pDiffCtx->pStmt = pStmt; @@ -228595,7 +236161,7 @@ static int sessionDiffFindModified( rc = SQLITE_NOMEM; }else{ sqlite3_stmt *pStmt; - rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0); + rc = sqlite3_prepare_v2(pSession->db, zStmt, -1, &pStmt, 0); if( rc==SQLITE_OK ){ SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx; @@ -228637,7 +236203,9 @@ SQLITE_API int sqlite3session_diff( SessionTable *pTo; /* Table zTbl */ /* Locate and if necessary initialize the target table object */ + pSession->bAutoAttach++; rc = sessionFindTable(pSession, zTbl, &pTo); + pSession->bAutoAttach--; if( pTo==0 ) goto diff_out; if( sessionInitTable(pSession, pTo, pSession->db, pSession->zDb) ){ rc = pSession->rc; @@ -228648,16 +236216,43 @@ SQLITE_API int sqlite3session_diff( if( rc==SQLITE_OK ){ int bHasPk = 0; int bMismatch = 0; - int nCol; /* Columns in zFrom.zTbl */ + int nCol = 0; /* Columns in zFrom.zTbl */ int bRowid = 0; - u8 *abPK; + u8 *abPK = 0; const char **azCol = 0; - rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, 0, &abPK, - pSession->bImplicitPK ? &bRowid : 0 - ); + char *zDbExists = 0; + + /* Check that database zFrom is attached. */ + zDbExists = sqlite3_mprintf("SELECT * FROM %Q.sqlite_schema", zFrom); + if( zDbExists==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_stmt *pDbExists = 0; + rc = sqlite3_prepare_v2(db, zDbExists, -1, &pDbExists, 0); + if( rc==SQLITE_ERROR ){ + rc = SQLITE_OK; + nCol = -1; + } + sqlite3_finalize(pDbExists); + sqlite3_free(zDbExists); + } + + if( rc==SQLITE_OK && nCol==0 ){ + rc = sessionTableInfo(0, db, zFrom, zTbl, + &nCol, 0, 0, &azCol, 0, 0, &abPK, + pSession->bImplicitPK ? &bRowid : 0 + ); + } if( rc==SQLITE_OK ){ if( pTo->nCol!=nCol ){ - bMismatch = 1; + if( nCol<=0 ){ + rc = SQLITE_SCHEMA; + if( pzErrMsg ){ + *pzErrMsg = sqlite3_mprintf("no such table: %s.%s", zFrom, zTbl); + } + }else{ + bMismatch = 1; + } }else{ int i; for(i=0; iaBuf[p->nBuf]; const char *zIn = zStr; *zOut++ = '"'; - while( *zIn ){ - if( *zIn=='"' ) *zOut++ = '"'; - *zOut++ = *(zIn++); + if( zIn!=0 ){ + while( *zIn ){ + if( *zIn=='"' ) *zOut++ = '"'; + *zOut++ = *(zIn++); + } } *zOut++ = '"'; p->nBuf = (int)((u8 *)zOut - p->aBuf); @@ -229002,15 +236599,14 @@ static void sessionAppendCol( int eType = sqlite3_column_type(pStmt, iCol); sessionAppendByte(p, (u8)eType, pRc); if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - sqlite3_int64 i; u8 aBuf[8]; if( eType==SQLITE_INTEGER ){ - i = sqlite3_column_int64(pStmt, iCol); + sqlite3_int64 i = sqlite3_column_int64(pStmt, iCol); + sessionPutI64(aBuf, i); }else{ double r = sqlite3_column_double(pStmt, iCol); - memcpy(&i, &r, 8); + sessionPutDouble(aBuf, r); } - sessionPutI64(aBuf, i); sessionAppendBlob(p, aBuf, 8, pRc); } if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){ @@ -229203,6 +236799,19 @@ static int sessionAppendDelete( return rc; } +static int sessionPrepare( + sqlite3 *db, + sqlite3_stmt **pp, + char **pzErrmsg, + const char *zSql +){ + int rc = sqlite3_prepare_v2(db, zSql, -1, pp, 0); + if( pzErrmsg && rc!=SQLITE_OK ){ + *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + } + return rc; +} + /* ** Formulate and prepare a SELECT statement to retrieve a row from table ** zTab in database zDb based on its primary key. i.e. @@ -229224,15 +236833,15 @@ static int sessionSelectStmt( int nCol, /* Number of columns in table */ const char **azCol, /* Names of table columns */ u8 *abPK, /* PRIMARY KEY array */ - sqlite3_stmt **ppStmt /* OUT: Prepared SELECT statement */ + sqlite3_stmt **ppStmt, /* OUT: Prepared SELECT statement */ + char **pzErrmsg /* OUT: Error message */ ){ int rc = SQLITE_OK; char *zSql = 0; const char *zSep = ""; - const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*"; - int nSql = -1; int i; + SessionBuffer cols = {0, 0, 0}; SessionBuffer nooptest = {0, 0, 0}; SessionBuffer pkfield = {0, 0, 0}; SessionBuffer pkvar = {0, 0, 0}; @@ -229245,9 +236854,16 @@ static int sessionSelectStmt( sessionAppendStr(&pkvar, "?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc ); - zCols = "tbl, ?2, stat"; + sessionAppendStr(&cols, "tbl, ?2, stat", &rc); }else{ +#if 0 + if( bRowid ){ + sessionAppendStr(&cols, SESSIONS_ROWID, &rc); + } +#endif for(i=0; idb; /* Source database handle */ SessionTable *pTab; /* Used to iterate through attached tables */ - SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */ + SessionBuffer buf = {0,0,0}; /* Buffer in which to accumulate changeset */ int rc; /* Return code */ assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0) ); @@ -229439,10 +237056,13 @@ static int sessionGenerateChangeset( } if( pSession->rc ) return pSession->rc; - rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0); - if( rc!=SQLITE_OK ) return rc; sqlite3_mutex_enter(sqlite3_db_mutex(db)); + rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0); + if( rc!=SQLITE_OK ){ + sqlite3_mutex_leave(sqlite3_db_mutex(db)); + return rc; + } for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ if( pTab->nEntry ){ @@ -229465,7 +237085,7 @@ static int sessionGenerateChangeset( /* Build and compile a statement to execute: */ if( rc==SQLITE_OK ){ rc = sessionSelectStmt(db, 0, pSession->zDb, - zName, pTab->bRowid, pTab->nCol, pTab->azCol, pTab->abPK, &pSel + zName, pTab->bRowid, pTab->nCol, pTab->azCol, pTab->abPK, &pSel, 0 ); } @@ -229776,14 +237396,15 @@ SQLITE_API int sqlite3changeset_start_v2_strm( ** object and the buffer is full, discard some data to free up space. */ static void sessionDiscardData(SessionInput *pIn){ - if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){ - int nMove = pIn->buf.nBuf - pIn->iNext; + if( pIn->xInput && pIn->iCurrent>=sessions_strm_chunk_size ){ + int nMove = pIn->buf.nBuf - pIn->iCurrent; assert( nMove>=0 ); if( nMove>0 ){ - memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove); + memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iCurrent], nMove); } - pIn->buf.nBuf -= pIn->iNext; - pIn->iNext = 0; + pIn->buf.nBuf -= pIn->iCurrent; + pIn->iNext -= pIn->iCurrent; + pIn->iCurrent = 0; pIn->nData = pIn->buf.nBuf; } } @@ -229924,7 +237545,8 @@ static int sessionReadRecord( u8 *aVal = &pIn->aData[pIn->iNext]; if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ int nByte; - pIn->iNext += sessionVarintGet(aVal, &nByte); + int nRem = pIn->nData - pIn->iNext; + pIn->iNext += sessionVarintGetSafe(aVal, nRem, &nByte); rc = sessionInputBuffer(pIn, nByte); if( rc==SQLITE_OK ){ if( nByte<0 || nByte>pIn->nData-pIn->iNext ){ @@ -229977,7 +237599,8 @@ static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){ rc = sessionInputBuffer(pIn, 9); if( rc==SQLITE_OK ){ - nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol); + int nBuf = pIn->nData - pIn->iNext; + nRead += sessionVarintGetSafe(&pIn->aData[pIn->iNext], nBuf, &nCol); /* The hard upper limit for the number of columns in an SQLite ** database table is, according to sqliteLimit.h, 32676. So ** consider any table-header that purports to have more than 65536 @@ -229997,8 +237620,15 @@ static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){ while( (pIn->iNext + nRead)nData && pIn->aData[pIn->iNext + nRead] ){ nRead++; } + + /* Break out of the loop if if the nul-terminator byte has been found. + ** Otherwise, read some more input data and keep seeking. If there is + ** no more input data, consider the changeset corrupt. */ if( (pIn->iNext + nRead)nData ) break; rc = sessionInputBuffer(pIn, nRead + 100); + if( rc==SQLITE_OK && (pIn->iNext + nRead)>=pIn->nData ){ + rc = SQLITE_CORRUPT_BKPT; + } } *pnByte = nRead+1; return rc; @@ -230019,7 +237649,7 @@ static int sessionChangesetBufferRecord( int *pnByte /* OUT: Size of record in bytes */ ){ int rc = SQLITE_OK; - int nByte = 0; + i64 nByte = 0; int i; for(i=0; rc==SQLITE_OK && iaData[pIn->iNext + nByte++]; if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ int n; - nByte += sessionVarintGet(&pIn->aData[pIn->iNext+nByte], &n); + int nRem = pIn->nData - (pIn->iNext + nByte); + nByte += sessionVarintGetSafe(&pIn->aData[pIn->iNext+nByte], nRem, &n); nByte += n; rc = sessionInputBuffer(pIn, nByte); }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ nByte += 8; + }else if( eType!=0 && eType!=SQLITE_NULL ){ + rc = SQLITE_CORRUPT_BKPT; } } + if( rc==SQLITE_OK && (pIn->iNext+nByte)>pIn->nData ){ + rc = SQLITE_CORRUPT_BKPT; + } } *pnByte = nByte; return rc; @@ -230130,15 +237766,15 @@ static int sessionChangesetNextOne( memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2); } - /* Make sure the buffer contains at least 10 bytes of input data, or all - ** remaining data if there are less than 10 bytes available. This is - ** sufficient either for the 'T' or 'P' byte and the varint that follows - ** it, or for the two single byte values otherwise. */ + /* Make sure the buffer contains at least 2 bytes of input data, or all + ** remaining data if there are less than 2 bytes available. This is + ** sufficient either for the 'T' or 'P' byte that begins a new table, + ** or for the "op" and "bIndirect" single bytes otherwise. */ p->rc = sessionInputBuffer(&p->in, 2); if( p->rc!=SQLITE_OK ) return p->rc; - sessionDiscardData(&p->in); p->in.iCurrent = p->in.iNext; + sessionDiscardData(&p->in); /* If the iterator is already at the end of the changeset, return DONE. */ if( p->in.iNext>=p->in.nData ){ @@ -230163,11 +237799,13 @@ static int sessionChangesetNextOne( return (p->rc = SQLITE_CORRUPT_BKPT); } - p->op = op; - p->bIndirect = p->in.aData[p->in.iNext++]; - if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){ + if( (op!=SQLITE_UPDATE && op!=SQLITE_DELETE && op!=SQLITE_INSERT) + || (p->in.iNext>=p->in.nData) + ){ return (p->rc = SQLITE_CORRUPT_BKPT); } + p->op = op; + p->bIndirect = p->in.aData[p->in.iNext++]; if( paRec ){ int nVal; /* Number of values to buffer */ @@ -230476,7 +238114,13 @@ static int sessionChangesetInvert( /* Test for EOF. */ if( (rc = sessionInputBuffer(pInput, 2)) ) goto finished_invert; - if( pInput->iNext>=pInput->nData ) break; + if( pInput->iNext+1>=pInput->nData ){ + if( pInput->iNext!=pInput->nData ){ + rc = SQLITE_CORRUPT_BKPT; + goto finished_invert; + } + break; + } eType = pInput->aData[pInput->iNext]; switch( eType ){ @@ -230672,7 +238316,9 @@ struct SessionApplyCtx { u8 bRebaseStarted; /* If table header is already in rebase */ u8 bRebase; /* True to collect rebase information */ u8 bIgnoreNoop; /* True to ignore no-op conflicts */ + u8 bNoUpdateLoop; /* No update-loop processing */ int bRowid; + char *zErr; /* Error message, if any */ }; /* Number of prepared UPDATE statements to cache. */ @@ -230898,7 +238544,7 @@ static int sessionDeleteRow( } if( rc==SQLITE_OK ){ - rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0); + rc = sessionPrepare(db, &p->pDelete, &p->zErr, (char*)buf.aBuf); } sqlite3_free(buf.aBuf); @@ -230925,7 +238571,7 @@ static int sessionSelectRow( ){ /* TODO */ return sessionSelectStmt(db, p->bIgnoreNoop, - "main", zTab, p->bRowid, p->nCol, p->azCol, p->abPK, &p->pSelect + "main", zTab, p->bRowid, p->nCol, p->azCol, p->abPK, &p->pSelect, &p->zErr ); } @@ -230962,16 +238608,12 @@ static int sessionInsertRow( sessionAppendStr(&buf, ")", &rc); if( rc==SQLITE_OK ){ - rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0); + rc = sessionPrepare(db, &p->pInsert, &p->zErr, (char*)buf.aBuf); } sqlite3_free(buf.aBuf); return rc; } -static int sessionPrepare(sqlite3 *db, sqlite3_stmt **pp, const char *zSql){ - return sqlite3_prepare_v2(db, zSql, -1, pp, 0); -} - /* ** Prepare statements for applying changes to the sqlite_stat1 table. ** These are similar to those created by sessionSelectRow(), @@ -230981,14 +238623,14 @@ static int sessionPrepare(sqlite3 *db, sqlite3_stmt **pp, const char *zSql){ static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){ int rc = sessionSelectRow(db, "sqlite_stat1", p); if( rc==SQLITE_OK ){ - rc = sessionPrepare(db, &p->pInsert, + rc = sessionPrepare(db, &p->pInsert, 0, "INSERT INTO main.sqlite_stat1 VALUES(?1, " "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, " "?3)" ); } if( rc==SQLITE_OK ){ - rc = sessionPrepare(db, &p->pDelete, + rc = sessionPrepare(db, &p->pDelete, 0, "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS " "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END " "AND (?4 OR stat IS ?3)" @@ -231212,7 +238854,7 @@ static int sessionConflictHandler( void *pCtx, /* First argument for conflict handler */ int *pbReplace /* OUT: Set to true if PK row is found */ ){ - int res = 0; /* Value returned by conflict handler */ + int res = SQLITE_CHANGESET_OMIT;/* Value returned by conflict handler */ int rc; int nCol; int op; @@ -231233,11 +238875,9 @@ static int sessionConflictHandler( if( rc==SQLITE_ROW ){ /* There exists another row with the new.* primary key. */ - if( p->bIgnoreNoop - && sqlite3_column_int(p->pSelect, sqlite3_column_count(p->pSelect)-1) + if( 0==p->bIgnoreNoop + || 0==sqlite3_column_int(p->pSelect, sqlite3_column_count(p->pSelect)-1) ){ - res = SQLITE_CHANGESET_OMIT; - }else{ pIter->pConflict = p->pSelect; res = xConflict(pCtx, eType, pIter); pIter->pConflict = 0; @@ -231250,8 +238890,10 @@ static int sessionConflictHandler( u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent]; int nBlob = pIter->in.iNext - pIter->in.iCurrent; sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc); - return SQLITE_OK; - }else{ + return rc; + }else if( p->bIgnoreNoop==0 || op!=SQLITE_DELETE + || eType==SQLITE_CHANGESET_CONFLICT + ){ /* No other row with the new.* primary key. */ res = xConflict(pCtx, eType+1, pIter); if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE; @@ -231349,7 +238991,7 @@ static int sessionApplyOneOp( sqlite3_step(p->pDelete); rc = sqlite3_reset(p->pDelete); - if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 && p->bIgnoreNoop==0 ){ + if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ rc = sessionConflictHandler( SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry ); @@ -231370,7 +239012,7 @@ static int sessionApplyOneOp( for(i=0; rc==SQLITE_OK && iabPK[i] || (bPatchset==0 && pOld) ){ + if( pOld && (p->abPK[i] || bPatchset==0) ){ rc = sessionBindValue(pUp, i*2+2, pOld); } if( rc==SQLITE_OK && pNew ){ @@ -231496,7 +239138,264 @@ static int sessionApplyOneWithRetry( } /* -** Retry the changes accumulated in the pApply->constraints buffer. +** Create an iterator to iterate through the retry buffer pRetry. +*/ +static int sessionRetryIterInit( + SessionBuffer *pRetry, /* Buffer to iterate through */ + int bPatchset, /* True for patchset, false for changeset */ + const char *zTab, /* Table name */ + SessionApplyCtx *pApply, /* Session apply context */ + sqlite3_changeset_iter **ppIter /* OUT: New iterator */ +){ + sqlite3_changeset_iter *pRet = 0; + int rc = SQLITE_OK; + + rc = sessionChangesetStart( + &pRet, 0, 0, pRetry->nBuf, pRetry->aBuf, pApply->bInvertConstraints, 1 + ); + if( rc==SQLITE_OK ){ + size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*); + pRet->bPatchset = bPatchset; + pRet->zTab = (char*)zTab; + pRet->nCol = pApply->nCol; + pRet->abPK = pApply->abPK; + sessionBufferGrow(&pRet->tblhdr, nByte, &rc); + pRet->apValue = (sqlite3_value**)pRet->tblhdr.aBuf; + if( rc==SQLITE_OK ){ + memset(pRet->apValue, 0, nByte); + }else{ + sqlite3changeset_finalize(pRet); + pRet = 0; + } + } + + *ppIter = pRet; + return rc; +} + +/* +** Attempt to apply all the changes in retry buffer pRetry to the database. +** Except, if parameter iSkip is greater than or equal to 0, skip change +** iSkip. +*/ +static int sessionApplyRetryBuffer( + SessionBuffer *pRetry, /* Buffer to apply changes from */ + int iSkip, /* If >=0, index of change to omit */ + sqlite3 *db, /* Database handle */ + int bPatchset, /* True for patchset, false for changeset */ + const char *zTab, /* Name of table to write to */ + SessionApplyCtx *pApply, /* Apply context */ + int(*xConflict)(void*, int, sqlite3_changeset_iter*), + void *pCtx /* First argument passed to xConflict */ +){ + int rc = SQLITE_OK; + int rc2 = SQLITE_OK; + int ii = 0; + sqlite3_changeset_iter *pIter = 0; + + assert( pApply->constraints.nBuf==0 ); + + rc = sessionRetryIterInit(pRetry, bPatchset, zTab, pApply, &pIter); + + for(ii=0; rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter); ii++){ + if( ii!=iSkip ){ + rc = sessionApplyOneWithRetry(db, pIter, pApply, xConflict, pCtx); + } + } + + rc2 = sqlite3changeset_finalize(pIter); + if( rc==SQLITE_OK ) rc = rc2; + assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 ); + + return rc; +} + +/* +** Check if table zTab in the "main" database of db is a WITHOUT ROWID +** table. +** +** If no error occurs, return SQLITE_OK and set output variable (*pbWR) to +** true if zTab is a WITHOUT ROWID table, or false otherwise. Or, if an +** error does occur, return an SQLite error code. The final value of (*pbWR) +** is undefined in this case. +*/ +static int sessionTableIsWithoutRowid(sqlite3 *db, const char *zTab, int *pbWR){ + sqlite3_stmt *pList = 0; + char *zSql = 0; + int rc = SQLITE_OK; + + zSql = sqlite3_mprintf("PRAGMA table_list = %Q", zTab); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(db, zSql, -1, &pList, 0); + sqlite3_free(zSql); + } + + if( rc==SQLITE_OK ){ + sqlite3_step(pList); + *pbWR = sqlite3_column_int(pList, 4); + rc = sqlite3_finalize(pList); + } + + return rc; +} + +/* +** Iterator pUp points to an UPDATE change. This function deletes the +** affected row from the database and creates an INSERT statement that +** may be used to reinsert the row as it is after the UPDATE change +** has been applied. +** +** If successful, SQLITE_OK is returned and output variable (*ppInsert) +** is left pointing to a prepared INSERT statement. It is the responsibility +** of the caller to eventually free this statement using sqlite3_finalize(). +** Or, if an error occurs, an SQLite error code is returned and (*ppInsert) +** set to NULL. pApply->zErr may be set to an error message in this case. +*/ +static int sessionUpdateToDeleteInsert( + sqlite3 *db, /* Database to write to */ + const char *zTab, /* Table name */ + SessionApplyCtx *pApply, /* Apply context */ + sqlite3_changeset_iter *pUp, /* Iterator pointing to UPDATE change */ + sqlite3_stmt **ppInsert /* OUT: INSERT statement */ +){ + sqlite3_stmt *pRet = 0; /* The INSERT statement */ + sqlite3_stmt *pSelect = 0; /* SELECT to read current values of row */ + int rc = SQLITE_OK; + int bWR = 0; + + rc = sessionTableIsWithoutRowid(db, zTab, &bWR); + if( rc==SQLITE_OK ){ + char *zSelect = 0; + char *zInsert = 0; + SessionBuffer cols = {0, 0, 0}; + SessionBuffer insbind = {0, 0, 0}; + SessionBuffer pkcols = {0, 0, 0}; + SessionBuffer selbind = {0, 0, 0}; + + const char *zComma = ""; + const char *zComma2 = ""; + int ii; + for(ii=0; iinCol; ii++){ + sessionAppendStr(&cols, zComma, &rc); + sessionAppendIdent(&cols, pApply->azCol[ii], &rc); + sessionAppendStr(&insbind, zComma, &rc); + sessionAppendStr(&insbind, "?", &rc); + zComma = ", "; + + if( pApply->abPK[ii] ){ + sessionAppendStr(&pkcols, zComma2, &rc); + sessionAppendIdent(&pkcols, pApply->azCol[ii], &rc); + sessionAppendStr(&selbind, zComma2, &rc); + sessionAppendPrintf(&selbind, &rc, "?%d", ii+1); + zComma2 = ", "; + } + } + if( bWR==0 ){ + sessionAppendStr(&cols, zComma, &rc); + sessionAppendStr(&cols, SESSIONS_ROWID, &rc); + sessionAppendStr(&insbind, zComma, &rc); + sessionAppendStr(&insbind, "?", &rc); + } + + if( rc==SQLITE_OK ){ + zSelect = sqlite3_mprintf("SELECT %s FROM %Q WHERE (%s) IS (%s)", + cols.aBuf, zTab, pkcols.aBuf, selbind.aBuf + ); + if( zSelect==0 ) rc = SQLITE_NOMEM; + } + if( rc==SQLITE_OK ){ + zInsert = sqlite3_mprintf("INSERT INTO %Q(%s) VALUES(%s)", + zTab, cols.aBuf, insbind.aBuf + ); + if( zInsert==0 ) rc = SQLITE_NOMEM; + } + + if( rc==SQLITE_OK ){ + rc = sessionPrepare(db, &pSelect, &pApply->zErr, zSelect); + } + if( rc==SQLITE_OK ){ + rc = sessionPrepare(db, &pRet, &pApply->zErr, zInsert); + } + + sqlite3_free(zSelect); + sqlite3_free(zInsert); + sqlite3_free(cols.aBuf); + sqlite3_free(insbind.aBuf); + sqlite3_free(pkcols.aBuf); + sqlite3_free(selbind.aBuf); + } + + if( rc==SQLITE_OK ){ + rc = sessionBindRow( + pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pSelect + ); + } + + if( rc==SQLITE_OK && sqlite3_step(pSelect)==SQLITE_ROW ){ + int iCol; + for(iCol=0; iColnCol; iCol++){ + sqlite3_value *pVal = pUp->apValue[iCol+pApply->nCol]; + if( pVal==0 ){ + pVal = sqlite3_column_value(pSelect, iCol); + } + rc = sqlite3_bind_value(pRet, iCol+1, pVal); + } + if( bWR==0 ){ + sqlite3_bind_int64(pRet, iCol+1, sqlite3_column_int64(pSelect, iCol)); + } + } + sessionFinalizeStmt(pSelect, &rc); + + /* Delete the row from the database. */ + if( rc==SQLITE_OK ){ + rc = sessionBindRow( + pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pApply->pDelete + ); + sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1); + } + if( rc==SQLITE_OK ){ + sqlite3_step(pApply->pDelete); + rc = sqlite3_reset(pApply->pDelete); + } + + if( rc!=SQLITE_OK ){ + sqlite3_finalize(pRet); + pRet = 0; + } + + *ppInsert = pRet; + return rc; +} + +/* +** Retry the changes accumulated in the pApply->constraints buffer. The +** pApply->constraints buffer contains all changes to table zTab that +** could not be applied due to SQLITE_CONSTRAINT errors. This function +** attempts to apply them as follows: +** +** 1) It runs through the buffer and attempts to retry each change, +** removing any that are successfully applied from the buffer. This +** is repeated until no further progress can be made. +** +** 2) For each UPDATE change in the buffer, try the following in a +** savepoint transaction: +** +** a) DELETE the affected row, +** b) Attempt step (1) with remaining changes, +** c) Attempt to INSERT a row equivalent to the one that would be +** created by applying this UPDATE change. +** +** If the INSERT in (c) succeeds, the savepoint is committed and all +** successfully applied changes are removed from the buffer. Step (2) +** is then repeated. +** +** 3) Once step (2) has been attempted for each UPDATE in the change, +** a final attempt is made to apply each remaining change. This time, +** if an SQLITE_CONSTRAINT error is encountered, the conflict handler +** is invoked and the user has to decide whether to omit the change +** or rollback the entire _apply() operation. */ static int sessionRetryConstraints( sqlite3 *db, @@ -231507,41 +239406,101 @@ static int sessionRetryConstraints( void *pCtx /* First argument passed to xConflict */ ){ int rc = SQLITE_OK; + int iUpdate = 0; + /* Step (1) */ while( pApply->constraints.nBuf ){ - sqlite3_changeset_iter *pIter2 = 0; SessionBuffer cons = pApply->constraints; memset(&pApply->constraints, 0, sizeof(SessionBuffer)); - rc = sessionChangesetStart( - &pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints, 1 + rc = sessionApplyRetryBuffer( + &cons, -1, db, bPatchset, zTab, pApply, xConflict, pCtx + ); + + sqlite3_free(cons.aBuf); + if( rc!=SQLITE_OK ) break; + + /* If no progress has been made this round, break out of the loop. */ + if( pApply->constraints.nBuf>=cons.nBuf ) break; + } + + /* Step (2) */ + while( rc==SQLITE_OK && pApply->constraints.nBuf && !pApply->bNoUpdateLoop ){ + SessionBuffer cons = {0, 0, 0}; + sqlite3_changeset_iter *pUp = 0; + sqlite3_stmt *pInsert = 0; + int iSkip = 0; + + rc = sessionRetryIterInit( + &pApply->constraints, bPatchset, zTab, pApply, &pUp ); if( rc==SQLITE_OK ){ - size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*); - int rc2; - pIter2->bPatchset = bPatchset; - pIter2->zTab = (char*)zTab; - pIter2->nCol = pApply->nCol; - pIter2->abPK = pApply->abPK; - sessionBufferGrow(&pIter2->tblhdr, nByte, &rc); - pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf; - if( rc==SQLITE_OK ) memset(pIter2->apValue, 0, nByte); + int iThis = -1; + while( SQLITE_ROW==sqlite3changeset_next(pUp) ){ + if( pUp->op==SQLITE_UPDATE ) iThis++; + if( iThis==iUpdate ) break; + iSkip++; + } + if( iThis==iUpdate ){ + rc = sqlite3_exec(db, "SAVEPOINT update_op", 0, 0, 0); + if( rc==SQLITE_OK ){ + rc = sessionUpdateToDeleteInsert(db, zTab, pApply, pUp, &pInsert); + } + } + sqlite3changeset_finalize(pUp); + if( iThis!=iUpdate ) break; + } + + if( rc==SQLITE_OK ){ + cons = pApply->constraints; - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter2) ){ - rc = sessionApplyOneWithRetry(db, pIter2, pApply, xConflict, pCtx); + while( rc==SQLITE_OK && pApply->constraints.nBuf>0 ){ + SessionBuffer app = pApply->constraints; + memset(&pApply->constraints, 0, sizeof(SessionBuffer)); + rc = sessionApplyRetryBuffer( + &app, iSkip, db, bPatchset, zTab, pApply, xConflict, pCtx + ); + if( app.aBuf!=cons.aBuf ){ + sqlite3_free(app.aBuf); + } + if( pApply->constraints.nBuf>=app.nBuf ){ + break; + } + iSkip = -1; } + } - rc2 = sqlite3changeset_finalize(pIter2); - if( rc==SQLITE_OK ) rc = rc2; + iUpdate++; + if( rc==SQLITE_OK ){ + sqlite3_step(pInsert); + rc = sqlite3_finalize(pInsert); + if( rc==SQLITE_CONSTRAINT ){ + rc = sqlite3_exec(db, "ROLLBACK TO update_op", 0, 0, 0); + sqlite3_free(pApply->constraints.aBuf); + pApply->constraints = cons; + memset(&cons, 0, sizeof(cons)); + }else if( rc==SQLITE_OK ){ + iUpdate = 0; + } + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "RELEASE update_op", 0, 0, 0); + } + }else{ + sqlite3_finalize(pInsert); } - assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 ); sqlite3_free(cons.aBuf); - if( rc!=SQLITE_OK ) break; - if( pApply->constraints.nBuf>=cons.nBuf ){ - /* No progress was made on the last round. */ - pApply->bDeferConstraints = 0; - } + } + + /* Step (3) */ + if( rc==SQLITE_OK && pApply->constraints.nBuf ){ + SessionBuffer cons = pApply->constraints; + memset(&pApply->constraints, 0, sizeof(SessionBuffer)); + pApply->bDeferConstraints = 0; + rc = sessionApplyRetryBuffer( + &cons, -1, db, bPatchset, zTab, pApply, xConflict, pCtx + ); + sqlite3_free(cons.aBuf); } return rc; @@ -231561,6 +239520,10 @@ static int sessionChangesetApply( void *pCtx, /* Copy of sixth arg to _apply() */ const char *zTab /* Table name */ ), + int(*xFilterIter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + sqlite3_changeset_iter *p + ), int(*xConflict)( void *pCtx, /* Copy of fifth arg to _apply() */ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ @@ -231591,6 +239554,7 @@ static int sessionChangesetApply( sApply.bRebase = (ppRebase && pnRebase); sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP); + sApply.bNoUpdateLoop = !!(flags & SQLITE_CHANGESETAPPLY_NOUPDATELOOP); if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); } @@ -231648,7 +239612,8 @@ static int sessionChangesetApply( sqlite3changeset_pk(pIter, &abPK, 0); rc = sessionTableInfo(0, db, "main", zNew, - &sApply.nCol, &zTab, &sApply.azCol, 0, &sApply.abPK, &sApply.bRowid + &sApply.nCol, 0, &zTab, &sApply.azCol, 0, 0, + &sApply.abPK, &sApply.bRowid ); if( rc!=SQLITE_OK ) break; for(i=0; iflags &= ~((u64)SQLITE_FkNoAction); db->aDb[0].pSchema->schema_cookie -= 32; } + + assert( rc!=SQLITE_OK || sApply.zErr==0 ); + sqlite3_set_errmsg(db, rc, sApply.zErr); + sqlite3_free(sApply.zErr); + sqlite3_mutex_leave(sqlite3_db_mutex(db)); return rc; } /* -** Apply the changeset passed via pChangeset/nChangeset to the main -** database attached to handle "db". +** This function is called by all six sqlite3changeset_apply() variants: +** +** + sqlite3changeset_apply() +** + sqlite3changeset_apply_v2() +** + sqlite3changeset_apply_v3() +** + sqlite3changeset_apply_strm() +** + sqlite3changeset_apply_strm_v2() +** + sqlite3changeset_apply_strm_v3() +** +** Arguments passed to this function are as follows: +** +** db: +** Database handle to apply changeset to main database of. +** +** nChangeset/pChangeset: +** These are both passed zero for the streaming variants. For the normal +** apply() functions, these are passed the size of and the buffer containing +** the changeset, respectively. +** +** xInput/pIn: +** These are both passed zero for the normal variants. For the streaming +** apply() functions, these are passed the input callback and context +** pointer, respectively. +** +** xFilter: +** The filter function as passed to apply() or apply_v2() (to filter by +** table name), if any. This is always NULL for apply_v3() calls. +** +** xFilterIter: +** The filter function as passed to apply_v3(), if any. +** +** xConflict: +** The conflict handler callback (must not be NULL). +** +** pCtx: +** The context pointer passed to the xFilter and xConflict handler callbacks. +** +** ppRebase, pnRebase: +** Zero for apply(). The rebase changeset output pointers, if any, for +** apply_v2() and apply_v3(). +** +** flags: +** Zero for apply(). The flags parameter for apply_v2() and apply_v3(). */ -SQLITE_API int sqlite3changeset_apply_v2( +static int sessionChangesetApplyV23( sqlite3 *db, /* Apply change to "main" db of this handle */ int nChangeset, /* Size of changeset in bytes */ void *pChangeset, /* Changeset blob */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ int(*xFilter)( void *pCtx, /* Copy of sixth arg to _apply() */ const char *zTab /* Table name */ ), + int(*xFilterIter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + sqlite3_changeset_iter *p /* Handle describing current change */ + ), int(*xConflict)( void *pCtx, /* Copy of sixth arg to _apply() */ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ @@ -231784,18 +239810,74 @@ SQLITE_API int sqlite3changeset_apply_v2( int flags ){ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ - int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); - int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1); - + int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); + int rc = sessionChangesetStart( + &pIter, xInput, pIn, nChangeset, pChangeset, bInverse, 1 + ); if( rc==SQLITE_OK ){ - rc = sessionChangesetApply( - db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags + rc = sessionChangesetApply(db, pIter, + xFilter, xFilterIter, xConflict, pCtx, ppRebase, pnRebase, flags ); } - return rc; } +/* +** Apply the changeset passed via pChangeset/nChangeset to the main +** database attached to handle "db". +*/ +SQLITE_API int sqlite3changeset_apply_v2( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, + int flags +){ + return sessionChangesetApplyV23(db, + nChangeset, pChangeset, 0, 0, + xFilter, 0, xConflict, pCtx, + ppRebase, pnRebase, flags + ); +} + +/* +** Apply the changeset passed via pChangeset/nChangeset to the main +** database attached to handle "db". +*/ +SQLITE_API int sqlite3changeset_apply_v3( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + sqlite3_changeset_iter *p /* Handle describing current change */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, + int flags +){ + return sessionChangesetApplyV23(db, + nChangeset, pChangeset, 0, 0, + 0, xFilter, xConflict, pCtx, + ppRebase, pnRebase, flags + ); +} + /* ** Apply the changeset passed via pChangeset/nChangeset to the main database ** attached to handle "db". Invoke the supplied conflict handler callback @@ -231816,8 +239898,10 @@ SQLITE_API int sqlite3changeset_apply( ), void *pCtx /* First argument passed to xConflict */ ){ - return sqlite3changeset_apply_v2( - db, nChangeset, pChangeset, xFilter, xConflict, pCtx, 0, 0, 0 + return sessionChangesetApplyV23(db, + nChangeset, pChangeset, 0, 0, + xFilter, 0, xConflict, pCtx, + 0, 0, 0 ); } @@ -231826,6 +239910,29 @@ SQLITE_API int sqlite3changeset_apply( ** attached to handle "db". Invoke the supplied conflict handler callback ** to resolve any conflicts encountered while applying the change. */ +SQLITE_API int sqlite3changeset_apply_v3_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + sqlite3_changeset_iter *p + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, + int flags +){ + return sessionChangesetApplyV23(db, + 0, 0, xInput, pIn, + 0, xFilter, xConflict, pCtx, + ppRebase, pnRebase, flags + ); +} SQLITE_API int sqlite3changeset_apply_v2_strm( sqlite3 *db, /* Apply change to "main" db of this handle */ int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ @@ -231843,15 +239950,11 @@ SQLITE_API int sqlite3changeset_apply_v2_strm( void **ppRebase, int *pnRebase, int flags ){ - sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ - int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); - int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse, 1); - if( rc==SQLITE_OK ){ - rc = sessionChangesetApply( - db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags - ); - } - return rc; + return sessionChangesetApplyV23(db, + 0, 0, xInput, pIn, + xFilter, 0, xConflict, pCtx, + ppRebase, pnRebase, flags + ); } SQLITE_API int sqlite3changeset_apply_strm( sqlite3 *db, /* Apply change to "main" db of this handle */ @@ -231868,11 +239971,28 @@ SQLITE_API int sqlite3changeset_apply_strm( ), void *pCtx /* First argument passed to xConflict */ ){ - return sqlite3changeset_apply_v2_strm( - db, xInput, pIn, xFilter, xConflict, pCtx, 0, 0, 0 + return sessionChangesetApplyV23(db, + 0, 0, xInput, pIn, + xFilter, 0, xConflict, pCtx, + 0, 0, 0 ); } +/* +** The parts of the sqlite3_changegroup structure used by the +** sqlite3changegroup_change_xxx() APIs. +*/ +typedef struct ChangeData ChangeData; +struct ChangeData { + SessionTable *pTab; + int bIndirect; + int eOp; + + int nBufAlloc; + SessionBuffer *aBuf; + SessionBuffer record; +}; + /* ** sqlite3_changegroup handle. */ @@ -231884,12 +240004,17 @@ struct sqlite3_changegroup { sqlite3 *db; /* Configured by changegroup_schema() */ char *zDb; /* Configured by changegroup_schema() */ + ChangeData cd; /* Used by changegroup_change_xxx() APIs. */ }; /* ** This function is called to merge two changes to the same row together as ** part of an sqlite3changeset_concat() operation. A new change object is ** allocated and a pointer to it stored in *ppNew. +** +** Because they have been vetted by sqlite3changegroup_add() or similar, +** both the aRec[] change and the pExist change are safe to use without +** checking for buffer overflows. */ static int sessionChangeMerge( SessionTable *pTab, /* Table structure */ @@ -232030,7 +240155,7 @@ static int sessionChangeMerge( memcpy(aCsr, aRec, nRec); aCsr += nRec; }else{ - if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){ + if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist,0,aRec,0) ){ sqlite3_free(pNew); pNew = 0; } @@ -232123,15 +240248,14 @@ static int sessionChangesetExtendRecord( switch( eType ){ case SQLITE_FLOAT: case SQLITE_INTEGER: { - i64 iVal; - if( eType==SQLITE_INTEGER ){ - iVal = sqlite3_column_int64(pTab->pDfltStmt, ii); - }else{ - double rVal = sqlite3_column_int64(pTab->pDfltStmt, ii); - memcpy(&iVal, &rVal, sizeof(i64)); - } if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){ - sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal); + if( eType==SQLITE_INTEGER ){ + sqlite3_int64 iVal = sqlite3_column_int64(pTab->pDfltStmt, ii); + sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal); + }else{ + double rVal = sqlite3_column_double(pTab->pDfltStmt, ii); + sessionPutDouble(&pOut->aBuf[pOut->nBuf], rVal); + } pOut->nBuf += 8; } break; @@ -232202,13 +240326,19 @@ static int sessionChangesetFindTable( int nCol = 0; *ppTab = 0; - sqlite3changeset_pk(pIter, &abPK, &nCol); /* Search the list for an existing table */ for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){ if( 0==sqlite3_strnicmp(pTab->zName, zTab, nTab+1) ) break; } + + if( pIter ){ + sqlite3changeset_pk(pIter, &abPK, &nCol); + }else if( !pTab && !pGrp->db ){ + return SQLITE_OK; + } + /* If one was not found above, create a new table now */ if( !pTab ){ SessionTable **ppNew; @@ -232220,15 +240350,17 @@ static int sessionChangesetFindTable( memset(pTab, 0, sizeof(SessionTable)); pTab->nCol = nCol; pTab->abPK = (u8*)&pTab[1]; - memcpy(pTab->abPK, abPK, nCol); + if( nCol>0 ){ + memcpy(pTab->abPK, abPK, nCol); + } pTab->zName = (char*)&pTab->abPK[nCol]; memcpy(pTab->zName, zTab, nTab+1); if( pGrp->db ){ pTab->nCol = 0; rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb); - if( rc ){ - assert( pTab->azCol==0 ); + if( rc || pTab->nCol==0 ){ + sqlite3_free(pTab->azCol); sqlite3_free(pTab); return rc; } @@ -232243,7 +240375,7 @@ static int sessionChangesetFindTable( } /* Check that the table is compatible. */ - if( !sessionChangesetCheckCompat(pTab, nCol, abPK) ){ + if( pIter && !sessionChangesetCheckCompat(pTab, nCol, abPK) ){ rc = SQLITE_SCHEMA; } @@ -232252,44 +240384,27 @@ static int sessionChangesetFindTable( } /* -** Add the change currently indicated by iterator pIter to the hash table -** belonging to changegroup pGrp. +** Add a single change to the changegroup pGrp. */ static int sessionOneChangeToHash( - sqlite3_changegroup *pGrp, - sqlite3_changeset_iter *pIter, - int bRebase + sqlite3_changegroup *pGrp, /* Changegroup to update */ + SessionTable *pTab, /* Table change pertains to */ + int op, /* One of SQLITE_INSERT, UPDATE, DELETE */ + int bIndirect, /* True to flag change as "indirect" */ + int nCol, /* Number of columns in record(s) */ + u8 *aRec, /* Serialized change record(s) */ + int nRec, /* Size of aRec[] in bytes */ + int bRebase /* True if this is a rebase blob */ ){ int rc = SQLITE_OK; - int nCol = 0; - int op = 0; int iHash = 0; - int bIndirect = 0; SessionChange *pChange = 0; SessionChange *pExist = 0; SessionChange **pp = 0; - SessionTable *pTab = 0; - u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2]; - int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2; assert( nRec>0 ); - /* Ensure that only changesets, or only patchsets, but not a mixture - ** of both, are being combined. It is an error to try to combine a - ** changeset and a patchset. */ - if( pGrp->pList==0 ){ - pGrp->bPatch = pIter->bPatchset; - }else if( pIter->bPatchset!=pGrp->bPatch ){ - rc = SQLITE_ERROR; - } - - if( rc==SQLITE_OK ){ - const char *zTab = 0; - sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect); - rc = sessionChangesetFindTable(pGrp, zTab, pIter, &pTab); - } - - if( rc==SQLITE_OK && nColnCol ){ + if( nColnCol ){ SessionBuffer *pBuf = &pGrp->rec; rc = sessionChangesetExtendRecord(pGrp, pTab, nCol, op, aRec, nRec, pBuf); aRec = pBuf->aBuf; @@ -232297,7 +240412,7 @@ static int sessionOneChangeToHash( assert( pGrp->db ); } - if( rc==SQLITE_OK && sessionGrowHash(0, pIter->bPatchset, pTab) ){ + if( rc==SQLITE_OK && sessionGrowHash(0, pGrp->bPatch, pTab) ){ rc = SQLITE_NOMEM; } @@ -232305,12 +240420,12 @@ static int sessionOneChangeToHash( /* Search for existing entry. If found, remove it from the hash table. ** Code below may link it back in. */ iHash = sessionChangeHash( - pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange + pTab, (pGrp->bPatch && op==SQLITE_DELETE), aRec, pTab->nChange ); for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){ int bPkOnly1 = 0; int bPkOnly2 = 0; - if( pIter->bPatchset ){ + if( pGrp->bPatch ){ bPkOnly1 = (*pp)->op==SQLITE_DELETE; bPkOnly2 = op==SQLITE_DELETE; } @@ -232325,7 +240440,7 @@ static int sessionOneChangeToHash( if( rc==SQLITE_OK ){ rc = sessionChangeMerge(pTab, bRebase, - pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange + pGrp->bPatch, pExist, op, bIndirect, aRec, nRec, &pChange ); } if( rc==SQLITE_OK && pChange ){ @@ -232334,6 +240449,47 @@ static int sessionOneChangeToHash( pTab->nEntry++; } + return rc; +} + +/* +** Add the change currently indicated by iterator pIter to the hash table +** belonging to changegroup pGrp. +*/ +static int sessionOneChangeIterToHash( + sqlite3_changegroup *pGrp, + sqlite3_changeset_iter *pIter, + int bRebase +){ + u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2]; + int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2; + const char *zTab = 0; + int nCol = 0; + int op = 0; + int bIndirect = 0; + int rc = SQLITE_OK; + SessionTable *pTab = 0; + + /* Ensure that only changesets, or only patchsets, but not a mixture + ** of both, are being combined. It is an error to try to combine a + ** changeset and a patchset. */ + if( pGrp->pList==0 ){ + pGrp->bPatch = pIter->bPatchset; + }else if( pIter->bPatchset!=pGrp->bPatch ){ + rc = SQLITE_ERROR; + } + + if( rc==SQLITE_OK ){ + sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect); + rc = sessionChangesetFindTable(pGrp, zTab, pIter, &pTab); + } + + if( rc==SQLITE_OK ){ + rc = sessionOneChangeToHash( + pGrp, pTab, op, bIndirect, nCol, aRec, nRec, bRebase + ); + } + if( rc==SQLITE_OK ) rc = pIter->rc; return rc; } @@ -232353,7 +240509,12 @@ static int sessionChangesetToHash( pIter->in.bNoDiscard = 1; while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){ - rc = sessionOneChangeToHash(pGrp, pIter, bRebase); + if( bRebase && pIter->bPatchset ){ + /* A patchset may not be used as a rebase */ + rc = SQLITE_ERROR; + }else{ + rc = sessionOneChangeIterToHash(pGrp, pIter, bRebase); + } if( rc!=SQLITE_OK ) break; } @@ -232443,6 +240604,33 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){ return rc; } +/* +** Configure a changegroup object. +*/ +SQLITE_API int sqlite3changegroup_config( + sqlite3_changegroup *pGrp, + int op, + void *pArg +){ + int rc = SQLITE_OK; + + switch( op ){ + case SQLITE_CHANGEGROUP_CONFIG_PATCHSET: { + int arg = *(int*)pArg; + if( pGrp->pList==0 && arg>=0 ){ + pGrp->bPatch = (arg>0); + } + *(int*)pArg = pGrp->bPatch; + break; + } + default: + rc = SQLITE_MISUSE; + break; + } + + return rc; +} + /* ** Provide a database schema to the changegroup object. */ @@ -232491,14 +240679,19 @@ SQLITE_API int sqlite3changegroup_add_change( sqlite3_changegroup *pGrp, sqlite3_changeset_iter *pIter ){ + int rc = SQLITE_OK; + if( pIter->in.iCurrent==pIter->in.iNext || pIter->rc!=SQLITE_OK || pIter->bInvert ){ /* Iterator does not point to any valid entry or is an INVERT iterator. */ - return SQLITE_ERROR; + rc = SQLITE_ERROR; + }else{ + pIter->in.bNoDiscard = 1; + rc = sessionOneChangeIterToHash(pGrp, pIter, 0); } - return sessionOneChangeToHash(pGrp, pIter, 0); + return rc; } /* @@ -232548,6 +240741,12 @@ SQLITE_API int sqlite3changegroup_output_strm( */ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){ if( pGrp ){ + int ii; + for(ii=0; iicd.nBufAlloc; ii++){ + sqlite3_free(pGrp->cd.aBuf[ii].aBuf); + } + sqlite3_free(pGrp->cd.record.aBuf); + sqlite3_free(pGrp->cd.aBuf); sqlite3_free(pGrp->zDb); sessionDeleteTable(0, pGrp->pList); sqlite3_free(pGrp->rec.aBuf); @@ -232633,14 +240832,17 @@ static void sessionAppendRecordMerge( u8 *a2, int n2, /* Record 2 */ int *pRc /* IN/OUT: error code */ ){ - sessionBufferGrow(pBuf, n1+n2, pRc); + u8 *a1Eof = &a1[n1]; + u8 *a2Eof = &a2[n2]; + + sessionBufferGrow(pBuf, (i64)n1+n2, pRc); if( *pRc==SQLITE_OK ){ int i; u8 *pOut = &pBuf->aBuf[pBuf->nBuf]; for(i=0; i0 && (*a1==0 || *a1==0xFF)) ){ memcpy(pOut, a2, nn2); pOut += nn2; }else{ @@ -232682,20 +240884,21 @@ static void sessionAppendPartialUpdate( u8 *aChange, int nChange, /* Record to rebase against */ int *pRc /* IN/OUT: Return Code */ ){ - sessionBufferGrow(pBuf, 2+nRec+nChange, pRc); + sessionBufferGrow(pBuf, (i64)2+nRec+nChange, pRc); if( *pRc==SQLITE_OK ){ int bData = 0; u8 *pOut = &pBuf->aBuf[pBuf->nBuf]; int i; u8 *a1 = aRec; u8 *a2 = aChange; + u8 *a2Eof = &a2[nChange]; *pOut++ = SQLITE_UPDATE; *pOut++ = pIter->bIndirect; for(i=0; inCol; i++){ int n1 = sessionSerialLen(a1); - int n2 = sessionSerialLen(a2); - if( pIter->abPK[i] || a2[0]==0 ){ + int n2 = (a2>=a2Eof) ? 0 : sessionSerialLen(a2); + if( n2<=0 || pIter->abPK[i] || a2[0]==0 ){ if( !pIter->abPK[i] && a1[0] ) bData = 1; memcpy(pOut, a1, n1); pOut += n1; @@ -232896,8 +241099,8 @@ SQLITE_API int sqlite3rebaser_configure( sqlite3_rebaser *p, int nRebase, const void *pRebase ){ - sqlite3_changeset_iter *pIter = 0; /* Iterator opened on pData/nData */ int rc; /* Return code */ + sqlite3_changeset_iter *pIter = 0; /* Iterator opened on pData/nData */ rc = sqlite3changeset_start(&pIter, nRebase, (void*)pRebase); if( rc==SQLITE_OK ){ rc = sessionChangesetToHash(pIter, &p->grp, 1); @@ -232978,12 +241181,354 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){ return rc; } +/* +** Begin adding a change to a changegroup object. +*/ +SQLITE_API int sqlite3changegroup_change_begin( + sqlite3_changegroup *pGrp, + int eOp, + const char *zTab, + int bIndirect, + char **pzErr +){ + SessionTable *pTab = 0; + int rc = SQLITE_OK; + + if( pGrp->cd.pTab ){ + rc = SQLITE_MISUSE; + }else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_UPDATE && eOp!=SQLITE_DELETE ){ + rc = SQLITE_ERROR; + }else{ + rc = sessionChangesetFindTable(pGrp, zTab, 0, &pTab); + } + if( rc==SQLITE_OK ){ + if( pTab==0 ){ + if( pzErr ){ + *pzErr = sqlite3_mprintf("no such table: %s", zTab); + } + rc = SQLITE_ERROR; + }else{ + int nReq = pTab->nCol * (eOp==SQLITE_UPDATE ? 2 : 1); + pGrp->cd.pTab = pTab; + pGrp->cd.eOp = eOp; + pGrp->cd.bIndirect = bIndirect; + + if( pGrp->cd.nBufAlloccd.aBuf, nReq * sizeof(SessionBuffer) + ); + if( aBuf==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(&aBuf[pGrp->cd.nBufAlloc], 0, + sizeof(SessionBuffer) * (nReq - pGrp->cd.nBufAlloc) + ); + pGrp->cd.aBuf = aBuf; + pGrp->cd.nBufAlloc = nReq; + } + } + +#ifdef SQLITE_DEBUG + { + /* Assert that all column values are currently undefined */ + int ii; + for(ii=0; iicd.nBufAlloc; ii++){ + assert( pGrp->cd.aBuf[ii].nBuf==0 ); + } + } +#endif + } + } + + return rc; +} + +/* +** This function does processing common to the _change_int64(), _change_text() +** and other similar APIs. +*/ +static int checkChangeParams( + sqlite3_changegroup *pGrp, + int bNew, + int iCol, + sqlite3_int64 nReq, + SessionBuffer **ppBuf +){ + int rc = SQLITE_OK; + if( pGrp->cd.pTab==0 ){ + rc = SQLITE_MISUSE; + }else if( iCol<0 || iCol>=pGrp->cd.pTab->nCol ){ + rc = SQLITE_RANGE; + }else if( + (bNew && pGrp->cd.eOp==SQLITE_DELETE) + || (!bNew && pGrp->cd.eOp==SQLITE_INSERT) + ){ + rc = SQLITE_ERROR; + }else{ + SessionBuffer *pBuf = &pGrp->cd.aBuf[iCol]; + if( pGrp->cd.eOp==SQLITE_UPDATE && bNew ){ + pBuf += pGrp->cd.pTab->nCol; + } + pBuf->nBuf = 0; + sessionBufferGrow(pBuf, nReq, &rc); + pBuf->nBuf = nReq; + *ppBuf = pBuf; + } + return rc; +} + +/* +** Configure the change currently under construction with an integer value. +*/ +SQLITE_API int sqlite3changegroup_change_int64( + sqlite3_changegroup *pGrp, + int bNew, + int iCol, + sqlite3_int64 iVal +){ + int rc = SQLITE_OK; + SessionBuffer *pBuf = 0; + + if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, 9, &pBuf)) ){ + return rc; + } + + pBuf->aBuf[0] = SQLITE_INTEGER; + sessionPutI64(&pBuf->aBuf[1], iVal); + return SQLITE_OK; +} + +/* +** Configure the change currently under construction with a null value. +*/ +SQLITE_API int sqlite3changegroup_change_null( + sqlite3_changegroup *pGrp, + int bNew, + int iCol +){ + int rc = SQLITE_OK; + SessionBuffer *pBuf = 0; + + if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, 1, &pBuf)) ){ + return rc; + } + + pBuf->aBuf[0] = SQLITE_NULL; + return SQLITE_OK; +} + +/* +** Configure the change currently under construction with a real value. +*/ +SQLITE_API int sqlite3changegroup_change_double( + sqlite3_changegroup *pGrp, + int bNew, + int iCol, + double fVal +){ + int rc = SQLITE_OK; + SessionBuffer *pBuf = 0; + + if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, 9, &pBuf)) ){ + return rc; + } + + pBuf->aBuf[0] = SQLITE_FLOAT; + sessionPutDouble(&pBuf->aBuf[1], fVal); + return SQLITE_OK; +} + +/* +** Configure the change currently under construction with a text value. +*/ +SQLITE_API int sqlite3changegroup_change_text( + sqlite3_changegroup *pGrp, + int bNew, + int iCol, + const char *pVal, + int nVal +){ + int nText = nVal>=0 ? nVal : strlen(pVal); + sqlite3_int64 nByte = 1 + sessionVarintLen(nText) + nText; + int rc = SQLITE_OK; + SessionBuffer *pBuf = 0; + + if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, nByte, &pBuf)) ){ + return rc; + } + + pBuf->aBuf[0] = SQLITE_TEXT; + pBuf->nBuf = (1 + sessionVarintPut(&pBuf->aBuf[1], nText)); + memcpy(&pBuf->aBuf[pBuf->nBuf], pVal, nText); + pBuf->nBuf += nText; + + return SQLITE_OK; +} + +/* +** Configure the change currently under construction with a blob value. +*/ +SQLITE_API int sqlite3changegroup_change_blob( + sqlite3_changegroup *pGrp, + int bNew, + int iCol, + const void *pVal, + int nVal +){ + sqlite3_int64 nByte = 1 + sessionVarintLen(nVal) + (i64)nVal; + int rc = SQLITE_OK; + SessionBuffer *pBuf = 0; + + if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, nByte, &pBuf)) ){ + return rc; + } + + pBuf->aBuf[0] = SQLITE_BLOB; + pBuf->nBuf = (1 + sessionVarintPut(&pBuf->aBuf[1], nVal)); + memcpy(&pBuf->aBuf[pBuf->nBuf], pVal, nVal); + pBuf->nBuf += nVal; + + return SQLITE_OK; +} + +/* +** Finish any change currently being constructed by the changegroup object. +*/ +SQLITE_API int sqlite3changegroup_change_finish( + sqlite3_changegroup *pGrp, + int bDiscard, + char **pzErr +){ + int rc = SQLITE_OK; + if( pGrp->cd.pTab ){ + SessionBuffer *aBuf = pGrp->cd.aBuf; + int ii; + + if( bDiscard==0 ){ + int nBuf = pGrp->cd.pTab->nCol; + u8 eUndef = SQLITE_NULL; + if( pGrp->cd.eOp==SQLITE_UPDATE ){ + for(ii=0; iicd.pTab->abPK[ii] ){ + if( aBuf[ii].nBuf<=1 ){ + *pzErr = sqlite3_mprintf( + "invalid change: %s value in PK of old.* record", + aBuf[ii].nBuf==1 ? "null" : "undefined" + ); + rc = SQLITE_ERROR; + break; + }else if( aBuf[ii + nBuf].nBuf>0 ){ + *pzErr = sqlite3_mprintf( + "invalid change: defined value in PK of new.* record" + ); + rc = SQLITE_ERROR; + break; + } + }else + if( pGrp->bPatch==0 && (aBuf[ii].nBuf>0)!=(aBuf[ii+nBuf].nBuf>0) ){ + *pzErr = sqlite3_mprintf( + "invalid change: column %d " + "- old.* value is %sdefined but new.* is %sdefined", + ii, aBuf[ii].nBuf ? "" : "un", aBuf[ii+nBuf].nBuf ? "" : "un" + ); + rc = SQLITE_ERROR; + break; + } + } + eUndef = 0x00; + if( pGrp->bPatch==0 ) nBuf = nBuf * 2; + }else{ + for(ii=0; iicd.pTab->abPK[ii]; + if( (pGrp->cd.eOp==SQLITE_INSERT || pGrp->bPatch==0 || isPK) + && aBuf[ii].nBuf==0 + ){ + *pzErr = sqlite3_mprintf( + "invalid change: column %d is undefined", ii + ); + rc = SQLITE_ERROR; + break; + } + if( aBuf[ii].nBuf==1 && isPK ){ + *pzErr = sqlite3_mprintf( + "invalid change: null value in PK" + ); + rc = SQLITE_ERROR; + break; + } + } + } + + pGrp->cd.record.nBuf = 0; + for(ii=0; iicd.aBuf[ii]; + if( pGrp->bPatch ){ + if( pGrp->cd.pTab->abPK[ii]==0 ){ + if( pGrp->cd.eOp==SQLITE_UPDATE ){ + p += pGrp->cd.pTab->nCol; + }else if( pGrp->cd.eOp==SQLITE_DELETE ){ + continue; + } + } + } + if( 0==sessionBufferGrow(&pGrp->cd.record, p->nBuf?p->nBuf:1, &rc) ){ + if( p->nBuf ){ + memcpy(&pGrp->cd.record.aBuf[pGrp->cd.record.nBuf],p->aBuf,p->nBuf); + pGrp->cd.record.nBuf += p->nBuf; + }else{ + pGrp->cd.record.aBuf[pGrp->cd.record.nBuf++] = eUndef; + } + } + } + if( rc==SQLITE_OK ){ + rc = sessionOneChangeToHash( + pGrp, pGrp->cd.pTab, + pGrp->cd.eOp, pGrp->cd.bIndirect, pGrp->cd.pTab->nCol, + pGrp->cd.record.aBuf, pGrp->cd.record.nBuf, 0 + ); + } + } + + /* Reset all aBuf[] entries to "undefined". */ + { + int nZero = pGrp->cd.pTab->nCol; + if( pGrp->cd.eOp==SQLITE_UPDATE ) nZero += nZero; + for(ii=0; iicd.aBuf[ii].nBuf = 0; + } + } + pGrp->cd.pTab = 0; + } + + return rc; +} + #endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */ /************** End of sqlite3session.c **************************************/ /************** Begin file fts5.c ********************************************/ - +/* +** This, the "fts5.c" source file, is a composite file that is itself +** assembled from the following files: +** +** fts5.h +** fts5Int.h +** fts5parse.h <--- Generated from fts5parse.y by Lemon +** fts5parse.c <--- Generated from fts5parse.y by Lemon +** fts5_aux.c +** fts5_buffer.c +** fts5_config.c +** fts5_expr.c +** fts5_hash.c +** fts5_index.c +** fts5_main.c +** fts5_storage.c +** fts5_tokenize.c +** fts5_unicode2.c +** fts5_varint.c +** fts5_vocab.c +*/ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) @@ -232993,6 +241538,12 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){ # undef NDEBUG #endif +#ifdef HAVE_STDINT_H +/* #include */ +#endif +#ifdef HAVE_INTTYPES_H +/* #include */ +#endif /* ** 2014 May 31 ** @@ -233293,14 +241844,29 @@ struct Fts5PhraseIter { ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, ** output variable (*ppToken) is set to point to a buffer containing the ** matching document token, and (*pnToken) to the size of that buffer in -** bytes. This API is not available if the specified token matches a -** prefix query term. In that case both output variables are always set -** to 0. +** bytes. ** ** The output text is not a copy of the document text that was tokenized. ** It is the output of the tokenizer module. For tokendata=1 tables, this ** includes any embedded 0x00 and trailing data. ** +** This API may be slow in some cases if the token identified by parameters +** iIdx and iToken matched a prefix token in the query. In most cases, the +** first call to this API for each prefix token in the query is forced +** to scan the portion of the full-text index that matches the prefix +** token to collect the extra data required by this API. If the prefix +** token matches a large number of token instances in the document set, +** this may be a performance problem. +** +** If the user knows in advance that a query may use this API for a +** prefix token, FTS5 may be configured to collect all required data as part +** of the initial querying of the full-text index, avoiding the second scan +** entirely. This also causes prefix queries that do not use this API to +** run more slowly and use more memory. FTS5 may be configured in this way +** either on a per-table basis using the [FTS5 insttoken | 'insttoken'] +** option, or on a per-query basis using the +** [fts5_insttoken | fts5_insttoken()] user function. +** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. ** @@ -233755,6 +242321,7 @@ SQLITE_EXTENSION_INIT1 /* #include */ /* #include */ +/* #include */ #ifndef SQLITE_AMALGAMATION @@ -233794,23 +242361,34 @@ typedef sqlite3_uint64 u64; # define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) # define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) -/* The uptr type is an unsigned integer large enough to hold a pointer +/* +** This macro is used in a single assert() within fts5 to check that an +** allocation is aligned to an 8-byte boundary. But it is a complicated +** macro to get right for multiple platforms without generating warnings. +** So instead of reproducing the entire definition from sqliteInt.h, we +** just do without this assert() for the rare non-amalgamation builds. */ -#if defined(HAVE_STDINT_H) - typedef uintptr_t uptr; -#elif SQLITE_PTRSIZE==4 - typedef u32 uptr; -#else - typedef u64 uptr; -#endif +#define EIGHT_BYTE_ALIGNMENT(x) 1 -#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC -# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0) +/* +** Macros needed to provide flexible arrays in a portable way +*/ +#ifndef offsetof +# define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0)) +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define FLEXARRAY #else -# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) +# define FLEXARRAY 1 #endif -#endif +#endif /* SQLITE_AMALGAMATION */ + +/* +** Constants for the largest and smallest possible 32-bit signed integers. +*/ +# define LARGEST_INT32 ((int)(0x7fffffff)) +# define SMALLEST_INT32 ((int)((-1) - LARGEST_INT32)) /* Truncate very long tokens to this many bytes. Hard limit is ** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset @@ -233882,10 +242460,11 @@ typedef struct Fts5Colset Fts5Colset; */ struct Fts5Colset { int nCol; - int aiCol[1]; + int aiCol[FLEXARRAY]; }; - +/* Size (int bytes) of a complete Fts5Colset object with N columns. */ +#define SZ_FTS5COLSET(N) (sizeof(i64)*((N+2)/2)) /************************************************************************** ** Interface to code in fts5_config.c. fts5_config.c contains contains code @@ -233982,7 +242561,8 @@ struct Fts5Config { char *zRank; /* Name of rank function */ char *zRankArgs; /* Arguments to rank function */ int bSecureDelete; /* 'secure-delete' */ - int nDeleteMerge; /* 'deletemerge' */ + int nDeleteMerge; /* 'deletemerge' */ + int bPrefixInsttoken; /* 'prefix-insttoken' */ /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */ char **pzErrmsg; @@ -234239,7 +242819,14 @@ static int sqlite3Fts5StructureTest(Fts5Index*, void*); /* ** Used by xInstToken(): */ -static int sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*); +static int sqlite3Fts5IterToken( + Fts5IndexIter *pIndexIter, + const char *pToken, int nToken, + i64 iRowid, + int iCol, + int iOff, + const char **ppOut, int *pnOut +); /* ** Insert or remove data to or from the index. Each time a document is @@ -234535,7 +243122,7 @@ static int sqlite3Fts5ExprPattern( ** i64 iRowid = sqlite3Fts5ExprRowid(pExpr); ** } */ -static int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, int bDesc); +static int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, i64, int bDesc); static int sqlite3Fts5ExprNext(Fts5Expr*, i64 iMax); static int sqlite3Fts5ExprEof(Fts5Expr*); static i64 sqlite3Fts5ExprRowid(Fts5Expr*); @@ -234706,7 +243293,7 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*); ** ** The "lemon" program processes an LALR(1) input grammar file, then uses ** this template to construct a parser. The "lemon" program inserts text -** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the +** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the ** interstitial "-" characters) contained in this template is changed into ** the value of the %name directive from the grammar. Otherwise, the content ** of this template is copied straight through into the generate parser @@ -234846,14 +243433,22 @@ typedef union { #define sqlite3Fts5ParserARG_PARAM ,pParse #define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse=fts5yypParser->pParse; #define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse=pParse; +#undef fts5YYREALLOC #define fts5YYREALLOC realloc +#undef fts5YYFREE #define fts5YYFREE free +#undef fts5YYDYNSTACK #define fts5YYDYNSTACK 0 +#undef fts5YYSIZELIMIT +#define sqlite3Fts5ParserCTX(P) 0 #define sqlite3Fts5ParserCTX_SDECL #define sqlite3Fts5ParserCTX_PDECL #define sqlite3Fts5ParserCTX_PARAM #define sqlite3Fts5ParserCTX_FETCH #define sqlite3Fts5ParserCTX_STORE +#undef fts5YYERRORSYMBOL +#undef fts5YYERRSYMDT +#undef fts5YYFALLBACK #define fts5YYNSTATE 35 #define fts5YYNRULE 28 #define fts5YYNRULE_WITH_ACTION 28 @@ -235178,15 +243773,24 @@ static int fts5yyGrowStack(fts5yyParser *p){ int newSize; int idx; fts5yyStackEntry *pNew; +#ifdef fts5YYSIZELIMIT + int nLimit = fts5YYSIZELIMIT(sqlite3Fts5ParserCTX(p)); +#endif newSize = oldSize*2 + 100; +#ifdef fts5YYSIZELIMIT + if( newSize>nLimit ){ + newSize = nLimit; + if( newSize<=oldSize ) return 1; + } +#endif idx = (int)(p->fts5yytos - p->fts5yystack); if( p->fts5yystack==p->fts5yystk0 ){ - pNew = fts5YYREALLOC(0, newSize*sizeof(pNew[0])); + pNew = fts5YYREALLOC(0, newSize*sizeof(pNew[0]), sqlite3Fts5ParserCTX(p)); if( pNew==0 ) return 1; memcpy(pNew, p->fts5yystack, oldSize*sizeof(pNew[0])); }else{ - pNew = fts5YYREALLOC(p->fts5yystack, newSize*sizeof(pNew[0])); + pNew = fts5YYREALLOC(p->fts5yystack, newSize*sizeof(pNew[0]), sqlite3Fts5ParserCTX(p)); if( pNew==0 ) return 1; } p->fts5yystack = pNew; @@ -235366,7 +243970,9 @@ static void sqlite3Fts5ParserFinalize(void *p){ } #if fts5YYGROWABLESTACK - if( pParser->fts5yystack!=pParser->fts5yystk0 ) fts5YYFREE(pParser->fts5yystack); + if( pParser->fts5yystack!=pParser->fts5yystk0 ){ + fts5YYFREE(pParser->fts5yystack, sqlite3Fts5ParserCTX(pParser)); + } #endif } @@ -236619,7 +245225,7 @@ static void fts5SnippetFunction( int rc = SQLITE_OK; /* Return code */ int iCol; /* 1st argument to snippet() */ const char *zEllips; /* 4th argument to snippet() */ - int nToken; /* 5th argument to snippet() */ + i64 nToken; /* 5th argument to snippet() */ int nInst = 0; /* Number of instance matches this row */ int i; /* Used to iterate through instances */ int nPhrase; /* Number of phrases in query */ @@ -236644,11 +245250,11 @@ static void fts5SnippetFunction( ctx.zClose = fts5ValueToText(apVal[2]); ctx.iRangeEnd = -1; zEllips = fts5ValueToText(apVal[3]); - nToken = sqlite3_value_int(apVal[4]); + nToken = (int)(MIN( MAX(sqlite3_value_int64(apVal[4]), 0), 64)); iBestCol = (iCol>=0 ? iCol : 0); nPhrase = pApi->xPhraseCount(pFts); - aSeen = sqlite3_malloc(nPhrase); + aSeen = sqlite3_malloc64(nPhrase); if( aSeen==0 ){ rc = SQLITE_NOMEM; } @@ -236860,7 +245466,7 @@ static int fts5Bm25GetData( ** under consideration. ** ** The problem with this is that if (N < 2*nHit), the IDF is - ** negative. Which is undesirable. So the mimimum allowable IDF is + ** negative. Which is undesirable. So the minimum allowable IDF is ** (1e-6) - roughly the same as a term that appears in just over ** half of set of 5,000,000 documents. */ double idf = log( (nRow - nHit + 0.5) / (nHit + 0.5) ); @@ -237303,7 +245909,7 @@ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){ if( nIn<0 ){ nIn = (int)strlen(pIn); } - zRet = (char*)sqlite3_malloc(nIn+1); + zRet = (char*)sqlite3_malloc64((i64)nIn+1); if( zRet ){ memcpy(zRet, pIn, nIn); zRet[nIn] = '\0'; @@ -237323,7 +245929,7 @@ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){ ** * The 52 upper and lower case ASCII characters, and ** * The 10 integer ASCII characters. ** * The underscore character "_" (0x5F). -** * The unicode "subsitute" character (0x1A). +** * The unicode "substitute" character (0x1A). */ static int sqlite3Fts5IsBareword(char t){ u8 aBareword[128] = { @@ -238003,7 +246609,7 @@ static int sqlite3Fts5ConfigParse( sqlite3_int64 nByte; int bUnindexed = 0; /* True if there are one or more UNINDEXED */ - *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config)); + *ppOut = pRet = (Fts5Config*)sqlite3_malloc64(sizeof(Fts5Config)); if( pRet==0 ) return SQLITE_NOMEM; memset(pRet, 0, sizeof(Fts5Config)); pRet->pGlobal = pGlobal; @@ -238453,6 +247059,19 @@ static int sqlite3Fts5ConfigSetValue( }else{ pConfig->bSecureDelete = (bVal ? 1 : 0); } + } + + else if( 0==sqlite3_stricmp(zKey, "insttoken") ){ + int bVal = -1; + if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ + bVal = sqlite3_value_int(pVal); + } + if( bVal<0 ){ + *pbBadkey = 1; + }else{ + pConfig->bPrefixInsttoken = (bVal ? 1 : 0); + } + }else{ *pbBadkey = 1; } @@ -238538,8 +247157,6 @@ static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){ va_end(ap); } - - /* ** 2014 May 31 ** @@ -238628,9 +247245,13 @@ struct Fts5ExprNode { /* Child nodes. For a NOT node, this array always contains 2 entries. For ** AND or OR nodes, it contains 2 or more entries. */ int nChild; /* Number of child nodes */ - Fts5ExprNode *apChild[1]; /* Array of child nodes */ + Fts5ExprNode *apChild[FLEXARRAY]; /* Array of child nodes */ }; +/* Size (in bytes) of an Fts5ExprNode object that holds up to N children */ +#define SZ_FTS5EXPRNODE(N) \ + (offsetof(Fts5ExprNode,apChild) + (N)*sizeof(Fts5ExprNode*)) + #define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING) /* @@ -238661,9 +247282,13 @@ struct Fts5ExprPhrase { Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */ Fts5Buffer poslist; /* Current position list */ int nTerm; /* Number of entries in aTerm[] */ - Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */ + Fts5ExprTerm aTerm[FLEXARRAY]; /* Terms that make up this phrase */ }; +/* Size (in bytes) of an Fts5ExprPhrase object that holds up to N terms */ +#define SZ_FTS5EXPRPHRASE(N) \ + (offsetof(Fts5ExprPhrase,aTerm) + (N)*sizeof(Fts5ExprTerm)) + /* ** One or more phrases that must appear within a certain token distance of ** each other within each matching document. @@ -238672,9 +247297,12 @@ struct Fts5ExprNearset { int nNear; /* NEAR parameter */ Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */ int nPhrase; /* Number of entries in aPhrase[] array */ - Fts5ExprPhrase *apPhrase[1]; /* Array of phrase pointers */ + Fts5ExprPhrase *apPhrase[FLEXARRAY]; /* Array of phrase pointers */ }; +/* Size (in bytes) of an Fts5ExprNearset object covering up to N phrases */ +#define SZ_FTS5EXPRNEARSET(N) \ + (offsetof(Fts5ExprNearset,apPhrase)+(N)*sizeof(Fts5ExprPhrase*)) /* ** Parse context. @@ -238834,7 +247462,7 @@ static int sqlite3Fts5ExprNew( /* If the LHS of the MATCH expression was a user column, apply the ** implicit column-filter. */ if( sParse.rc==SQLITE_OK && iColnCol ){ - int n = sizeof(Fts5Colset); + int n = SZ_FTS5COLSET(1); Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n); if( pColset ){ pColset->nCol = 1; @@ -238845,7 +247473,7 @@ static int sqlite3Fts5ExprNew( assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 ); if( sParse.rc==SQLITE_OK ){ - *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr)); + *ppNew = pNew = sqlite3_malloc64(sizeof(Fts5Expr)); if( pNew==0 ){ sParse.rc = SQLITE_NOMEM; sqlite3Fts5ParseNodeFree(sParse.pExpr); @@ -238997,7 +247625,7 @@ static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){ p2->pRoot = 0; if( sParse.rc==SQLITE_OK ){ - Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc( + Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc64( p1->apExprPhrase, nPhrase * sizeof(Fts5ExprPhrase*) ); if( ap==0 ){ @@ -239338,7 +247966,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){ i64 iPos = a[i].reader.iPos; Fts5PoslistWriter *pWriter = &a[i].writer; if( a[i].pOut->n==0 || iPos!=pWriter->iPrev ){ - sqlite3Fts5PoslistWriterAppend(a[i].pOut, pWriter, iPos); + sqlite3Fts5PoslistSafeAppend(a[i].pOut, &pWriter->iPrev, iPos); } } @@ -240080,7 +248708,13 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){ ** Return SQLITE_OK if successful, or an SQLite error code otherwise. It ** is not considered an error if the query does not match any documents. */ -static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){ +static int sqlite3Fts5ExprFirst( + Fts5Expr *p, + Fts5Index *pIdx, + i64 iFirst, + i64 iLast, + int bDesc +){ Fts5ExprNode *pRoot = p->pRoot; int rc; /* Return code */ @@ -240102,6 +248736,9 @@ static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bD assert( pRoot->bEof==0 ); rc = fts5ExprNodeNext(p, pRoot, 0, 0); } + if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){ + pRoot->bEof = 1; + } return rc; } @@ -240192,7 +248829,7 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( if( pParse->rc==SQLITE_OK ){ if( pNear==0 ){ sqlite3_int64 nByte; - nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); + nByte = SZ_FTS5EXPRNEARSET(SZALLOC+1); pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; @@ -240203,7 +248840,7 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( int nNew = pNear->nPhrase + SZALLOC; sqlite3_int64 nByte; - nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*); + nByte = SZ_FTS5EXPRNEARSET(nNew+1); pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; @@ -240280,10 +248917,10 @@ static int fts5ParseTokenize( memset(pSyn, 0, (size_t)nByte); pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); pSyn->nFullTerm = pSyn->nQueryTerm = nToken; + memcpy(pSyn->pTerm, pToken, nToken); if( pCtx->pConfig->bTokendata ){ pSyn->nQueryTerm = (int)strlen(pSyn->pTerm); } - memcpy(pSyn->pTerm, pToken, nToken); pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; } @@ -240294,12 +248931,12 @@ static int fts5ParseTokenize( int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0); pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase, - sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew + SZ_FTS5EXPRPHRASE(nNew+1) ); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ - if( pPhrase==0 ) memset(pNew, 0, sizeof(Fts5ExprPhrase)); + if( pPhrase==0 ) memset(pNew, 0, SZ_FTS5EXPRPHRASE(1)); pCtx->pPhrase = pPhrase = pNew; pNew->nTerm = nNew - SZALLOC; } @@ -240407,7 +249044,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( if( sCtx.pPhrase==0 ){ /* This happens when parsing a token or quoted phrase that contains ** no token characters at all. (e.g ... MATCH '""'). */ - sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase)); + sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, SZ_FTS5EXPRPHRASE(1)); }else if( sCtx.pPhrase->nTerm ){ sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix; } @@ -240442,19 +249079,18 @@ static int sqlite3Fts5ExprClonePhrase( sizeof(Fts5ExprPhrase*)); } if( rc==SQLITE_OK ){ - pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, - sizeof(Fts5ExprNode)); + pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRNODE(1)); } if( rc==SQLITE_OK ){ pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, - sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); + SZ_FTS5EXPRNEARSET(2)); } if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ sqlite3_int64 nByte; Fts5Colset *pColset; - nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); + nByte = SZ_FTS5COLSET(pColsetOrig->nCol); pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); if( pColset ){ memcpy(pColset, pColsetOrig, (size_t)nByte); @@ -240482,7 +249118,7 @@ static int sqlite3Fts5ExprClonePhrase( }else{ /* This happens when parsing a token or quoted phrase that contains ** no token characters at all. (e.g ... MATCH '""'). */ - sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); + sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRPHRASE(1)); } } @@ -240547,7 +249183,8 @@ static void sqlite3Fts5ParseSetDistance( ); return; } - nNear = nNear * 10 + (p->p[i] - '0'); + if( nNear<214748363 ) nNear = nNear * 10 + (p->p[i] - '0'); + /* ^^^^^^^^^^^^^^^--- Prevent integer overflow */ } }else{ nNear = FTS5_DEFAULT_NEARDIST; @@ -240576,7 +249213,7 @@ static Fts5Colset *fts5ParseColset( assert( pParse->rc==SQLITE_OK ); assert( iCol>=0 && iColpConfig->nCol ); - pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol); + pNew = sqlite3_realloc64(p, SZ_FTS5COLSET(nCol+1)); if( pNew==0 ){ pParse->rc = SQLITE_NOMEM; }else{ @@ -240611,7 +249248,7 @@ static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p int nCol = pParse->pConfig->nCol; pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, - sizeof(Fts5Colset) + sizeof(int)*nCol + SZ_FTS5COLSET(nCol+1) ); if( pRet ){ int i; @@ -240672,7 +249309,7 @@ static Fts5Colset *sqlite3Fts5ParseColset( static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){ Fts5Colset *pRet; if( pOrig ){ - sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int); + sqlite3_int64 nByte = SZ_FTS5COLSET(pOrig->nCol); pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte); if( pRet ){ memcpy(pRet, pOrig, (size_t)nByte); @@ -240840,7 +249477,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd( assert( pNear->nPhrase==1 ); assert( pParse->bPhraseToAnd ); - nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*); + nByte = SZ_FTS5EXPRNODE(nTerm+1); pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); if( pRet ){ pRet->eType = FTS5_AND; @@ -240850,7 +249487,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd( pParse->nPhrase--; for(ii=0; iirc, sizeof(Fts5ExprPhrase) + &pParse->rc, SZ_FTS5EXPRPHRASE(1) ); if( pPhrase ){ if( parseGrowPhraseArray(pParse) ){ @@ -240919,7 +249556,7 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( if( pRight->eType==eType ) nChild += pRight->nChild-1; } - nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); + nByte = SZ_FTS5EXPRNODE(nChild); pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); if( pRet ){ @@ -241588,7 +250225,7 @@ static int fts5ExprPopulatePoslistsCb( int rc = sqlite3Fts5PoslistWriterAppend( &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff ); - if( rc==SQLITE_OK && pExpr->pConfig->bTokendata && !pT->bPrefix ){ + if( rc==SQLITE_OK && (pExpr->pConfig->bTokendata || pT->bPrefix) ){ int iCol = p->iOff>>32; int iTokOff = p->iOff & 0x7FFFFFFF; rc = sqlite3Fts5IndexIterWriteTokendata( @@ -241781,21 +250418,20 @@ static int sqlite3Fts5ExprInstToken( return SQLITE_RANGE; } pTerm = &pPhrase->aTerm[iToken]; - if( pTerm->bPrefix==0 ){ - if( pExpr->pConfig->bTokendata ){ - rc = sqlite3Fts5IterToken( - pTerm->pIter, iRowid, iCol, iOff+iToken, ppOut, pnOut - ); - }else{ - *ppOut = pTerm->pTerm; - *pnOut = pTerm->nFullTerm; - } + if( pExpr->pConfig->bTokendata || pTerm->bPrefix ){ + rc = sqlite3Fts5IterToken( + pTerm->pIter, pTerm->pTerm, pTerm->nQueryTerm, + iRowid, iCol, iOff+iToken, ppOut, pnOut + ); + }else{ + *ppOut = pTerm->pTerm; + *pnOut = pTerm->nFullTerm; } return rc; } /* -** Clear the token mappings for all Fts5IndexIter objects mannaged by +** Clear the token mappings for all Fts5IndexIter objects managed by ** the expression passed as the only argument. */ static void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){ @@ -241830,7 +250466,7 @@ typedef struct Fts5HashEntry Fts5HashEntry; /* ** This file contains the implementation of an in-memory hash table used -** to accumuluate "term -> doclist" content before it is flused to a level-0 +** to accumulate "term -> doclist" content before it is flushed to a level-0 ** segment. */ @@ -241887,7 +250523,7 @@ struct Fts5HashEntry { }; /* -** Eqivalent to: +** Equivalent to: ** ** char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; } */ @@ -241901,7 +250537,7 @@ static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte int rc = SQLITE_OK; Fts5Hash *pNew; - *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash)); + *ppNew = pNew = (Fts5Hash*)sqlite3_malloc64(sizeof(Fts5Hash)); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ @@ -242823,9 +251459,13 @@ struct Fts5Structure { u64 nOriginCntr; /* Origin value for next top-level segment */ int nSegment; /* Total segments in this structure */ int nLevel; /* Number of levels in this index */ - Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */ + Fts5StructureLevel aLevel[FLEXARRAY]; /* Array of nLevel level objects */ }; +/* Size (in bytes) of an Fts5Structure object holding up to N levels */ +#define SZ_FTS5STRUCTURE(N) \ + (offsetof(Fts5Structure,aLevel) + (N)*sizeof(Fts5StructureLevel)) + /* ** An object of type Fts5SegWriter is used to write to segments. */ @@ -242951,15 +251591,49 @@ struct Fts5SegIter { u8 bDel; /* True if the delete flag is set */ }; +static int fts5IndexCorruptRowid(Fts5Index *pIdx, i64 iRowid){ + pIdx->rc = FTS5_CORRUPT; + sqlite3Fts5ConfigErrmsg(pIdx->pConfig, + "fts5: corruption found reading blob %lld from table \"%s\"", + iRowid, pIdx->pConfig->zName + ); + return SQLITE_CORRUPT_VTAB; +} +#define FTS5_CORRUPT_ROWID(pIdx, iRowid) fts5IndexCorruptRowid(pIdx, iRowid) + +static int fts5IndexCorruptIter(Fts5Index *pIdx, Fts5SegIter *pIter){ + pIdx->rc = FTS5_CORRUPT; + sqlite3Fts5ConfigErrmsg(pIdx->pConfig, + "fts5: corruption on page %d, segment %d, table \"%s\"", + pIter->iLeafPgno, pIter->pSeg->iSegid, pIdx->pConfig->zName + ); + return SQLITE_CORRUPT_VTAB; +} +#define FTS5_CORRUPT_ITER(pIdx, pIter) fts5IndexCorruptIter(pIdx, pIter) + +static int fts5IndexCorruptIdx(Fts5Index *pIdx){ + pIdx->rc = FTS5_CORRUPT; + sqlite3Fts5ConfigErrmsg(pIdx->pConfig, + "fts5: corruption in table \"%s\"", pIdx->pConfig->zName + ); + return SQLITE_CORRUPT_VTAB; +} +#define FTS5_CORRUPT_IDX(pIdx) fts5IndexCorruptIdx(pIdx) + + /* ** Array of tombstone pages. Reference counted. */ struct Fts5TombstoneArray { - int nRef; /* Number of pointers to this object */ + int nRef; /* Number of pointers to this object */ int nTombstone; - Fts5Data *apTombstone[1]; /* Array of tombstone pages */ + Fts5Data *apTombstone[FLEXARRAY]; /* Array of tombstone pages */ }; +/* Size (in bytes) of an Fts5TombstoneArray holding up to N tombstones */ +#define SZ_FTS5TOMBSTONEARRAY(N) \ + (offsetof(Fts5TombstoneArray,apTombstone)+(N)*sizeof(Fts5Data*)) + /* ** Argument is a pointer to an Fts5Data structure that contains a ** leaf page. @@ -243028,9 +251702,12 @@ struct Fts5Iter { i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */ Fts5CResult *aFirst; /* Current merge state (see above) */ - Fts5SegIter aSeg[1]; /* Array of segment iterators */ + Fts5SegIter aSeg[FLEXARRAY]; /* Array of segment iterators */ }; +/* Size (in bytes) of an Fts5Iter object holding up to N segment iterators */ +#define SZ_FTS5ITER(N) (offsetof(Fts5Iter,aSeg)+(N)*sizeof(Fts5SegIter)) + /* ** An instance of the following type is used to iterate through the contents ** of a doclist-index record. @@ -243057,9 +251734,13 @@ struct Fts5DlidxLvl { struct Fts5DlidxIter { int nLvl; int iSegid; - Fts5DlidxLvl aLvl[1]; + Fts5DlidxLvl aLvl[FLEXARRAY]; }; +/* Size (in bytes) of an Fts5DlidxIter object with up to N levels */ +#define SZ_FTS5DLIDXITER(N) \ + (offsetof(Fts5DlidxIter,aLvl)+(N)*sizeof(Fts5DlidxLvl)) + static void fts5PutU16(u8 *aOut, u16 iVal){ aOut[0] = (iVal>>8); aOut[1] = (iVal&0xFF); @@ -243179,11 +251860,13 @@ static int fts5LeafFirstTermOff(Fts5Data *pLeaf){ /* ** Close the read-only blob handle, if it is open. */ -static void sqlite3Fts5IndexCloseReader(Fts5Index *p){ +static void fts5IndexCloseReader(Fts5Index *p){ if( p->pReader ){ + int rc; sqlite3_blob *pReader = p->pReader; p->pReader = 0; - sqlite3_blob_close(pReader); + rc = sqlite3_blob_close(pReader); + if( p->rc==SQLITE_OK ) p->rc = rc; } } @@ -243208,7 +251891,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ assert( p->pReader==0 ); p->pReader = pBlob; if( rc!=SQLITE_OK ){ - sqlite3Fts5IndexCloseReader(p); + fts5IndexCloseReader(p); } if( rc==SQLITE_ABORT ) rc = SQLITE_OK; } @@ -243227,16 +251910,17 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ ** All the reasons those functions might return SQLITE_ERROR - missing ** table, missing row, non-blob/text in block column - indicate ** backing store corruption. */ - if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT; + if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT_ROWID(p, iRowid); if( rc==SQLITE_OK ){ u8 *aOut = 0; /* Read blob data into this buffer */ - int nByte = sqlite3_blob_bytes(p->pReader); - int szData = (sizeof(Fts5Data) + 7) & ~7; - sqlite3_int64 nAlloc = szData + nByte + FTS5_DATA_PADDING; + i64 nByte = sqlite3_blob_bytes(p->pReader); + i64 szData = (sizeof(Fts5Data) + 7) & ~7; + i64 nAlloc = szData + nByte + FTS5_DATA_PADDING; pRet = (Fts5Data*)sqlite3_malloc64(nAlloc); if( pRet ){ pRet->nn = nByte; + pRet->szLeaf = 0; aOut = pRet->p = (u8*)pRet + szData; }else{ rc = SQLITE_NOMEM; @@ -243249,10 +251933,8 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ sqlite3_free(pRet); pRet = 0; }else{ - /* TODO1: Fix this */ pRet->p[nByte] = 0x00; pRet->p[nByte+1] = 0x00; - pRet->szLeaf = fts5GetU16(&pRet->p[2]); } } p->rc = rc; @@ -243273,11 +251955,19 @@ static void fts5DataRelease(Fts5Data *pData){ sqlite3_free(pData); } +/* +** Read a leaf-page record. This is similar to fts5DataRead(), except that +** it fills in the Fts5Data.szLeaf value before returning. +*/ static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){ Fts5Data *pRet = fts5DataRead(p, iRowid); if( pRet ){ - if( pRet->nn<4 || pRet->szLeaf>pRet->nn ){ - p->rc = FTS5_CORRUPT; + assert( pRet->szLeaf==0 ); + if( pRet->nn>=4 ){ + pRet->szLeaf = fts5GetU16(&pRet->p[2]); + } + if( pRet->szLeaf<4 || pRet->szLeaf>pRet->nn ){ + FTS5_CORRUPT_ROWID(p, iRowid); fts5DataRelease(pRet); pRet = 0; } @@ -243292,9 +251982,13 @@ static int fts5IndexPrepareStmt( ){ if( p->rc==SQLITE_OK ){ if( zSql ){ - p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1, + int rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1, SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB, ppStmt, 0); + /* If this prepare() call fails with SQLITE_ERROR, then one of the + ** %_idx or %_data tables has been removed or modified. Call this + ** corruption. */ + p->rc = (rc==SQLITE_ERROR ? SQLITE_CORRUPT : rc); }else{ p->rc = SQLITE_NOMEM; } @@ -243421,7 +252115,7 @@ static int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){ static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){ Fts5Structure *p = *pp; if( *pRc==SQLITE_OK && p->nRef>1 ){ - i64 nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel); + i64 nByte = SZ_FTS5STRUCTURE(p->nLevel); Fts5Structure *pNew; pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte); if( pNew ){ @@ -243495,10 +252189,7 @@ static int fts5StructureDecode( ){ return FTS5_CORRUPT; } - nByte = ( - sizeof(Fts5Structure) + /* Main structure */ - sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */ - ); + nByte = SZ_FTS5STRUCTURE(nLevel); pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte); if( pRet ){ @@ -243519,7 +252210,7 @@ static int fts5StructureDecode( i += fts5GetVarint32(&pData[i], nTotal); if( nTotalnMerge ) rc = FTS5_CORRUPT; pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, - nTotal * sizeof(Fts5StructureSegment) + (i64)nTotal * sizeof(Fts5StructureSegment) ); nSegment -= nTotal; } @@ -243578,10 +252269,7 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){ if( *pRc==SQLITE_OK ){ Fts5Structure *pStruct = *ppStruct; int nLevel = pStruct->nLevel; - sqlite3_int64 nByte = ( - sizeof(Fts5Structure) + /* Main structure */ - sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */ - ); + sqlite3_int64 nByte = SZ_FTS5STRUCTURE(nLevel+2); pStruct = sqlite3_realloc64(pStruct, nByte); if( pStruct ){ @@ -243638,8 +252326,14 @@ static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){ /* TODO: Do we need this if the leaf-index is appended? Probably... */ memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING); p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet); - if( p->rc==SQLITE_OK && (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){ - p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); + if( p->rc==SQLITE_OK ){ + if( (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){ + p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); + } + }else if( p->rc==SQLITE_CORRUPT_VTAB ){ + sqlite3Fts5ConfigErrmsg(p->pConfig, + "fts5: corrupt structure record for table \"%s\"", p->pConfig->zName + ); } fts5DataRelease(pData); if( p->rc!=SQLITE_OK ){ @@ -244120,7 +252814,7 @@ static Fts5DlidxIter *fts5DlidxIterInit( int bDone = 0; for(i=0; p->rc==SQLITE_OK && bDone==0; i++){ - sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl); + sqlite3_int64 nByte = SZ_FTS5DLIDXITER(i+1); Fts5DlidxIter *pNew; pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte); @@ -244262,7 +252956,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ while( iOff>=pIter->pLeaf->szLeaf ){ fts5SegIterNextPage(p, pIter); if( pIter->pLeaf==0 ){ - if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; + if( p->rc==SQLITE_OK ) FTS5_CORRUPT_ITER(p, pIter); return; } iOff = 4; @@ -244294,7 +252988,7 @@ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){ iOff += fts5GetVarint32(&a[iOff], nNew); if( iOff+nNew>pIter->pLeaf->szLeaf || nKeep>pIter->term.n || nNew==0 ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ITER(p, pIter); return; } pIter->term.n = nKeep; @@ -244336,9 +253030,9 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){ ** leave an error in the Fts5Index object. */ static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){ - const int nTomb = pIter->pSeg->nPgTombstone; + const i64 nTomb = (i64)pIter->pSeg->nPgTombstone; if( nTomb>0 ){ - int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray); + i64 nByte = SZ_FTS5TOMBSTONEARRAY(nTomb+1); Fts5TombstoneArray *pNew; pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pNew ){ @@ -244424,6 +253118,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ while( 1 ){ u64 iDelta = 0; + if( i>=n ) break; if( eDetail==FTS5_DETAIL_NONE ){ /* todo */ if( iaRowidOffset[] array. */ if( iRowidOffset>=pIter->nRowidOffset ){ - int nNew = pIter->nRowidOffset + 8; + i64 nNew = pIter->nRowidOffset + 8; int *aNew = (int*)sqlite3_realloc64(pIter->aRowidOffset,nNew*sizeof(int)); if( aNew==0 ){ p->rc = SQLITE_NOMEM; @@ -244471,7 +253166,7 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){ while( p->rc==SQLITE_OK && pIter->iLeafPgno>pIter->iTermLeafPgno ){ Fts5Data *pNew; pIter->iLeafPgno--; - pNew = fts5DataRead(p, FTS5_SEGMENT_ROWID( + pNew = fts5LeafRead(p, FTS5_SEGMENT_ROWID( pIter->pSeg->iSegid, pIter->iLeafPgno )); if( pNew ){ @@ -244489,7 +253184,7 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){ iRowidOff = fts5LeafFirstRowidOff(pNew); if( iRowidOff ){ if( iRowidOff>=pNew->szLeaf ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ITER(p, pIter); }else{ pIter->pLeaf = pNew; pIter->iLeafOffset = iRowidOff; @@ -244723,7 +253418,7 @@ static void fts5SegIterNext( } assert_nc( iOffszLeaf ); if( iOff>pLeaf->szLeaf ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ITER(p, pIter); return; } } @@ -244831,18 +253526,20 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ fts5DataRelease(pIter->pLeaf); pIter->pLeaf = pLast; pIter->iLeafPgno = pgnoLast; - iOff = fts5LeafFirstRowidOff(pLast); - if( iOff>pLast->szLeaf ){ - p->rc = FTS5_CORRUPT; - return; - } - iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid); - pIter->iLeafOffset = iOff; + if( p->rc==SQLITE_OK ){ + iOff = fts5LeafFirstRowidOff(pLast); + if( iOff>pLast->szLeaf ){ + FTS5_CORRUPT_ITER(p, pIter); + return; + } + iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid); + pIter->iLeafOffset = iOff; - if( fts5LeafIsTermless(pLast) ){ - pIter->iEndofDoclist = pLast->nn+1; - }else{ - pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast); + if( fts5LeafIsTermless(pLast) ){ + pIter->iEndofDoclist = pLast->nn+1; + }else{ + pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast); + } } } @@ -244912,7 +253609,7 @@ static void fts5LeafSeek( iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff); iOff = iTermOff; if( iOff>n ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ITER(p, pIter); return; } @@ -244923,6 +253620,10 @@ static void fts5LeafSeek( if( nKeepn ){ + FTS5_CORRUPT_ITER(p, pIter); + return; + } assert( nKeep>=nMatch ); if( nKeep==nMatch ){ @@ -244955,7 +253656,7 @@ static void fts5LeafSeek( iOff = iTermOff; if( iOff>=n ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ITER(p, pIter); return; } @@ -244977,7 +253678,7 @@ static void fts5LeafSeek( iPgidx = (u32)pIter->pLeaf->szLeaf; iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff); if( iOff<4 || (i64)iOff>=pIter->pLeaf->szLeaf ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ITER(p, pIter); return; }else{ nKeep = 0; @@ -244992,7 +253693,7 @@ static void fts5LeafSeek( search_success: if( (i64)iOff+nNew>n || nNew<1 ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ITER(p, pIter); return; } pIter->iLeafOffset = iOff + nNew; @@ -245174,6 +253875,10 @@ static void fts5SegIterNextInit( pIter->iPgidxOff = pIter->pLeaf->szLeaf; pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], iTermOff); + if( iTermOff > pIter->pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + return; + } pIter->iLeafOffset = iTermOff; fts5SegIterLoadTerm(p, pIter, 0); fts5SegIterLoadNPos(p, pIter); @@ -245457,7 +254162,7 @@ static void fts5SegIterGotoPage( assert( iLeafPgno>pIter->iLeafPgno ); if( iLeafPgno>pIter->pSeg->pgnoLast ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_IDX(p); }else{ fts5DataRelease(pIter->pNextLeaf); pIter->pNextLeaf = 0; @@ -245472,7 +254177,7 @@ static void fts5SegIterGotoPage( u8 *a = pIter->pLeaf->p; int n = pIter->pLeaf->szLeaf; if( iOff<4 || iOff>=n ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_IDX(p); }else{ iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid); pIter->iLeafOffset = iOff; @@ -245799,8 +254504,7 @@ static Fts5Iter *fts5MultiIterAlloc( for(nSlot=2; nSlotaSeg[] */ + SZ_FTS5ITER(nSlot) + /* pNew + pNew->aSeg[] */ sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */ ); if( pNew ){ @@ -245900,8 +254604,7 @@ static void fts5PoslistFilterCallback( do { while( ieState ){ fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart); @@ -245952,7 +254655,7 @@ static void fts5ChunkIterate( if( nRem<=0 ){ break; }else if( pSeg->pSeg==0 ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_IDX(p); return; }else{ pgno++; @@ -246050,7 +254753,7 @@ static void fts5IndexExtractColset( /* Advance pointer p until it points to pEnd or an 0x01 byte that is ** not part of a varint */ while( paiCol[i]==iCurrent ){ @@ -246147,8 +254850,11 @@ static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){ assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS ); assert( pIter->pColset ); + assert( pIter->poslist.nSpace>=pIter->pIndex->pConfig->nCol ); - if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf ){ + if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf + || pSeg->nPos>pIter->pIndex->pConfig->nCol + ){ fts5IterSetOutputs_Col(pIter, pSeg); }else{ u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset]; @@ -247055,7 +255761,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ ** a single page has been assigned to more than one segment. In ** this case a prior iteration of this loop may have corrupted the ** segment currently being trimmed. */ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ROWID(p, iLeafRowid); }else{ fts5BufferZero(&buf); fts5BufferGrow(&p->rc, &buf, pData->nn); @@ -247406,6 +256112,14 @@ static int fts5IndexReturn(Fts5Index *p){ return rc; } +/* +** Close the read-only blob handle, if it is open. +*/ +static void sqlite3Fts5IndexCloseReader(Fts5Index *p){ + fts5IndexCloseReader(p); + fts5IndexReturn(p); +} + typedef struct Fts5FlushCtx Fts5FlushCtx; struct Fts5FlushCtx { Fts5Index *pIdx; @@ -247491,7 +256205,7 @@ static void fts5SecureDeleteOverflow( int iNext = 0; u8 *aPg = 0; - pLeaf = fts5DataRead(p, iRowid); + pLeaf = fts5LeafRead(p, iRowid); if( pLeaf==0 ) break; aPg = pLeaf->p; @@ -247499,7 +256213,7 @@ static void fts5SecureDeleteOverflow( if( iNext!=0 ){ *pbLastInDoclist = 0; } - if( iNext==0 && pLeaf->szLeaf!=pLeaf->nn ){ + if( iNext==0 && pLeaf->szLeafnn ){ fts5GetVarint32(&aPg[pLeaf->szLeaf], iNext); } @@ -247514,7 +256228,7 @@ static void fts5SecureDeleteOverflow( }else if( bDetailNone ){ break; }else if( iNext>=pLeaf->szLeaf || pLeaf->nnszLeaf || iNext<4 ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ROWID(p, iRowid); break; }else{ int nShift = iNext - 4; @@ -247534,7 +256248,7 @@ static void fts5SecureDeleteOverflow( i1 += fts5GetVarint32(&aPg[i1], iFirst); if( iFirstrc = FTS5_CORRUPT; + FTS5_CORRUPT_ROWID(p, iRowid); break; } aIdx = sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2); @@ -247580,7 +256294,7 @@ static void fts5DoSecureDelete( int iSegid = pSeg->pSeg->iSegid; u8 *aPg = pSeg->pLeaf->p; int nPg = pSeg->pLeaf->nn; - int iPgIdx = pSeg->pLeaf->szLeaf; + int iPgIdx = pSeg->pLeaf->szLeaf; /* Offset of page footer */ u64 iDelta = 0; int iNextOff = 0; @@ -247593,7 +256307,7 @@ static void fts5DoSecureDelete( int iDelKeyOff = 0; /* Offset of deleted key, if any */ nIdx = nPg-iPgIdx; - aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16); + aIdx = sqlite3Fts5MallocZero(&p->rc, ((i64)nIdx)+16); if( p->rc ) return; memcpy(aIdx, &aPg[iPgIdx], nIdx); @@ -247634,6 +256348,11 @@ static void fts5DoSecureDelete( }else{ iStart = fts5GetU16(&aPg[0]); } + if( iStart>nPg ){ + FTS5_CORRUPT_IDX(p); + sqlite3_free(aIdx); + return; + } iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta); assert_nc( iSOP<=pSeg->iLeafOffset ); @@ -247659,7 +256378,7 @@ static void fts5DoSecureDelete( iSOP += fts5GetVarint32(&aPg[iSOP], nPos); } assert_nc( iSOP==pSeg->iLeafOffset ); - iNextOff = pSeg->iLeafOffset + pSeg->nPos; + iNextOff = iSOP + pSeg->nPos; } } @@ -247739,32 +256458,32 @@ static void fts5DoSecureDelete( ** is another term following it on this page. So the subsequent term ** needs to be moved to replace the term associated with the entry ** being removed. */ - int nPrefix = 0; - int nSuffix = 0; - int nPrefix2 = 0; - int nSuffix2 = 0; + u64 nPrefix = 0; + u64 nSuffix = 0; + u64 nPrefix2 = 0; + u64 nSuffix2 = 0; iDelKeyOff = iNextOff; - iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2); - iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2); + iNextOff += fts5GetVarint(&aPg[iNextOff], &nPrefix2); + iNextOff += fts5GetVarint(&aPg[iNextOff], &nSuffix2); if( iKey!=1 ){ - iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix); + iKeyOff += fts5GetVarint(&aPg[iKeyOff], &nPrefix); } - iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix); + iKeyOff += fts5GetVarint(&aPg[iKeyOff], &nSuffix); nPrefix = MIN(nPrefix, nPrefix2); nSuffix = (nPrefix2 + nSuffix2) - nPrefix; - if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){ - p->rc = FTS5_CORRUPT; + if( (iKeyOff+nSuffix)>(u64)iPgIdx || (iNextOff+nSuffix2)>(u64)iPgIdx ){ + FTS5_CORRUPT_IDX(p); }else{ if( iKey!=1 ){ iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix); } iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix); - if( nPrefix2>pSeg->term.n ){ - p->rc = FTS5_CORRUPT; + if( nPrefix2>(u64)pSeg->term.n ){ + FTS5_CORRUPT_IDX(p); }else if( nPrefix2>nPrefix ){ memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix); iOff += (nPrefix2-nPrefix); @@ -247781,7 +256500,7 @@ static void fts5DoSecureDelete( /* The entry being removed may be the only position list in ** its doclist. */ for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){ - Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno)); + Fts5Data *pPg = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno)); int bEmpty = (pPg && pPg->nn==4); fts5DataRelease(pPg); if( bEmpty==0 ) break; @@ -247789,12 +256508,12 @@ static void fts5DoSecureDelete( if( iPgno==pSeg->iTermLeafPgno ){ i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno); - Fts5Data *pTerm = fts5DataRead(p, iId); + Fts5Data *pTerm = fts5LeafRead(p, iId); if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){ u8 *aTermIdx = &pTerm->p[pTerm->szLeaf]; int nTermIdx = pTerm->nn - pTerm->szLeaf; int iTermIdx = 0; - int iTermOff = 0; + i64 iTermOff = 0; while( 1 ){ u32 iVal = 0; @@ -247805,12 +256524,15 @@ static void fts5DoSecureDelete( } nTermIdx = iTermIdx; - memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx); - fts5PutU16(&pTerm->p[2], iTermOff); - - fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx); - if( nTermIdx==0 ){ - fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno); + if( iTermOff>pTerm->szLeaf ){ + FTS5_CORRUPT_IDX(p); + }else{ + memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx); + fts5PutU16(&pTerm->p[2], iTermOff); + fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx); + if( nTermIdx==0 ){ + fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno); + } } } fts5DataRelease(pTerm); @@ -247833,7 +256555,9 @@ static void fts5DoSecureDelete( int iPrevKeyOut = 0; int iKeyIn = 0; - memmove(&aPg[iOff], &aPg[iNextOff], nMove); + if( nMove>0 ){ + memmove(&aPg[iOff], &aPg[iNextOff], nMove); + } iPgIdx -= nShift; nPg = iPgIdx; fts5PutU16(&aPg[2], iPgIdx); @@ -247863,8 +256587,11 @@ static void fts5DoSecureDelete( ** This is called as part of flushing a delete to disk in 'secure-delete' ** mode. It edits the segments within the database described by argument ** pStruct to remove the entries for term zTerm, rowid iRowid. +** +** Return SQLITE_OK if successful, or an SQLite error code if an error +** has occurred. Any error code is also stored in the Fts5Index handle. */ -static void fts5FlushSecureDelete( +static int fts5FlushSecureDelete( Fts5Index *p, Fts5Structure *pStruct, const char *zTerm, @@ -247874,6 +256601,24 @@ static void fts5FlushSecureDelete( const int f = FTS5INDEX_QUERY_SKIPHASH; Fts5Iter *pIter = 0; /* Used to find term instance */ + /* If the version number has not been set to SECUREDELETE, do so now. */ + if( p->pConfig->iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE ){ + Fts5Config *pConfig = p->pConfig; + sqlite3_stmt *pStmt = 0; + fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf( + "REPLACE INTO %Q.'%q_config' VALUES ('version', %d)", + pConfig->zDb, pConfig->zName, FTS5_CURRENT_VERSION_SECUREDELETE + )); + if( p->rc==SQLITE_OK ){ + int rc; + sqlite3_step(pStmt); + rc = sqlite3_finalize(pStmt); + if( p->rc==SQLITE_OK ) p->rc = rc; + pConfig->iCookie++; + pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE; + } + } + fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter); if( fts5MultiIterEof(p, pIter)==0 ){ i64 iThis = fts5MultiIterRowid(pIter); @@ -247891,6 +256636,7 @@ static void fts5FlushSecureDelete( } fts5MultiIterFree(pIter); + return p->rc; } @@ -247974,8 +256720,9 @@ static void fts5FlushOneHash(Fts5Index *p){ ** using fts5FlushSecureDelete(). */ if( bSecureDelete ){ if( eDetail==FTS5_DETAIL_NONE ){ - if( iOffrc!=SQLITE_OK || pDoclist[iOff]==0x01 ){ iOff++; continue; @@ -248134,7 +256882,7 @@ static Fts5Structure *fts5IndexOptimizeStruct( Fts5Structure *pStruct ){ Fts5Structure *pNew = 0; - sqlite3_int64 nByte = sizeof(Fts5Structure); + sqlite3_int64 nByte = SZ_FTS5STRUCTURE(1); int nSeg = pStruct->nSegment; int i; @@ -248163,7 +256911,8 @@ static Fts5Structure *fts5IndexOptimizeStruct( assert( pStruct->aLevel[i].nMerge<=nThis ); } - nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel); + nByte += (((i64)pStruct->nLevel)+1) * sizeof(Fts5StructureLevel); + assert( nByte==(i64)SZ_FTS5STRUCTURE(pStruct->nLevel+2) ); pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pNew ){ @@ -248246,7 +256995,7 @@ static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){ fts5StructureRelease(pStruct); pStruct = pNew; nMin = 1; - nMerge = nMerge*-1; + nMerge = (nMerge==SMALLEST_INT32 ? LARGEST_INT32 : (nMerge*-1)); } if( pStruct && pStruct->nLevel ){ if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){ @@ -248532,7 +257281,7 @@ static void fts5MergePrefixLists( } if( pHead==0 || pHead->pNext==0 ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_IDX(p); break; } @@ -248569,7 +257318,7 @@ static void fts5MergePrefixLists( assert_nc( tmp.n+nTail<=nTmp ); assert( tmp.n+nTail<=nTmp+nMerge*10 ); if( tmp.n+nTail>nTmp-FTS5_DATA_ZERO_PADDING ){ - if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; + if( p->rc==SQLITE_OK ) FTS5_CORRUPT_IDX(p); break; } fts5BufferSafeAppendVarint(&out, (tmp.n+nTail) * 2); @@ -248604,6 +257353,387 @@ static void fts5MergePrefixLists( *p1 = out; } + +/* +** Iterate through a range of entries in the FTS index, invoking the xVisit +** callback for each of them. +** +** Parameter pToken points to an nToken buffer containing an FTS index term +** (i.e. a document term with the preceding 1 byte index identifier - +** FTS5_MAIN_PREFIX or similar). If bPrefix is true, then the call visits +** all entries for terms that have pToken/nToken as a prefix. If bPrefix +** is false, then only entries with pToken/nToken as the entire key are +** visited. +** +** If the current table is a tokendata=1 table, then if bPrefix is true then +** each index term is treated separately. However, if bPrefix is false, then +** all index terms corresponding to pToken/nToken are collapsed into a single +** term before the callback is invoked. +** +** The callback invoked for each entry visited is specified by paramter xVisit. +** Each time it is invoked, it is passed a pointer to the Fts5Index object, +** a copy of the 7th paramter to this function (pCtx) and a pointer to the +** iterator that indicates the current entry. If the current entry is the +** first with a new term (i.e. different from that of the previous entry, +** including the very first term), then the final two parameters are passed +** a pointer to the term and its size in bytes, respectively. If the current +** entry is not the first associated with its term, these two parameters +** are passed 0. +** +** If parameter pColset is not NULL, then it is used to filter entries before +** the callback is invoked. +*/ +static int fts5VisitEntries( + Fts5Index *p, /* Fts5 index object */ + Fts5Colset *pColset, /* Columns filter to apply, or NULL */ + u8 *pToken, /* Buffer containing token */ + int nToken, /* Size of buffer pToken in bytes */ + int bPrefix, /* True for a prefix scan */ + void (*xVisit)(Fts5Index*, void *pCtx, Fts5Iter *pIter, const u8*, int), + void *pCtx /* Passed as second argument to xVisit() */ +){ + const int flags = (bPrefix ? FTS5INDEX_QUERY_SCAN : 0) + | FTS5INDEX_QUERY_SKIPEMPTY + | FTS5INDEX_QUERY_NOOUTPUT; + Fts5Iter *p1 = 0; /* Iterator used to gather data from index */ + int bNewTerm = 1; + Fts5Structure *pStruct = fts5StructureRead(p); + + fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1); + fts5IterSetOutputCb(&p->rc, p1); + for( /* no-op */ ; + fts5MultiIterEof(p, p1)==0; + fts5MultiIterNext2(p, p1, &bNewTerm) + ){ + Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ]; + int nNew = 0; + const u8 *pNew = 0; + + p1->xSetOutputs(p1, pSeg); + if( p->rc ) break; + + if( bNewTerm ){ + nNew = pSeg->term.n; + pNew = pSeg->term.p; + if( nNewrc; +} + + +/* +** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an +** array of these for each row it visits (so all iRowid fields are the same). +** Or, for an iterator used by an "ORDER BY rank" query, it accumulates an +** array of these for the entire query (in which case iRowid fields may take +** a variety of values). +** +** Each instance in the array indicates the iterator (and therefore term) +** associated with position iPos of rowid iRowid. This is used by the +** xInstToken() API. +** +** iRowid: +** Rowid for the current entry. +** +** iPos: +** Position of current entry within row. In the usual ((iCol<<32)+iOff) +** format (e.g. see macros FTS5_POS2COLUMN() and FTS5_POS2OFFSET()). +** +** iIter: +** If the Fts5TokenDataIter iterator that the entry is part of is +** actually an iterator (i.e. with nIter>0, not just a container for +** Fts5TokenDataMap structures), then this variable is an index into +** the apIter[] array. The corresponding term is that which the iterator +** at apIter[iIter] currently points to. +** +** Or, if the Fts5TokenDataIter iterator is just a container object +** (nIter==0), then iIter is an index into the term.p[] buffer where +** the term is stored. +** +** nByte: +** In the case where iIter is an index into term.p[], this variable +** is the size of the term in bytes. If iIter is an index into apIter[], +** this variable is unused. +*/ +struct Fts5TokenDataMap { + i64 iRowid; /* Row this token is located in */ + i64 iPos; /* Position of token */ + int iIter; /* Iterator token was read from */ + int nByte; /* Length of token in bytes (or 0) */ +}; + +/* +** An object used to supplement Fts5Iter for tokendata=1 iterators. +** +** This object serves two purposes. The first is as a container for an array +** of Fts5TokenDataMap structures, which are used to find the token required +** when the xInstToken() API is used. This is done by the nMapAlloc, nMap and +** aMap[] variables. +*/ +struct Fts5TokenDataIter { + i64 nMapAlloc; /* Allocated size of aMap[] in entries */ + i64 nMap; /* Number of valid entries in aMap[] */ + Fts5TokenDataMap *aMap; /* Array of (rowid+pos -> token) mappings */ + + /* The following are used for prefix-queries only. */ + Fts5Buffer terms; + + /* The following are used for other full-token tokendata queries only. */ + i64 nIter; + i64 nIterAlloc; + Fts5PoslistReader *aPoslistReader; + int *aPoslistToIter; + Fts5Iter *apIter[FLEXARRAY]; +}; + +/* Size in bytes of an Fts5TokenDataIter object holding up to N iterators */ +#define SZ_FTS5TOKENDATAITER(N) \ + (offsetof(Fts5TokenDataIter,apIter) + (N)*sizeof(Fts5Iter)) + +/* +** The two input arrays - a1[] and a2[] - are in sorted order. This function +** merges the two arrays together and writes the result to output array +** aOut[]. aOut[] is guaranteed to be large enough to hold the result. +** +** Duplicate entries are copied into the output. So the size of the output +** array is always (n1+n2) entries. +*/ +static void fts5TokendataMerge( + Fts5TokenDataMap *a1, int n1, /* Input array 1 */ + Fts5TokenDataMap *a2, int n2, /* Input array 2 */ + Fts5TokenDataMap *aOut /* Output array */ +){ + int i1 = 0; + int i2 = 0; + + assert( n1>=0 && n2>=0 ); + while( i1=n2 || (i1rc==SQLITE_OK ){ + if( pT->nMap==pT->nMapAlloc ){ + i64 nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64; + i64 nAlloc = nNew * sizeof(Fts5TokenDataMap); + Fts5TokenDataMap *aNew; + + aNew = (Fts5TokenDataMap*)sqlite3_realloc64(pT->aMap, nAlloc); + if( aNew==0 ){ + p->rc = SQLITE_NOMEM; + return; + } + + pT->aMap = aNew; + pT->nMapAlloc = nNew; + } + + pT->aMap[pT->nMap].iRowid = iRowid; + pT->aMap[pT->nMap].iPos = iPos; + pT->aMap[pT->nMap].iIter = iIter; + pT->aMap[pT->nMap].nByte = nByte; + pT->nMap++; + } +} + +/* +** Sort the contents of the pT->aMap[] array. +** +** The sorting algorithm requires a malloc(). If this fails, an error code +** is left in Fts5Index.rc before returning. +*/ +static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){ + Fts5TokenDataMap *aTmp = 0; + i64 nByte = pT->nMap * sizeof(Fts5TokenDataMap); + + aTmp = (Fts5TokenDataMap*)sqlite3Fts5MallocZero(&p->rc, nByte); + if( aTmp ){ + Fts5TokenDataMap *a1 = pT->aMap; + Fts5TokenDataMap *a2 = aTmp; + i64 nHalf; + + for(nHalf=1; nHalfnMap; nHalf=nHalf*2){ + int i1; + for(i1=0; i1nMap; i1+=(nHalf*2)){ + int n1 = MIN(nHalf, pT->nMap-i1); + int n2 = MIN(nHalf, pT->nMap-i1-n1); + fts5TokendataMerge(&a1[i1], n1, &a1[i1+n1], n2, &a2[i1]); + } + SWAPVAL(Fts5TokenDataMap*, a1, a2); + } + + if( a1!=pT->aMap ){ + memcpy(pT->aMap, a1, pT->nMap*sizeof(Fts5TokenDataMap)); + } + sqlite3_free(aTmp); + +#ifdef SQLITE_DEBUG + { + int ii; + for(ii=1; iinMap; ii++){ + Fts5TokenDataMap *p1 = &pT->aMap[ii-1]; + Fts5TokenDataMap *p2 = &pT->aMap[ii]; + assert( p1->iRowidiRowid + || (p1->iRowid==p2->iRowid && p1->iPos<=p2->iPos) + ); + } + } +#endif + } +} + +/* +** Delete an Fts5TokenDataIter structure and its contents. +*/ +static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){ + if( pSet ){ + int ii; + for(ii=0; iinIter; ii++){ + fts5MultiIterFree(pSet->apIter[ii]); + } + fts5BufferFree(&pSet->terms); + sqlite3_free(pSet->aPoslistReader); + sqlite3_free(pSet->aMap); + sqlite3_free(pSet); + } +} + + +/* +** fts5VisitEntries() context object used by fts5SetupPrefixIterTokendata() +** to pass data to prefixIterSetupTokendataCb(). +*/ +typedef struct TokendataSetupCtx TokendataSetupCtx; +struct TokendataSetupCtx { + Fts5TokenDataIter *pT; /* Object being populated with mappings */ + int iTermOff; /* Offset of current term in terms.p[] */ + int nTermByte; /* Size of current term in bytes */ +}; + +/* +** fts5VisitEntries() callback used by fts5SetupPrefixIterTokendata(). This +** callback adds an entry to the Fts5TokenDataIter.aMap[] array for each +** position in the current position-list. It doesn't matter that some of +** these may be out of order - they will be sorted later. +*/ +static void prefixIterSetupTokendataCb( + Fts5Index *p, + void *pCtx, + Fts5Iter *p1, + const u8 *pNew, + int nNew +){ + TokendataSetupCtx *pSetup = (TokendataSetupCtx*)pCtx; + int iPosOff = 0; + i64 iPos = 0; + + if( pNew ){ + pSetup->nTermByte = nNew-1; + pSetup->iTermOff = pSetup->pT->terms.n; + fts5BufferAppendBlob(&p->rc, &pSetup->pT->terms, nNew-1, pNew+1); + } + + while( 0==sqlite3Fts5PoslistNext64( + p1->base.pData, p1->base.nData, &iPosOff, &iPos + ) ){ + fts5TokendataIterAppendMap(p, + pSetup->pT, pSetup->iTermOff, pSetup->nTermByte, p1->base.iRowid, iPos + ); + } +} + + +/* +** Context object passed by fts5SetupPrefixIter() to fts5VisitEntries(). +*/ +typedef struct PrefixSetupCtx PrefixSetupCtx; +struct PrefixSetupCtx { + void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*); + void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*); + i64 iLastRowid; + int nMerge; + Fts5Buffer *aBuf; + int nBuf; + Fts5Buffer doclist; + TokendataSetupCtx *pTokendata; +}; + +/* +** fts5VisitEntries() callback used by fts5SetupPrefixIter() +*/ +static void prefixIterSetupCb( + Fts5Index *p, + void *pCtx, + Fts5Iter *p1, + const u8 *pNew, + int nNew +){ + PrefixSetupCtx *pSetup = (PrefixSetupCtx*)pCtx; + const int nMerge = pSetup->nMerge; + + if( p1->base.nData>0 ){ + if( p1->base.iRowid<=pSetup->iLastRowid && pSetup->doclist.n>0 ){ + int i; + for(i=0; p->rc==SQLITE_OK && pSetup->doclist.n; i++){ + int i1 = i*nMerge; + int iStore; + assert( i1+nMerge<=pSetup->nBuf ); + for(iStore=i1; iStoreaBuf[iStore].n==0 ){ + fts5BufferSwap(&pSetup->doclist, &pSetup->aBuf[iStore]); + fts5BufferZero(&pSetup->doclist); + break; + } + } + if( iStore==i1+nMerge ){ + pSetup->xMerge(p, &pSetup->doclist, nMerge, &pSetup->aBuf[i1]); + for(iStore=i1; iStoreaBuf[iStore]); + } + } + } + pSetup->iLastRowid = 0; + } + + pSetup->xAppend( + p, (u64)p1->base.iRowid-(u64)pSetup->iLastRowid, p1, &pSetup->doclist + ); + pSetup->iLastRowid = p1->base.iRowid; + } + + if( pSetup->pTokendata ){ + prefixIterSetupTokendataCb(p, (void*)pSetup->pTokendata, p1, pNew, nNew); + } +} + static void fts5SetupPrefixIter( Fts5Index *p, /* Index to read from */ int bDesc, /* True for "ORDER BY rowid DESC" */ @@ -248614,38 +257744,41 @@ static void fts5SetupPrefixIter( Fts5Iter **ppIter /* OUT: New iterator */ ){ Fts5Structure *pStruct; - Fts5Buffer *aBuf; - int nBuf = 32; - int nMerge = 1; + PrefixSetupCtx s; + TokendataSetupCtx s2; + + memset(&s, 0, sizeof(s)); + memset(&s2, 0, sizeof(s2)); + + s.nMerge = 1; + s.iLastRowid = 0; + s.nBuf = 32; + if( iIdx==0 + && p->pConfig->eDetail==FTS5_DETAIL_FULL + && p->pConfig->bPrefixInsttoken + ){ + s.pTokendata = &s2; + s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, SZ_FTS5TOKENDATAITER(1)); + } - void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*); - void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*); if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ - xMerge = fts5MergeRowidLists; - xAppend = fts5AppendRowid; + s.xMerge = fts5MergeRowidLists; + s.xAppend = fts5AppendRowid; }else{ - nMerge = FTS5_MERGE_NLIST-1; - nBuf = nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */ - xMerge = fts5MergePrefixLists; - xAppend = fts5AppendPoslist; + s.nMerge = FTS5_MERGE_NLIST-1; + s.nBuf = s.nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */ + s.xMerge = fts5MergePrefixLists; + s.xAppend = fts5AppendPoslist; } - aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf); + s.aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*s.nBuf); pStruct = fts5StructureRead(p); - assert( p->rc!=SQLITE_OK || (aBuf && pStruct) ); + assert( p->rc!=SQLITE_OK || (s.aBuf && pStruct) ); if( p->rc==SQLITE_OK ){ - const int flags = FTS5INDEX_QUERY_SCAN - | FTS5INDEX_QUERY_SKIPEMPTY - | FTS5INDEX_QUERY_NOOUTPUT; + void *pCtx = (void*)&s; int i; - i64 iLastRowid = 0; - Fts5Iter *p1 = 0; /* Iterator used to gather data from index */ Fts5Data *pData; - Fts5Buffer doclist; - int bNewTerm = 1; - - memset(&doclist, 0, sizeof(doclist)); /* If iIdx is non-zero, then it is the number of a prefix-index for ** prefixes 1 character longer than the prefix being queried for. That @@ -248653,94 +257786,46 @@ static void fts5SetupPrefixIter( ** corresponding to the prefix itself. That one is extracted from the ** main term index here. */ if( iIdx!=0 ){ - int dummy = 0; - const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT; pToken[0] = FTS5_MAIN_PREFIX; - fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1); - fts5IterSetOutputCb(&p->rc, p1); - for(; - fts5MultiIterEof(p, p1)==0; - fts5MultiIterNext2(p, p1, &dummy) - ){ - Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ]; - p1->xSetOutputs(p1, pSeg); - if( p1->base.nData ){ - xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist); - iLastRowid = p1->base.iRowid; - } - } - fts5MultiIterFree(p1); + fts5VisitEntries(p, pColset, pToken, nToken, 0, prefixIterSetupCb, pCtx); } pToken[0] = FTS5_MAIN_PREFIX + iIdx; - fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1); - fts5IterSetOutputCb(&p->rc, p1); - - for( /* no-op */ ; - fts5MultiIterEof(p, p1)==0; - fts5MultiIterNext2(p, p1, &bNewTerm) - ){ - Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ]; - int nTerm = pSeg->term.n; - const u8 *pTerm = pSeg->term.p; - p1->xSetOutputs(p1, pSeg); - - assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 ); - if( bNewTerm ){ - if( nTermbase.nData==0 ) continue; - if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){ - for(i=0; p->rc==SQLITE_OK && doclist.n; i++){ - int i1 = i*nMerge; - int iStore; - assert( i1+nMerge<=nBuf ); - for(iStore=i1; iStorebase.iRowid-(u64)iLastRowid, p1, &doclist); - iLastRowid = p1->base.iRowid; - } - - assert( (nBuf%nMerge)==0 ); - for(i=0; irc==SQLITE_OK ){ - xMerge(p, &doclist, nMerge, &aBuf[i]); + s.xMerge(p, &s.doclist, s.nMerge, &s.aBuf[i]); } - for(iFree=i; iFreerc!=SQLITE_OK ); if( pData ){ pData->p = (u8*)&pData[1]; - pData->nn = pData->szLeaf = doclist.n; - if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n); + pData->nn = pData->szLeaf = s.doclist.n; + if( s.doclist.n ) memcpy(pData->p, s.doclist.p, s.doclist.n); fts5MultiIterNew2(p, pData, bDesc, ppIter); } - fts5BufferFree(&doclist); + + assert( (*ppIter)!=0 || p->rc!=SQLITE_OK ); + if( p->rc==SQLITE_OK && s.pTokendata ){ + fts5TokendataIterSortMap(p, s2.pT); + (*ppIter)->pTokenDataIter = s2.pT; + s2.pT = 0; + } } + fts5TokendataIterDelete(s2.pT); + fts5BufferFree(&s.doclist); fts5StructureRelease(pStruct); - sqlite3_free(aBuf); + sqlite3_free(s.aBuf); } @@ -248778,7 +257863,7 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ static int sqlite3Fts5IndexSync(Fts5Index *p){ assert( p->rc==SQLITE_OK ); fts5IndexFlush(p); - sqlite3Fts5IndexCloseReader(p); + fts5IndexCloseReader(p); return fts5IndexReturn(p); } @@ -248789,11 +257874,10 @@ static int sqlite3Fts5IndexSync(Fts5Index *p){ ** records must be invalidated. */ static int sqlite3Fts5IndexRollback(Fts5Index *p){ - sqlite3Fts5IndexCloseReader(p); + fts5IndexCloseReader(p); fts5IndexDiscardData(p); fts5StructureInvalidate(p); - /* assert( p->rc==SQLITE_OK ); */ - return SQLITE_OK; + return fts5IndexReturn(p); } /* @@ -248802,15 +257886,20 @@ static int sqlite3Fts5IndexRollback(Fts5Index *p){ ** and the initial version of the "averages" record (a zero-byte blob). */ static int sqlite3Fts5IndexReinit(Fts5Index *p){ - Fts5Structure s; + Fts5Structure *pTmp; + union { + Fts5Structure sFts; + u8 tmpSpace[SZ_FTS5STRUCTURE(1)]; + } uFts; fts5StructureInvalidate(p); fts5IndexDiscardData(p); - memset(&s, 0, sizeof(Fts5Structure)); + pTmp = &uFts.sFts; + memset(uFts.tmpSpace, 0, sizeof(uFts.tmpSpace)); if( p->pConfig->bContentlessDelete ){ - s.nOriginCntr = 1; + pTmp->nOriginCntr = 1; } fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); - fts5StructureWrite(p, &s); + fts5StructureWrite(p, pTmp); return fts5IndexReturn(p); } @@ -248994,37 +258083,15 @@ static void fts5SegIterSetEOF(Fts5SegIter *pSeg){ pSeg->pLeaf = 0; } -/* -** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an -** array of these for each row it visits. Or, for an iterator used by an -** "ORDER BY rank" query, it accumulates an array of these for the entire -** query. -** -** Each instance in the array indicates the iterator (and therefore term) -** associated with position iPos of rowid iRowid. This is used by the -** xInstToken() API. -*/ -struct Fts5TokenDataMap { - i64 iRowid; /* Row this token is located in */ - i64 iPos; /* Position of token */ - int iIter; /* Iterator token was read from */ -}; - -/* -** An object used to supplement Fts5Iter for tokendata=1 iterators. -*/ -struct Fts5TokenDataIter { - int nIter; - int nIterAlloc; - - int nMap; - int nMapAlloc; - Fts5TokenDataMap *aMap; - - Fts5PoslistReader *aPoslistReader; - int *aPoslistToIter; - Fts5Iter *apIter[1]; -}; +static void fts5IterClose(Fts5IndexIter *pIndexIter){ + if( pIndexIter ){ + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; + Fts5Index *pIndex = pIter->pIndex; + fts5TokendataIterDelete(pIter->pTokenDataIter); + fts5MultiIterFree(pIter); + fts5IndexCloseReader(pIndex); + } +} /* ** This function appends iterator pAppend to Fts5TokenDataIter pIn and @@ -249039,9 +258106,10 @@ static Fts5TokenDataIter *fts5AppendTokendataIter( if( p->rc==SQLITE_OK ){ if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){ - int nAlloc = pIn ? pIn->nIterAlloc*2 : 16; - int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter); - Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte); + i64 nAlloc = pIn ? pIn->nIterAlloc*2 : 16; + i64 nByte = SZ_FTS5TOKENDATAITER(nAlloc+1); + Fts5TokenDataIter *pNew; + pNew = (Fts5TokenDataIter*)sqlite3_realloc64(pIn, nByte); if( pNew==0 ){ p->rc = SQLITE_NOMEM; @@ -249053,7 +258121,7 @@ static Fts5TokenDataIter *fts5AppendTokendataIter( } } if( p->rc ){ - sqlite3Fts5IterClose((Fts5IndexIter*)pAppend); + fts5IterClose((Fts5IndexIter*)pAppend); }else{ pRet->apIter[pRet->nIter++] = pAppend; } @@ -249062,54 +258130,6 @@ static Fts5TokenDataIter *fts5AppendTokendataIter( return pRet; } -/* -** Delete an Fts5TokenDataIter structure and its contents. -*/ -static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){ - if( pSet ){ - int ii; - for(ii=0; iinIter; ii++){ - fts5MultiIterFree(pSet->apIter[ii]); - } - sqlite3_free(pSet->aPoslistReader); - sqlite3_free(pSet->aMap); - sqlite3_free(pSet); - } -} - -/* -** Append a mapping to the token-map belonging to object pT. -*/ -static void fts5TokendataIterAppendMap( - Fts5Index *p, - Fts5TokenDataIter *pT, - int iIter, - i64 iRowid, - i64 iPos -){ - if( p->rc==SQLITE_OK ){ - if( pT->nMap==pT->nMapAlloc ){ - int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64; - int nByte = nNew * sizeof(Fts5TokenDataMap); - Fts5TokenDataMap *aNew; - - aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nByte); - if( aNew==0 ){ - p->rc = SQLITE_NOMEM; - return; - } - - pT->aMap = aNew; - pT->nMapAlloc = nNew; - } - - pT->aMap[pT->nMap].iRowid = iRowid; - pT->aMap[pT->nMap].iPos = iPos; - pT->aMap[pT->nMap].iIter = iIter; - pT->nMap++; - } -} - /* ** The iterator passed as the only argument must be a tokendata=1 iterator ** (pIter->pTokenDataIter!=0). This function sets the iterator output @@ -249150,7 +258170,7 @@ static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){ pIter->base.iRowid = iRowid; if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){ - fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, iRowid, -1); + fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, 0, iRowid, -1); }else if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){ int nReader = 0; @@ -249186,8 +258206,8 @@ static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){ /* Ensure the token-mapping is large enough */ if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){ - int nNew = (pT->nMapAlloc + nByte) * 2; - Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc( + i64 nNew = (pT->nMapAlloc + nByte) * 2; + Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc64( pT->aMap, nNew*sizeof(Fts5TokenDataMap) ); if( aNew==0 ){ @@ -249314,7 +258334,7 @@ static Fts5Iter *fts5SetupTokendataIter( fts5BufferSet(&p->rc, &bSeek, nToken, pToken); } if( p->rc ){ - sqlite3Fts5IterClose((Fts5IndexIter*)pNew); + fts5IterClose((Fts5IndexIter*)pNew); break; } @@ -249379,7 +258399,7 @@ static Fts5Iter *fts5SetupTokendataIter( ** not point to any terms that match the query. So delete it and break ** out of the loop - all required iterators have been collected. */ if( pSmall==0 ){ - sqlite3Fts5IterClose((Fts5IndexIter*)pNew); + fts5IterClose((Fts5IndexIter*)pNew); break; } @@ -249403,6 +258423,7 @@ static Fts5Iter *fts5SetupTokendataIter( pRet = fts5MultiIterAlloc(p, 0); } if( pRet ){ + pRet->nSeg = 0; pRet->pTokenDataIter = pSet; if( pSet ){ fts5IterSetOutputsTokendata(pRet); @@ -249418,7 +258439,6 @@ static Fts5Iter *fts5SetupTokendataIter( return pRet; } - /* ** Open a new iterator to iterate though all rowid that match the ** specified token or token prefix. @@ -249441,8 +258461,14 @@ static int sqlite3Fts5IndexQuery( int iIdx = 0; /* Index to search */ int iPrefixIdx = 0; /* +1 prefix index */ int bTokendata = pConfig->bTokendata; + assert( buf.p!=0 ); if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken); + /* The NOTOKENDATA flag is set when each token in a tokendata=1 table + ** should be treated individually, instead of merging all those with + ** a common prefix into a single entry. This is used, for example, by + ** queries performed as part of an integrity-check, or by the fts5vocab + ** module. */ if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){ bTokendata = 0; } @@ -249473,7 +258499,7 @@ static int sqlite3Fts5IndexQuery( } if( bTokendata && iIdx==0 ){ - buf.p[0] = '0'; + buf.p[0] = FTS5_MAIN_PREFIX; pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset); }else if( iIdx<=pConfig->nPrefix ){ /* Straight index lookup */ @@ -249486,7 +258512,7 @@ static int sqlite3Fts5IndexQuery( fts5StructureRelease(pStruct); } }else{ - /* Scan multiple terms in the main index */ + /* Scan multiple terms in the main index for a prefix query. */ int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0; fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet); if( pRet==0 ){ @@ -249502,9 +258528,9 @@ static int sqlite3Fts5IndexQuery( } if( p->rc ){ - sqlite3Fts5IterClose((Fts5IndexIter*)pRet); + fts5IterClose((Fts5IndexIter*)pRet); pRet = 0; - sqlite3Fts5IndexCloseReader(p); + fts5IndexCloseReader(p); } *ppIter = (Fts5IndexIter*)pRet; @@ -249522,7 +258548,8 @@ static int sqlite3Fts5IndexQuery( static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; assert( pIter->pIndex->rc==SQLITE_OK ); - if( pIter->pTokenDataIter ){ + if( pIter->nSeg==0 ){ + assert( pIter->pTokenDataIter ); fts5TokendataIterNext(pIter, 0, 0); }else{ fts5MultiIterNext(pIter->pIndex, pIter, 0, 0); @@ -249559,7 +258586,8 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){ */ static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; - if( pIter->pTokenDataIter ){ + if( pIter->nSeg==0 ){ + assert( pIter->pTokenDataIter ); fts5TokendataIterNext(pIter, 1, iMatch); }else{ fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch); @@ -249578,14 +258606,62 @@ static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){ return (z ? &z[1] : 0); } +/* +** pIter is a prefix query. This function populates pIter->pTokenDataIter +** with an Fts5TokenDataIter object containing mappings for all rows +** matched by the query. +*/ +static int fts5SetupPrefixIterTokendata( + Fts5Iter *pIter, + const char *pToken, /* Token prefix to search for */ + int nToken /* Size of pToken in bytes */ +){ + Fts5Index *p = pIter->pIndex; + Fts5Buffer token = {0, 0, 0}; + TokendataSetupCtx ctx; + + memset(&ctx, 0, sizeof(ctx)); + + fts5BufferGrow(&p->rc, &token, nToken+1); + assert( token.p!=0 || p->rc!=SQLITE_OK ); + ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, + SZ_FTS5TOKENDATAITER(1)); + + if( p->rc==SQLITE_OK ){ + + /* Fill in the token prefix to search for */ + token.p[0] = FTS5_MAIN_PREFIX; + memcpy(&token.p[1], pToken, nToken); + token.n = nToken+1; + + fts5VisitEntries( + p, 0, token.p, token.n, 1, prefixIterSetupTokendataCb, (void*)&ctx + ); + + fts5TokendataIterSortMap(p, ctx.pT); + } + + if( p->rc==SQLITE_OK ){ + pIter->pTokenDataIter = ctx.pT; + }else{ + fts5TokendataIterDelete(ctx.pT); + } + fts5BufferFree(&token); + + return fts5IndexReturn(p); +} + /* ** This is used by xInstToken() to access the token at offset iOff, column ** iCol of row iRowid. The token is returned via output variables *ppOut ** and *pnOut. The iterator passed as the first argument must be a tokendata=1 ** iterator (pIter->pTokenDataIter!=0). +** +** pToken/nToken: */ static int sqlite3Fts5IterToken( Fts5IndexIter *pIndexIter, + const char *pToken, int nToken, i64 iRowid, int iCol, int iOff, @@ -249593,13 +258669,22 @@ static int sqlite3Fts5IterToken( ){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; Fts5TokenDataIter *pT = pIter->pTokenDataIter; - Fts5TokenDataMap *aMap = pT->aMap; i64 iPos = (((i64)iCol)<<32) + iOff; - + Fts5TokenDataMap *aMap = 0; int i1 = 0; - int i2 = pT->nMap; + int i2 = 0; int iTest = 0; + assert( pT || (pToken && pIter->nSeg>0) ); + if( pT==0 ){ + int rc = fts5SetupPrefixIterTokendata(pIter, pToken, nToken); + if( rc!=SQLITE_OK ) return rc; + pT = pIter->pTokenDataIter; + } + + i2 = pT->nMap; + aMap = pT->aMap; + while( i2>i1 ){ iTest = (i1 + i2) / 2; @@ -249622,9 +258707,15 @@ static int sqlite3Fts5IterToken( } if( i2>i1 ){ - Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter]; - *ppOut = (const char*)pMap->aSeg[0].term.p+1; - *pnOut = pMap->aSeg[0].term.n-1; + if( pIter->nSeg==0 ){ + Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter]; + *ppOut = (const char*)pMap->aSeg[0].term.p+1; + *pnOut = pMap->aSeg[0].term.n-1; + }else{ + Fts5TokenDataMap *p = &aMap[iTest]; + *ppOut = (const char*)&pT->terms.p[p->iIter]; + *pnOut = aMap[iTest].nByte; + } } return SQLITE_OK; @@ -249636,7 +258727,9 @@ static int sqlite3Fts5IterToken( */ static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; - if( pIter && pIter->pTokenDataIter ){ + if( pIter && pIter->pTokenDataIter + && (pIter->nSeg==0 || pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_FULL) + ){ pIter->pTokenDataIter->nMap = 0; } } @@ -249656,17 +258749,30 @@ static int sqlite3Fts5IndexIterWriteTokendata( Fts5Iter *pIter = (Fts5Iter*)pIndexIter; Fts5TokenDataIter *pT = pIter->pTokenDataIter; Fts5Index *p = pIter->pIndex; - int ii; + i64 iPos = (((i64)iCol)<<32) + iOff; assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL ); - assert( pIter->pTokenDataIter ); - - for(ii=0; iinIter; ii++){ - Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term; - if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break; - } - if( iinIter ){ - fts5TokendataIterAppendMap(p, pT, ii, iRowid, (((i64)iCol)<<32) + iOff); + assert( pIter->pTokenDataIter || pIter->nSeg>0 ); + if( pIter->nSeg>0 ){ + /* This is a prefix term iterator. */ + if( pT==0 ){ + pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, + SZ_FTS5TOKENDATAITER(1)); + pIter->pTokenDataIter = pT; + } + if( pT ){ + fts5TokendataIterAppendMap(p, pT, pT->terms.n, nToken, iRowid, iPos); + fts5BufferAppendBlob(&p->rc, &pT->terms, nToken, (const u8*)pToken); + } + }else{ + int ii; + for(ii=0; iinIter; ii++){ + Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term; + if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break; + } + if( iinIter ){ + fts5TokendataIterAppendMap(p, pT, ii, 0, iRowid, iPos); + } } return fts5IndexReturn(p); } @@ -249676,11 +258782,9 @@ static int sqlite3Fts5IndexIterWriteTokendata( */ static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){ if( pIndexIter ){ - Fts5Iter *pIter = (Fts5Iter*)pIndexIter; - Fts5Index *pIndex = pIter->pIndex; - fts5TokendataIterDelete(pIter->pTokenDataIter); - fts5MultiIterFree(pIter); - sqlite3Fts5IndexCloseReader(pIndex); + Fts5Index *pIndex = ((Fts5Iter*)pIndexIter)->pIndex; + fts5IterClose(pIndexIter); + fts5IndexReturn(pIndex); } } @@ -249934,8 +259038,8 @@ static void fts5IndexTombstoneRebuild( ){ const int MINSLOT = 32; int nSlotPerPage = MAX(MINSLOT, (p->pConfig->pgsz - 8) / szKey); - int nSlot = 0; /* Number of slots in each output page */ - int nOut = 0; + i64 nSlot = 0; /* Number of slots in each output page */ + i64 nOut = 0; /* Figure out how many output pages (nOut) and how many slots per ** page (nSlot). There are three possibilities: @@ -249960,23 +259064,26 @@ static void fts5IndexTombstoneRebuild( nSlot = MINSLOT; }else if( pSeg->nPgTombstone==1 ){ /* Case 2. */ - int nElem = (int)fts5GetU32(&pData1->p[4]); + u32 nElem = fts5GetU32(&pData1->p[4]); assert( pData1 && iPg1==0 ); - nOut = 1; - nSlot = MAX(nElem*4, MINSLOT); - if( nSlot>nSlotPerPage ) nOut = 0; + if( nElem>((u32)nSlotPerPage/4) ){ + nOut = 0; + }else{ + nOut = 1; + nSlot = MAX((i64)nElem*4, MINSLOT); + } } if( nOut==0 ){ /* Case 3. */ - nOut = (pSeg->nPgTombstone * 2 + 1); + nOut = ((i64)pSeg->nPgTombstone * 2 + 1); nSlot = nSlotPerPage; } /* Allocate the required array and output pages */ while( 1 ){ int res = 0; - int ii = 0; - int szPage = 0; + i64 ii = 0; + i64 szPage = 0; Fts5Data **apOut = 0; /* Allocate space for the new hash table */ @@ -250210,7 +259317,7 @@ static int fts5QueryCksum( rc = sqlite3Fts5IterNext(pIter); } } - sqlite3Fts5IterClose(pIter); + fts5IterClose(pIter); *pCksum = cksum; return rc; @@ -250251,19 +259358,27 @@ static int fts5TestUtf8(const char *z, int n){ /* ** This function is also purely an internal test. It does not contribute to ** FTS functionality, or even the integrity-check, in any way. +** +** This function sets output variable (*pbFail) to true if the test fails. Or +** leaves it unchanged if the test succeeds. */ static void fts5TestTerm( Fts5Index *p, Fts5Buffer *pPrev, /* Previous term */ const char *z, int n, /* Possibly new term to test */ u64 expected, - u64 *pCksum + u64 *pCksum, + int *pbFail ){ int rc = p->rc; if( pPrev->n==0 ){ fts5BufferSet(&rc, pPrev, n, (const u8*)z); }else - if( rc==SQLITE_OK && (pPrev->n!=n || memcmp(pPrev->p, z, n)) ){ + if( *pbFail==0 + && rc==SQLITE_OK + && (pPrev->n!=n || memcmp(pPrev->p, z, n)) + && (p->pHash==0 || p->pHash->nEntry==0) + ){ u64 cksum3 = *pCksum; const char *zTerm = (const char*)&pPrev->p[1]; /* term sans prefix-byte */ int nTerm = pPrev->n-1; /* Size of zTerm in bytes */ @@ -250313,7 +259428,7 @@ static void fts5TestTerm( fts5BufferSet(&rc, pPrev, n, (const u8*)z); if( rc==SQLITE_OK && cksum3!=expected ){ - rc = FTS5_CORRUPT; + *pbFail = 1; } *pCksum = cksum3; } @@ -250322,7 +259437,7 @@ static void fts5TestTerm( #else # define fts5TestDlidxReverse(x,y,z) -# define fts5TestTerm(u,v,w,x,y,z) +# define fts5TestTerm(t,u,v,w,x,y,z) #endif /* @@ -250345,16 +259460,19 @@ static void fts5IndexIntegrityCheckEmpty( /* Now check that the iter.nEmpty leaves following the current leaf ** (a) exist and (b) contain no terms. */ for(i=iFirst; p->rc==SQLITE_OK && i<=iLast; i++){ - Fts5Data *pLeaf = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i)); + Fts5Data *pLeaf = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i)); if( pLeaf ){ - if( !fts5LeafIsTermless(pLeaf) ) p->rc = FTS5_CORRUPT; - if( i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf) ) p->rc = FTS5_CORRUPT; + if( !fts5LeafIsTermless(pLeaf) + || (i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf)) + ){ + FTS5_CORRUPT_ROWID(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i)); + } } fts5DataRelease(pLeaf); } } -static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){ +static void fts5IntegrityCheckPgidx(Fts5Index *p, i64 iRowid, Fts5Data *pLeaf){ i64 iTermOff = 0; int ii; @@ -250372,12 +259490,12 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){ iOff = iTermOff; if( iOff>=pLeaf->szLeaf ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ROWID(p, iRowid); }else if( iTermOff==nIncr ){ int nByte; iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte); if( (iOff+nByte)>pLeaf->szLeaf ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ROWID(p, iRowid); }else{ fts5BufferSet(&p->rc, &buf1, nByte, &pLeaf->p[iOff]); } @@ -250386,7 +259504,7 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){ iOff += fts5GetVarint32(&pLeaf->p[iOff], nKeep); iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte); if( nKeep>buf1.n || (iOff+nByte)>pLeaf->szLeaf ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ROWID(p, iRowid); }else{ buf1.n = nKeep; fts5BufferAppendBlob(&p->rc, &buf1, nByte, &pLeaf->p[iOff]); @@ -250394,7 +259512,7 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){ if( p->rc==SQLITE_OK ){ res = fts5BufferCompare(&buf1, &buf2); - if( res<=0 ) p->rc = FTS5_CORRUPT; + if( res<=0 ) FTS5_CORRUPT_ROWID(p, iRowid); } } fts5BufferSet(&p->rc, &buf2, buf1.n, buf1.p); @@ -250455,7 +259573,7 @@ static void fts5IndexIntegrityCheckSegment( ** entry even if all the terms are removed from it by secure-delete ** operations. */ }else{ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ROWID(p, iRow); } }else{ @@ -250467,15 +259585,19 @@ static void fts5IndexIntegrityCheckSegment( iOff = fts5LeafFirstTermOff(pLeaf); iRowidOff = fts5LeafFirstRowidOff(pLeaf); if( iRowidOff>=iOff || iOff>=pLeaf->szLeaf ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ROWID(p, iRow); }else{ iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm); - res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); - if( res==0 ) res = nTerm - nIdxTerm; - if( res<0 ) p->rc = FTS5_CORRUPT; + if( (i64)iOff+(i64)nTerm>(i64)pLeaf->szLeaf ){ + FTS5_CORRUPT_ROWID(p, iRow); + }else{ + res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); + if( res==0 ) res = nTerm - nIdxTerm; + if( res<0 ) FTS5_CORRUPT_ROWID(p, iRow); + } } - fts5IntegrityCheckPgidx(p, pLeaf); + fts5IntegrityCheckPgidx(p, iRow, pLeaf); } fts5DataRelease(pLeaf); if( p->rc ) break; @@ -250503,9 +259625,9 @@ static void fts5IndexIntegrityCheckSegment( /* Check any rowid-less pages that occur before the current leaf. */ for(iPg=iPrevLeaf+1; iPgrc = FTS5_CORRUPT; + if( fts5LeafFirstRowidOff(pLeaf)!=0 ) FTS5_CORRUPT_ROWID(p, iKey); fts5DataRelease(pLeaf); } } @@ -250514,18 +259636,18 @@ static void fts5IndexIntegrityCheckSegment( /* Check that the leaf page indicated by the iterator really does ** contain the rowid suggested by the same. */ iKey = FTS5_SEGMENT_ROWID(iSegid, iPrevLeaf); - pLeaf = fts5DataRead(p, iKey); + pLeaf = fts5LeafRead(p, iKey); if( pLeaf ){ i64 iRowid; int iRowidOff = fts5LeafFirstRowidOff(pLeaf); ASSERT_SZLEAF_OK(pLeaf); if( iRowidOff>=pLeaf->szLeaf ){ - p->rc = FTS5_CORRUPT; + FTS5_CORRUPT_ROWID(p, iKey); }else if( bSecureDelete==0 || iRowidOff>0 ){ i64 iDlRowid = fts5DlidxIterRowid(pDlidx); fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid); if( iRowidrc = FTS5_CORRUPT; + FTS5_CORRUPT_ROWID(p, iKey); } } fts5DataRelease(pLeaf); @@ -250577,6 +259699,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum /* Used by extra internal tests only run if NDEBUG is not defined */ u64 cksum3 = 0; /* Checksum based on contents of indexes */ Fts5Buffer term = {0,0,0}; /* Buffer used to hold most recent term */ + int bTestFail = 0; #endif const int flags = FTS5INDEX_QUERY_NOOUTPUT; @@ -250619,7 +259742,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum char *z = (char*)fts5MultiIterTerm(pIter, &n); /* If this is a new term, query for it. Update cksum3 with the results. */ - fts5TestTerm(p, &term, z, n, cksum2, &cksum3); + fts5TestTerm(p, &term, z, n, cksum2, &cksum3, &bTestFail); if( p->rc ) break; if( eDetail==FTS5_DETAIL_NONE ){ @@ -250637,15 +259760,26 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum } } } - fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3); + fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3, &bTestFail); fts5MultiIterFree(pIter); - if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ) p->rc = FTS5_CORRUPT; - - fts5StructureRelease(pStruct); + if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ){ + p->rc = FTS5_CORRUPT; + sqlite3Fts5ConfigErrmsg(p->pConfig, + "fts5: checksum mismatch for table \"%s\"", p->pConfig->zName + ); + } #ifdef SQLITE_DEBUG + /* In SQLITE_DEBUG builds, expensive extra checks were run as part of + ** the integrity-check above. If no other errors were detected, but one + ** of these tests failed, set the result to SQLITE_CORRUPT_VTAB here. */ + if( p->rc==SQLITE_OK && bTestFail ){ + p->rc = FTS5_CORRUPT; + } fts5BufferFree(&term); #endif + + fts5StructureRelease(pStruct); fts5BufferFree(&poslist); return fts5IndexReturn(p); } @@ -250687,7 +259821,7 @@ static void fts5DecodeRowid( #if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ - int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid compenents */ + int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid components */ fts5DecodeRowid(iKey, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno); if( iSegid==0 ){ @@ -250933,7 +260067,7 @@ static void fts5DecodeFunction( ** buffer overreads even if the record is corrupt. */ n = sqlite3_value_bytes(apVal[1]); aBlob = sqlite3_value_blob(apVal[1]); - nSpace = n + FTS5_DATA_ZERO_PADDING; + nSpace = ((i64)n) + FTS5_DATA_ZERO_PADDING; a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace); if( a==0 ) goto decode_out; if( n>0 ) memcpy(a, aBlob, n); @@ -251571,6 +260705,7 @@ struct Fts5Global { #define FTS5_LOCALE_HDR_SIZE ((int)sizeof( ((Fts5Global*)0)->aLocaleHdr )) #define FTS5_LOCALE_HDR(pConfig) ((const u8*)(pConfig->pGlobal->aLocaleHdr)) +#define FTS5_INSTTOKEN_SUBTYPE 73 /* ** Each auxiliary function registered with the FTS5 module is represented @@ -251647,9 +260782,11 @@ struct Fts5Sorter { i64 iRowid; /* Current rowid */ const u8 *aPoslist; /* Position lists for current row */ int nIdx; /* Number of entries in aIdx[] */ - int aIdx[1]; /* Offsets into aPoslist for current row */ + int aIdx[FLEXARRAY]; /* Offsets into aPoslist for current row */ }; +/* Size (int bytes) of an Fts5Sorter object with N indexes */ +#define SZ_FTS5SORTER(N) (offsetof(Fts5Sorter,nIdx)+((N+2)/2)*sizeof(i64)) /* ** Virtual-table cursor object. @@ -251986,6 +261123,17 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){ #endif } +static void fts5SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ +#if SQLITE_VERSION_NUMBER>=3008002 +#ifndef SQLITE_CORE + if( sqlite3_libversion_number()>=3008002 ) +#endif + { + pIdxInfo->estimatedRows = MAX(1, nRow); + } +#endif +} + static int fts5UsePatternMatch( Fts5Config *pConfig, struct sqlite3_index_constraint *p @@ -252050,19 +261198,30 @@ static int fts5UsePatternMatch( ** a) If a MATCH operator is present, the cost depends on the other ** constraints also present. As follows: ** -** * No other constraints: cost=1000.0 -** * One rowid range constraint: cost=750.0 -** * Both rowid range constraints: cost=500.0 -** * An == rowid constraint: cost=100.0 +** * No other constraints: cost=50000.0 +** * One rowid range constraint: cost=37500.0 +** * Both rowid range constraints: cost=30000.0 +** * An == rowid constraint: cost=25000.0 ** ** b) Otherwise, if there is no MATCH: ** -** * No other constraints: cost=1000000.0 -** * One rowid range constraint: cost=750000.0 -** * Both rowid range constraints: cost=250000.0 -** * An == rowid constraint: cost=10.0 +** * No other constraints: cost=3000000.0 +** * One rowid range constraints: cost=2250000.0 +** * Both rowid range constraint: cost=750000.0 +** * An == rowid constraint: cost=25.0 ** ** Costs are not modified by the ORDER BY clause. +** +** The ratios used in case (a) are based on informal results obtained from +** the tool/fts5cost.tcl script. The "MATCH and ==" combination has the +** cost set quite high because the query may be a prefix query. Unless +** there is a prefix index, prefix queries with rowid constraints are much +** more expensive than non-prefix queries with rowid constraints. +** +** The estimated rows returned is set to the cost/40. For simple queries, +** experimental results show that cost/4 might be about right. But for +** more complex queries that use multiple terms the number of rows might +** be far fewer than this. So we compromise and use cost/40. */ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ Fts5Table *pTab = (Fts5Table*)pVTab; @@ -252095,7 +261254,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ return SQLITE_ERROR; } - idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1); + idxStr = (char*)sqlite3_malloc64((i64)pInfo->nConstraint * 8 + 1); if( idxStr==0 ) return SQLITE_NOMEM; pInfo->idxStr = idxStr; pInfo->needToFreeIdxStr = 1; @@ -252110,6 +261269,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ if( p->usable==0 || iCol<0 ){ /* As there exists an unusable MATCH constraint this is an ** unusable plan. Return SQLITE_CONSTRAINT. */ + idxStr[iIdxStr] = 0; return SQLITE_CONSTRAINT; }else{ if( iCol==nCol+1 ){ @@ -252120,7 +261280,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ nSeenMatch++; idxStr[iIdxStr++] = 'M'; sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol); - idxStr += strlen(&idxStr[iIdxStr]); + iIdxStr += (int)strlen(&idxStr[iIdxStr]); assert( idxStr[iIdxStr]=='\0' ); } pInfo->aConstraintUsage[i].argvIndex = ++iCons; @@ -252139,6 +261299,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ idxStr[iIdxStr++] = '='; bSeenEq = 1; pInfo->aConstraintUsage[i].argvIndex = ++iCons; + pInfo->aConstraintUsage[i].omit = 1; } } } @@ -252186,17 +261347,35 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ /* Calculate the estimated cost based on the flags set in idxFlags. */ if( bSeenEq ){ - pInfo->estimatedCost = nSeenMatch ? 1000.0 : 10.0; - if( nSeenMatch==0 ) fts5SetUniqueFlag(pInfo); - }else if( bSeenLt && bSeenGt ){ - pInfo->estimatedCost = nSeenMatch ? 5000.0 : 250000.0; - }else if( bSeenLt || bSeenGt ){ - pInfo->estimatedCost = nSeenMatch ? 7500.0 : 750000.0; - }else{ - pInfo->estimatedCost = nSeenMatch ? 10000.0 : 1000000.0; - } - for(i=1; iestimatedCost *= 0.4; + pInfo->estimatedCost = nSeenMatch ? 25000.0 : 25.0; + fts5SetEstimatedRows(pInfo, 1); + fts5SetUniqueFlag(pInfo); + }else{ + i64 nEstRows; + if( nSeenMatch ){ + if( bSeenLt && bSeenGt ){ + pInfo->estimatedCost = 50000.0; + }else if( bSeenLt || bSeenGt ){ + pInfo->estimatedCost = 37500.0; + }else{ + pInfo->estimatedCost = 50000.0; + } + nEstRows = (i64)(pInfo->estimatedCost / 40.0); + for(i=1; iestimatedCost *= 2.5; + nEstRows = nEstRows / 2; + } + }else{ + if( bSeenLt && bSeenGt ){ + pInfo->estimatedCost = 750000.0; + }else if( bSeenLt || bSeenGt ){ + pInfo->estimatedCost = 2250000.0; + }else{ + pInfo->estimatedCost = 3000000.0; + } + nEstRows = (i64)(pInfo->estimatedCost / 4.0); + } + fts5SetEstimatedRows(pInfo, nEstRows); } pInfo->idxNum = idxFlags; @@ -252395,7 +261574,9 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ int bDesc = pCsr->bDesc; i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr); - rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->p.pIndex, iRowid, bDesc); + rc = sqlite3Fts5ExprFirst( + pCsr->pExpr, pTab->p.pIndex, iRowid, pCsr->iLastRowid, bDesc + ); if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){ *pbSkip = 1; } @@ -252526,7 +261707,7 @@ static int fts5CursorFirstSorted( const char *zRankArgs = pCsr->zRankArgs; nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); - nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); + nByte = SZ_FTS5SORTER(nPhrase); pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte); if( pSorter==0 ) return SQLITE_NOMEM; memset(pSorter, 0, (size_t)nByte); @@ -252567,7 +261748,9 @@ static int fts5CursorFirstSorted( static int fts5CursorFirst(Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc){ int rc; Fts5Expr *pExpr = pCsr->pExpr; - rc = sqlite3Fts5ExprFirst(pExpr, pTab->p.pIndex, pCsr->iFirstRowid, bDesc); + rc = sqlite3Fts5ExprFirst( + pExpr, pTab->p.pIndex, pCsr->iFirstRowid, pCsr->iLastRowid, bDesc + ); if( sqlite3Fts5ExprEof(pExpr) ){ CsrFlagSet(pCsr, FTS5CSR_EOF); } @@ -252895,6 +262078,7 @@ static int fts5FilterMethod( sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */ int iCol; /* Column on LHS of MATCH operator */ char **pzErrmsg = pConfig->pzErrmsg; + int bPrefixInsttoken = pConfig->bPrefixInsttoken; int i; int iIdxStr = 0; Fts5Expr *pExpr = 0; @@ -252930,6 +262114,9 @@ static int fts5FilterMethod( rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset); if( rc!=SQLITE_OK ) goto filter_out; if( zText==0 ) zText = ""; + if( sqlite3_value_subtype(apVal[i])==FTS5_INSTTOKEN_SUBTYPE ){ + pConfig->bPrefixInsttoken = 1; + } iCol = 0; do{ @@ -253070,6 +262257,7 @@ static int fts5FilterMethod( filter_out: sqlite3Fts5ExprFree(pExpr); pConfig->pzErrmsg = pzErrmsg; + pConfig->bPrefixInsttoken = bPrefixInsttoken; return rc; } @@ -253372,7 +262560,6 @@ static int fts5UpdateMethod( Fts5Config *pConfig = pTab->p.pConfig; int eType0; /* value_type() of apVal[0] */ int rc = SQLITE_OK; /* Return code */ - int bUpdateOrDelete = 0; /* A transaction must be open when this is called. */ assert( pTab->ts.eState==1 || pTab->ts.eState==2 ); @@ -253384,7 +262571,7 @@ static int fts5UpdateMethod( ); assert( pTab->p.pConfig->pzErrmsg==0 ); if( pConfig->pgsz==0 ){ - rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); + rc = sqlite3Fts5ConfigLoad(pTab->p.pConfig, pTab->p.pConfig->iCookie); if( rc!=SQLITE_OK ) return rc; } @@ -253409,7 +262596,6 @@ static int fts5UpdateMethod( rc = SQLITE_ERROR; }else{ rc = fts5SpecialDelete(pTab, apVal); - bUpdateOrDelete = 1; } }else{ rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]); @@ -253446,7 +262632,6 @@ static int fts5UpdateMethod( }else{ i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0); - bUpdateOrDelete = 1; } } @@ -253474,7 +262659,6 @@ static int fts5UpdateMethod( if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){ i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0); - bUpdateOrDelete = 1; } fts5StorageInsert(&rc, pTab, apVal, pRowid); } @@ -253528,27 +262712,13 @@ static int fts5UpdateMethod( rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1); fts5StorageInsert(&rc, pTab, apVal, pRowid); } - bUpdateOrDelete = 1; sqlite3Fts5StorageReleaseDeleteRow(pStorage); } - - } - } - - if( rc==SQLITE_OK - && bUpdateOrDelete - && pConfig->bSecureDelete - && pConfig->iVersion==FTS5_CURRENT_VERSION - ){ - rc = sqlite3Fts5StorageConfigValue( - pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE - ); - if( rc==SQLITE_OK ){ - pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE; } } update_out: + sqlite3Fts5IndexCloseReader(pTab->p.pIndex); pTab->p.pConfig->pzErrmsg = 0; return rc; } @@ -253597,6 +262767,7 @@ static int fts5RollbackMethod(sqlite3_vtab *pVtab){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0); rc = sqlite3Fts5StorageRollback(pTab->pStorage); + pTab->p.pConfig->pgsz = 0; return rc; } @@ -254145,19 +263316,23 @@ static int fts5ApiPhraseFirstColumn( if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ Fts5Sorter *pSorter = pCsr->pSorter; - int n; - if( pSorter ){ - int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); - n = pSorter->aIdx[iPhrase] - i1; - pIter->a = &pSorter->aPoslist[i1]; + if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){ + rc = SQLITE_RANGE; }else{ - rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); - } - if( rc==SQLITE_OK ){ - assert( pIter->a || n==0 ); - pIter->b = (pIter->a ? &pIter->a[n] : 0); - *piCol = 0; - fts5ApiPhraseNextColumn(pCtx, pIter, piCol); + int n; + if( pSorter ){ + int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); + n = pSorter->aIdx[iPhrase] - i1; + pIter->a = &pSorter->aPoslist[i1]; + }else{ + rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); + } + if( rc==SQLITE_OK ){ + assert( pIter->a || n==0 ); + pIter->b = (pIter->a ? &pIter->a[n] : 0); + *piCol = 0; + fts5ApiPhraseNextColumn(pCtx, pIter, piCol); + } } }else{ int n; @@ -255065,7 +264240,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2024-10-21 16:30:22 03a9703e27c44437c39363d0baf82db4ebc94538a0f28411c85dda156f82636e", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc", -1, SQLITE_TRANSIENT); } /* @@ -255088,9 +264263,9 @@ static void fts5LocaleFunc( sqlite3_value **apArg /* Function arguments */ ){ const char *zLocale = 0; - int nLocale = 0; + i64 nLocale = 0; const char *zText = 0; - int nText = 0; + i64 nText = 0; assert( nArg==2 ); UNUSED_PARAM(nArg); @@ -255107,10 +264282,10 @@ static void fts5LocaleFunc( Fts5Global *p = (Fts5Global*)sqlite3_user_data(pCtx); u8 *pBlob = 0; u8 *pCsr = 0; - int nBlob = 0; + i64 nBlob = 0; nBlob = FTS5_LOCALE_HDR_SIZE + nLocale + 1 + nText; - pBlob = (u8*)sqlite3_malloc(nBlob); + pBlob = (u8*)sqlite3_malloc64(nBlob); if( pBlob==0 ){ sqlite3_result_error_nomem(pCtx); return; @@ -255129,6 +264304,20 @@ static void fts5LocaleFunc( } } +/* +** Implementation of fts5_insttoken() function. +*/ +static void fts5InsttokenFunc( + sqlite3_context *pCtx, /* Function call context */ + int nArg, /* Number of args */ + sqlite3_value **apArg /* Function arguments */ +){ + assert( nArg==1 ); + (void)nArg; + sqlite3_result_value(pCtx, apArg[0]); + sqlite3_result_subtype(pCtx, FTS5_INSTTOKEN_SUBTYPE); +} + /* ** Return true if zName is the extension on one of the shadow tables used ** by this module. @@ -255174,8 +264363,9 @@ static int fts5IntegrityMethod( " FTS5 table %s.%s: %s", zSchema, zTabname, sqlite3_errstr(rc)); } + }else if( (rc&0xff)==SQLITE_CORRUPT ){ + rc = SQLITE_OK; } - sqlite3Fts5IndexCloseReader(pTab->p.pIndex); pTab->p.pConfig->pzErrmsg = 0; @@ -255214,7 +264404,7 @@ static int fts5Init(sqlite3 *db){ int rc; Fts5Global *pGlobal = 0; - pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global)); + pGlobal = (Fts5Global*)sqlite3_malloc64(sizeof(Fts5Global)); if( pGlobal==0 ){ rc = SQLITE_NOMEM; }else{ @@ -255258,10 +264448,17 @@ static int fts5Init(sqlite3 *db){ if( rc==SQLITE_OK ){ rc = sqlite3_create_function( db, "fts5_locale", 2, - SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE, + SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE|SQLITE_SUBTYPE, p, fts5LocaleFunc, 0, 0 ); } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function( + db, "fts5_insttoken", 1, + SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE, + p, fts5InsttokenFunc, 0, 0 + ); + } } /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file @@ -255269,8 +264466,8 @@ static int fts5Init(sqlite3 *db){ ** its entry point to enable the matchinfo() demo. */ #ifdef SQLITE_FTS5_ENABLE_TEST_MI if( rc==SQLITE_OK ){ - extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*); - rc = sqlite3Fts5TestRegisterMatchinfo(db); + extern int sqlite3Fts5TestRegisterMatchinfoAPI(fts5_api*); + rc = sqlite3Fts5TestRegisterMatchinfoAPI(&pGlobal->api); } #endif @@ -255525,6 +264722,11 @@ static int fts5StorageGetStmt( if( rc!=SQLITE_OK && pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); } + if( rc==SQLITE_ERROR && eStmt>FTS5_STMT_LOOKUP2 && eStmteContent==FTS5_CONTENT_NORMAL || pConfig->eContent==FTS5_CONTENT_UNINDEXED ){ - int nDefn = 32 + pConfig->nCol*10; - char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 20); - if( zDefn==0 ){ - rc = SQLITE_NOMEM; - }else{ - int i; - int iOff; - sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY"); - iOff = (int)strlen(zDefn); - for(i=0; inCol; i++){ - if( pConfig->eContent==FTS5_CONTENT_NORMAL - || pConfig->abUnindexed[i] - ){ - sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i); - iOff += (int)strlen(&zDefn[iOff]); - } + int i = 0; + char *zDefn = 0; + sqlite3_str *pDefn = sqlite3_str_new(pConfig->db); + + sqlite3_str_appendf(pDefn, "id INTEGER PRIMARY KEY"); + for(i=0; inCol; i++){ + if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->abUnindexed[i] ){ + sqlite3_str_appendf(pDefn, ", c%d", i); } - if( pConfig->bLocale ){ - for(i=0; inCol; i++){ - if( pConfig->abUnindexed[i]==0 ){ - sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i); - iOff += (int)strlen(&zDefn[iOff]); - } + } + if( pConfig->bLocale ){ + for(i=0; inCol; i++){ + if( pConfig->abUnindexed[i]==0 ){ + sqlite3_str_appendf(pDefn, ", l%d", i); } } + } + zDefn = sqlite3_str_finish(pDefn); + + if( zDefn ){ rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr); + sqlite3_free(zDefn); + }else{ + rc = SQLITE_NOMEM; } - sqlite3_free(zDefn); } if( rc==SQLITE_OK && pConfig->bColumnsize ){ @@ -255854,6 +265053,7 @@ static int fts5StorageDeleteFromIndex( for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ if( pConfig->abUnindexed[iCol-1]==0 ){ sqlite3_value *pVal = 0; + sqlite3_value *pFree = 0; const char *pText = 0; int nText = 0; const char *pLoc = 0; @@ -255870,11 +265070,22 @@ static int fts5StorageDeleteFromIndex( if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc); }else{ - pText = (const char*)sqlite3_value_text(pVal); - nText = sqlite3_value_bytes(pVal); - if( pConfig->bLocale && pSeek ){ - pLoc = (const char*)sqlite3_column_text(pSeek, iCol + pConfig->nCol); - nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol); + if( sqlite3_value_type(pVal)!=SQLITE_TEXT ){ + /* Make a copy of the value to work with. This is because the call + ** to sqlite3_value_text() below forces the type of the value to + ** SQLITE_TEXT, and we may need to use it again later. */ + pFree = pVal = sqlite3_value_dup(pVal); + if( pVal==0 ){ + rc = SQLITE_NOMEM; + } + } + if( rc==SQLITE_OK ){ + pText = (const char*)sqlite3_value_text(pVal); + nText = sqlite3_value_bytes(pVal); + if( pConfig->bLocale && pSeek ){ + pLoc = (const char*)sqlite3_column_text(pSeek, iCol+pConfig->nCol); + nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol); + } } } @@ -255890,6 +265101,7 @@ static int fts5StorageDeleteFromIndex( } sqlite3Fts5ClearLocale(pConfig); } + sqlite3_value_free(pFree); } } if( rc==SQLITE_OK && p->nTotalRow<1 ){ @@ -256905,7 +266117,7 @@ static int fts5AsciiCreate( if( nArg%2 ){ rc = SQLITE_ERROR; }else{ - p = sqlite3_malloc(sizeof(AsciiTokenizer)); + p = sqlite3_malloc64(sizeof(AsciiTokenizer)); if( p==0 ){ rc = SQLITE_NOMEM; }else{ @@ -257200,7 +266412,7 @@ static int fts5UnicodeCreate( if( nArg%2 ){ rc = SQLITE_ERROR; }else{ - p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer)); + p = (Unicode61Tokenizer*)sqlite3_malloc64(sizeof(Unicode61Tokenizer)); if( p ){ const char *zCat = "L* N* Co"; int i; @@ -257419,11 +266631,17 @@ static int fts5PorterCreate( const char *zBase = "unicode61"; fts5_tokenizer_v2 *pV2 = 0; - if( nArg>0 ){ - zBase = azArg[0]; + while( nArg>0 ){ + if( sqlite3_stricmp(azArg[0],"porter")==0 ){ + nArg--; + azArg++; + }else{ + zBase = azArg[0]; + break; + } } - pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer)); + pRet = (PorterTokenizer*)sqlite3_malloc64(sizeof(PorterTokenizer)); if( pRet ){ memset(pRet, 0, sizeof(PorterTokenizer)); rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2); @@ -258130,7 +267348,7 @@ static int fts5TriCreate( rc = SQLITE_ERROR; }else{ int i; - pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew)); + pNew = (TrigramTokenizer*)sqlite3_malloc64(sizeof(*pNew)); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ @@ -258186,8 +267404,8 @@ static int fts5TriTokenize( char *zOut = aBuf; int ii; const unsigned char *zIn = (const unsigned char*)pText; - const unsigned char *zEof = &zIn[nText]; - u32 iCode; + const unsigned char *zEof = (zIn ? &zIn[nText] : 0); + u32 iCode = 0; int aStart[3]; /* Input offset of each character in aBuf[] */ UNUSED_PARAM(unusedFlags); @@ -258196,8 +267414,8 @@ static int fts5TriTokenize( for(ii=0; ii<3; ii++){ do { aStart[ii] = zIn - (const unsigned char*)pText; + if( zIn>=zEof ) return SQLITE_OK; READ_UTF8(zIn, zEof, iCode); - if( iCode==0 ) return SQLITE_OK; if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam); }while( iCode==0 ); WRITE_UTF8(zOut, iCode); @@ -258218,8 +267436,11 @@ static int fts5TriTokenize( /* Read characters from the input up until the first non-diacritic */ do { iNext = zIn - (const unsigned char*)pText; + if( zIn>=zEof ){ + iCode = 0; + break; + } READ_UTF8(zIn, zEof, iCode); - if( iCode==0 ) break; if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam); }while( iCode==0 ); @@ -259100,7 +268321,6 @@ static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ aAscii[0] = 0; /* 0x00 is never a token character */ } - /* ** 2015 May 30 ** @@ -259641,12 +268861,12 @@ static int fts5VocabInitVtab( *pzErr = sqlite3_mprintf("wrong number of vtable arguments"); rc = SQLITE_ERROR; }else{ - int nByte; /* Bytes of space to allocate */ + i64 nByte; /* Bytes of space to allocate */ const char *zDb = bDb ? argv[3] : argv[1]; const char *zTab = bDb ? argv[4] : argv[3]; const char *zType = bDb ? argv[5] : argv[4]; - int nDb = (int)strlen(zDb)+1; - int nTab = (int)strlen(zTab)+1; + i64 nDb = strlen(zDb)+1; + i64 nTab = strlen(zTab)+1; int eType = 0; rc = fts5VocabTableType(zType, pzErr, &eType); @@ -259844,7 +269064,12 @@ static int fts5VocabOpenMethod( return rc; } +/* +** Restore cursor pCsr to the state it was in immediately after being +** created by the xOpen() method. +*/ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){ + int nCol = pCsr->pFts5->pConfig->nCol; pCsr->rowid = 0; sqlite3Fts5IterClose(pCsr->pIter); sqlite3Fts5StructureRelease(pCsr->pStruct); @@ -259854,6 +269079,12 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){ pCsr->nLeTerm = -1; pCsr->zLeTerm = 0; pCsr->bEof = 0; + pCsr->iCol = 0; + pCsr->iInstPos = 0; + pCsr->iInstOff = 0; + pCsr->colUsed = 0; + memset(pCsr->aCnt, 0, sizeof(i64)*nCol); + memset(pCsr->aDoc, 0, sizeof(i64)*nCol); } /* @@ -260103,7 +269334,7 @@ static int fts5VocabFilterMethod( const char *zCopy = (const char *)sqlite3_value_text(pLe); if( zCopy==0 ) zCopy = ""; pCsr->nLeTerm = sqlite3_value_bytes(pLe); - pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1); + pCsr->zLeTerm = sqlite3_malloc64((i64)pCsr->nLeTerm+1); if( pCsr->zLeTerm==0 ){ rc = SQLITE_NOMEM; }else{ @@ -260256,7 +269487,7 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ } - +/* Here ends the fts5.c composite file. */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */ /************** End of fts5.c ************************************************/ @@ -260612,6 +269843,7 @@ SQLITE_API int sqlite3_stmt_init( /************** End of stmt.c ************************************************/ /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } +#endif /* SQLITE_AMALGAMATION */ /************************** End of sqlite3.c ******************************/ /*** End of #include "sqlite3patched.c" ***/ @@ -260626,7 +269858,7 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } ** Purpose: Header file for SQLite3 Multiple Ciphers compile-time configuration ** Author: Ulrich Telle ** Created: 2021-09-27 -** Copyright: (c) 2019-2024 Ulrich Telle +** Copyright: (c) 2019-2025 Ulrich Telle ** License: MIT */ @@ -260664,6 +269896,10 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } #define HAVE_CIPHER_ASCON128 WXSQLITE3_HAVE_CIPHER_ASCON128 #endif +#ifdef WXSQLITE3_HAVE_CIPHER_AEGIS +#define HAVE_CIPHER_AEGIS WXSQLITE3_HAVE_CIPHER_AEGIS +#endif + /* ** Actual definitions of supported ciphers */ @@ -260691,6 +269927,22 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } #define HAVE_CIPHER_ASCON128 1 #endif +/* +** Disable AEGIS cipher scheme for MSVC 2015 and below +** MSVC versions below MSVC 2017 can't compile the AEGIS cipher code +** due to not supporting to pass aligned parameters by value +*/ +#if defined(_MSC_VER) && _MSC_VER < 1910 +#ifdef HAVE_CIPHER_AEGIS +#undef HAVE_CIPHER_AEGIS +#endif +#define HAVE_CIPHER_AEGIS 0 +#endif + +#ifndef HAVE_CIPHER_AEGIS +#define HAVE_CIPHER_AEGIS 1 +#endif + /* ** Define whether dynamic ciphers will be used */ @@ -260714,12 +269966,14 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } #undef HAVE_CIPHER_SQLCIPHER #undef HAVE_CIPHER_RC4 #undef HAVE_CIPHER_ASCON128 +#undef HAVE_CIPHER_AEGIS #define HAVE_CIPHER_AES_128_CBC 0 #define HAVE_CIPHER_AES_256_CBC 0 #define HAVE_CIPHER_CHACHA20 0 #define HAVE_CIPHER_SQLCIPHER 0 #define HAVE_CIPHER_RC4 0 #define HAVE_CIPHER_ASCON128 0 +#define HAVE_CIPHER_AEGIS 0 #endif /* @@ -260731,7 +269985,8 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } HAVE_CIPHER_CHACHA20 == 0 && \ HAVE_CIPHER_SQLCIPHER == 0 && \ HAVE_CIPHER_RC4 == 0 && \ - HAVE_CIPHER_ASCON128 == 0 + HAVE_CIPHER_ASCON128 == 0 && \ + HAVE_CIPHER_AEGIS == 0 #pragma message ("sqlite3mc_config.h: WARNING - No built-in cipher scheme enabled!") #endif @@ -260811,7 +270066,7 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } ** Purpose: Header file for SQLite3 Multiple Ciphers support ** Author: Ulrich Telle ** Created: 2020-03-01 -** Copyright: (c) 2019-2024 Ulrich Telle +** Copyright: (c) 2019-2026 Ulrich Telle ** License: MIT */ @@ -260828,7 +270083,7 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } ** Purpose: SQLite3 Multiple Ciphers version numbers ** Author: Ulrich Telle ** Created: 2020-08-05 -** Copyright: (c) 2020-2024 Ulrich Telle +** Copyright: (c) 2020-2026 Ulrich Telle ** License: MIT */ @@ -260837,11 +270092,11 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } #ifndef SQLITE3MC_VERSION_H_ #define SQLITE3MC_VERSION_H_ -#define SQLITE3MC_VERSION_MAJOR 1 -#define SQLITE3MC_VERSION_MINOR 9 +#define SQLITE3MC_VERSION_MAJOR 2 +#define SQLITE3MC_VERSION_MINOR 5 #define SQLITE3MC_VERSION_RELEASE 0 #define SQLITE3MC_VERSION_SUBRELEASE 0 -#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.9.0" +#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 2.5.0" #endif /* SQLITE3MC_VERSION_H_ */ /*** End of #include "sqlite3mc_version.h" ***/ @@ -260987,7 +270242,7 @@ extern "C" { ** ** Since [version 3.6.18] ([dateof:3.6.18]), ** SQLite source code has been stored in the -** Fossil configuration management +** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID @@ -261000,9 +270255,12 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.47.0" -#define SQLITE_VERSION_NUMBER 3047000 -#define SQLITE_SOURCE_ID "2024-10-21 16:30:22 03a9703e27c44437c39363d0baf82db4ebc94538a0f28411c85dda156f82636e" +#define SQLITE_VERSION "3.53.4" +#define SQLITE_VERSION_NUMBER 3053004 +#define SQLITE_SOURCE_ID "2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc" +#define SQLITE_SCM_BRANCH "branch-3.53" +#define SQLITE_SCM_TAGS "release version-3.53.4" +#define SQLITE_SCM_DATETIME "2026-07-24T19:02:57.525Z" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -261022,9 +270280,9 @@ extern "C" { ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 ); ** )^ ** -** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION] -** macro. ^The sqlite3_libversion() function returns a pointer to the -** to the sqlite3_version[] string constant. The sqlite3_libversion() +** ^The sqlite3_version[] string constant contains the text of the +** [SQLITE_VERSION] macro. ^The sqlite3_libversion() function returns a +** pointer to the sqlite3_version[] string constant. The sqlite3_libversion() ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to @@ -261224,7 +270482,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** without having to use a lot of C code. ** ** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, -** semicolon-separate SQL statements passed into its 2nd argument, +** semicolon-separated SQL statements passed into its 2nd argument, ** in the context of the [database connection] passed in as its 1st ** argument. ^If the callback function of the 3rd argument to ** sqlite3_exec() is not NULL, then it is invoked for each result row @@ -261257,7 +270515,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** result row is NULL then the corresponding string pointer for the ** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the ** sqlite3_exec() callback is an array of pointers to strings where each -** entry represents the name of corresponding result column as obtained +** entry represents the name of a corresponding result column as obtained ** from [sqlite3_column_name()]. ** ** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer @@ -261351,6 +270609,9 @@ SQLITE_API int sqlite3_exec( #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) #define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) +#define SQLITE_ERROR_RESERVESIZE (SQLITE_ERROR | (4<<8)) +#define SQLITE_ERROR_KEY (SQLITE_ERROR | (5<<8)) +#define SQLITE_ERROR_UNABLE (SQLITE_ERROR | (6<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) @@ -261385,6 +270646,8 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8)) +#define SQLITE_IOERR_BADKEY (SQLITE_IOERR | (35<<8)) +#define SQLITE_IOERR_CODEC (SQLITE_IOERR | (36<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) @@ -261424,7 +270687,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) -#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ +#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal only */ /* ** CAPI3REF: Flags For File Open Operations @@ -261443,7 +270706,7 @@ SQLITE_API int sqlite3_exec( ** Note in particular that passing the SQLITE_OPEN_EXCLUSIVE flag into ** [sqlite3_open_v2()] does *not* cause the underlying database file ** to be opened using O_EXCL. Passing SQLITE_OPEN_EXCLUSIVE into -** [sqlite3_open_v2()] has historically be a no-op and might become an +** [sqlite3_open_v2()] has historically been a no-op and might become an ** error in future versions of SQLite. */ #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ @@ -261506,6 +270769,13 @@ SQLITE_API int sqlite3_exec( ** filesystem supports doing multiple write operations atomically when those ** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and ** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. +** +** The SQLITE_IOCAP_SUBPAGE_READ property means that it is ok to read +** from the database file in amounts that are not a multiple of the +** page size and that do not begin at a page boundary. Without this +** property, SQLite is careful to only do full-page reads and write +** on aligned pages, with the one exception that it will do a sub-page +** read of the first page to access the database header. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -261522,6 +270792,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 +#define SQLITE_IOCAP_SUBPAGE_READ 0x00008000 /* ** CAPI3REF: File Locking Levels @@ -261529,7 +270800,7 @@ SQLITE_API int sqlite3_exec( ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods ** of an [sqlite3_io_methods] object. These values are ordered from -** lest restrictive to most restrictive. +** least restrictive to most restrictive. ** ** The argument to xLock() is always SHARED or higher. The argument to ** xUnlock is either SHARED or NONE. @@ -261668,6 +270939,7 @@ struct sqlite3_file { **
      • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] **
      • [SQLITE_IOCAP_IMMUTABLE] **
      • [SQLITE_IOCAP_BATCH_ATOMIC] +**
      • [SQLITE_IOCAP_SUBPAGE_READ] **
      ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -261769,7 +271041,7 @@ struct sqlite3_io_methods { ** connection. See also [SQLITE_FCNTL_FILE_POINTER]. ** **
    • [[SQLITE_FCNTL_SYNC_OMITTED]] -** No longer in use. +** The SQLITE_FCNTL_SYNC_OMITTED file-control is no longer used. ** **
    • [[SQLITE_FCNTL_SYNC]] ** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and @@ -261844,7 +271116,7 @@ struct sqlite3_io_methods { ** **
    • [[SQLITE_FCNTL_VFSNAME]] ** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of -** all [VFSes] in the VFS stack. The names are of all VFS shims and the +** all [VFSes] in the VFS stack. The names of all VFS shims and the ** final bottom-level VFS are written into memory obtained from ** [sqlite3_malloc()] and the result is stored in the char* variable ** that the fourth parameter of [sqlite3_file_control()] points to. @@ -261858,7 +271130,7 @@ struct sqlite3_io_methods { ** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level ** [VFSes] currently in use. ^(The argument X in ** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be -** of type "[sqlite3_vfs] **". This opcodes will set *X +** of type "[sqlite3_vfs] **". This opcode will set *X ** to a pointer to the top-level VFS.)^ ** ^When there are multiple VFS shims in the stack, this opcode finds the ** upper-most shim only. @@ -261945,6 +271217,11 @@ struct sqlite3_io_methods { ** pointed to by the pArg argument. This capability is used during testing ** and only needs to be supported when SQLITE_TEST is defined. ** +**
    • [[SQLITE_FCNTL_NULL_IO]] +** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor +** or file handle for the [sqlite3_file] object such that it will no longer +** read or write to the database file. +** **
    • [[SQLITE_FCNTL_WAL_BLOCK]] ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might ** be advantageous to block on the next WAL lock if the lock is not immediately @@ -262003,6 +271280,12 @@ struct sqlite3_io_methods { ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** +**
    • [[SQLITE_FCNTL_BLOCK_ON_CONNECT]] +** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the +** VFS to block when taking a SHARED lock to connect to a wal mode database. +** This is used to implement the functionality associated with +** SQLITE_SETLK_BLOCK_ON_CONNECT. +** **
    • [[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. @@ -262037,7 +271320,7 @@ struct sqlite3_io_methods { **
    • [[SQLITE_FCNTL_EXTERNAL_READER]] ** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect ** whether or not there is a database client in another process with a wal-mode -** transaction open on the database or not. It is only available on unix.The +** transaction open on the database or not. It is only available on unix. The ** (void*) argument passed with this file-control should be a pointer to a ** value of type (int). The integer value is set to 1 if the database is a wal ** mode database and there exists at least one client in another process that @@ -262055,6 +271338,15 @@ struct sqlite3_io_methods { ** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control ** purges the contents of the in-memory page cache. If there is an open ** transaction, or if the db is a temp-db, this opcode is a no-op, not an error. +** +**
    • [[SQLITE_FCNTL_FILESTAT]] +** The [SQLITE_FCNTL_FILESTAT] opcode returns low-level diagnostic information +** about the [sqlite3_file] objects used access the database and journal files +** for the given schema. The fourth parameter to [sqlite3_file_control()] +** should be an initialized [sqlite3_str] pointer. JSON text describing +** various aspects of the sqlite3_file object is appended to the sqlite3_str. +** The SQLITE_FCNTL_FILESTAT opcode is usually a no-op, unless compile-time +** options are used to enable it. **
    */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -262098,12 +271390,21 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 +#define SQLITE_FCNTL_NULL_IO 43 +#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44 +#define SQLITE_FCNTL_FILESTAT 45 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO +/* reserved file-control numbers: +** 101 +** 102 +** 103 +*/ + /* ** CAPI3REF: Mutex Handle @@ -262304,7 +271605,7 @@ typedef const char *sqlite3_filename; ** greater and the function pointer is not NULL) and will fall back ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. ** -** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces +** ^The xSetSystemCall(), xGetSystemCall(), and xNextSystemCall() interfaces ** are not used by the SQLite core. These optional interfaces are provided ** by some VFSes to facilitate testing of the VFS code. By overriding ** system calls with functions under its control, a test program can @@ -262460,7 +271761,7 @@ struct sqlite3_vfs { ** SQLite interfaces so that an application usually does not need to ** invoke sqlite3_initialize() directly. For example, [sqlite3_open()] ** calls sqlite3_initialize() so the SQLite library will be automatically -** initialized when [sqlite3_open()] is called if it has not be initialized +** initialized when [sqlite3_open()] is called if it has not been initialized ** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT] ** compile-time option, then the automatic calls to sqlite3_initialize() ** are omitted and the application must call sqlite3_initialize() directly @@ -262525,7 +271826,8 @@ SQLITE_API int sqlite3_os_end(void); ** are called "anytime configuration options". ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before ** [sqlite3_shutdown()] with a first argument that is not an anytime -** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE. +** configuration option, then the sqlite3_config() call will +** return SQLITE_MISUSE. ** Note, however, that ^sqlite3_config() can be called as part of the ** implementation of an application-defined [sqlite3_os_init()]. ** @@ -262717,21 +272019,21 @@ struct sqlite3_mem_methods { ** The [sqlite3_mem_methods] ** structure is filled with the currently defined memory allocation routines.)^ ** This option can be used to overload the default memory allocation -** routines with a wrapper that simulations memory allocation failure or +** routines with a wrapper that simulates memory allocation failure or ** tracks memory usage, for example. ** ** [[SQLITE_CONFIG_SMALL_MALLOC]]
    SQLITE_CONFIG_SMALL_MALLOC
    -**
    ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of +**
    ^The SQLITE_CONFIG_SMALL_MALLOC option takes a single argument of ** type int, interpreted as a boolean, which if true provides a hint to ** SQLite that it should avoid large memory allocations if possible. ** SQLite will run faster if it is free to make large memory allocations, -** but some application might prefer to run slower in exchange for +** but some applications might prefer to run slower in exchange for ** guarantees about memory fragmentation that are possible if large ** allocations are avoided. This hint is normally off. **
    ** ** [[SQLITE_CONFIG_MEMSTATUS]]
    SQLITE_CONFIG_MEMSTATUS
    -**
    ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, +**
    ^The SQLITE_CONFIG_MEMSTATUS option takes a single argument of type int, ** interpreted as a boolean, which enables or disables the collection of ** memory allocation statistics. ^(When memory allocation statistics are ** disabled, the following SQLite interfaces become non-operational: @@ -262776,7 +272078,7 @@ struct sqlite3_mem_methods { ** ^If pMem is NULL and N is non-zero, then each database connection ** does an initial bulk allocation for page cache memory ** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or -** of -1024*N bytes if N is negative, . ^If additional +** of -1024*N bytes if N is negative. ^If additional ** page cache memory is needed beyond what is provided by the initial ** allocation, then SQLite goes to [sqlite3_malloc()] separately for each ** additional cache line.
    @@ -262805,7 +272107,7 @@ struct sqlite3_mem_methods { **
    ^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a ** pointer to an instance of the [sqlite3_mutex_methods] structure. ** The argument specifies alternative low-level mutex routines to be used -** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of +** in place of the mutex routines built into SQLite.)^ ^SQLite makes a copy of ** the content of the [sqlite3_mutex_methods] structure before the call to ** [sqlite3_config()] returns. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then @@ -262828,13 +272130,16 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_LOOKASIDE]]
    SQLITE_CONFIG_LOOKASIDE
    **
    ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine -** the default size of lookaside memory on each [database connection]. +** the default size of [lookaside memory] on each [database connection]. ** The first argument is the -** size of each lookaside buffer slot and the second is the number of -** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE -** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] -** option to [sqlite3_db_config()] can be used to change the lookaside -** configuration on individual connections.)^
    +** size of each lookaside buffer slot ("sz") and the second is the number of +** slots allocated to each database connection ("cnt").)^ +** ^(SQLITE_CONFIG_LOOKASIDE sets the default lookaside size. +** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can +** be used to change the lookaside configuration on individual connections.)^ +** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the +** default lookaside configuration at compile-time. +** ** ** [[SQLITE_CONFIG_PCACHE2]]
    SQLITE_CONFIG_PCACHE2
    **
    ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is @@ -262844,7 +272149,7 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_GETPCACHE2]]
    SQLITE_CONFIG_GETPCACHE2
    **
    ^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which -** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of +** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies off ** the current page cache implementation into that object.)^
    ** ** [[SQLITE_CONFIG_LOG]]
    SQLITE_CONFIG_LOG
    @@ -262861,7 +272166,7 @@ struct sqlite3_mem_methods { ** the logger function is a copy of the first parameter to the corresponding ** [sqlite3_log()] call and is intended to be a [result code] or an ** [extended result code]. ^The third parameter passed to the logger is -** log message after formatting via [sqlite3_snprintf()]. +** a log message after formatting via [sqlite3_snprintf()]. ** The SQLite logging interface is not reentrant; the logger function ** supplied by the application must not invoke any SQLite interface. ** In a multi-threaded application, the application-defined logger @@ -263050,7 +272355,15 @@ struct sqlite3_mem_methods { ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that -** can be passed as the second argument to the [sqlite3_db_config()] interface. +** can be passed as the second parameter to the [sqlite3_db_config()] interface. +** +** The [sqlite3_db_config()] interface is a var-args function. It takes a +** variable number of parameters, though always at least two. The number of +** parameters passed into sqlite3_db_config() depends on which of these +** constants is given as the second parameter. This documentation page +** refers to parameters beyond the second as "arguments". Thus, when this +** page says "the N-th argument" it means "the N-th parameter past the +** configuration option" or "the (N+2)-th parameter to sqlite3_db_config()". ** ** New configuration options may be added in future releases of SQLite. ** Existing configuration options might be discontinued. Applications @@ -263062,31 +272375,58 @@ struct sqlite3_mem_methods { **
    ** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    -**
    ^This option takes three additional arguments that determine the -** [lookaside memory allocator] configuration for the [database connection]. -** ^The first argument (the third parameter to [sqlite3_db_config()] is a +**
    The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the +** configuration of the [lookaside memory allocator] within a database +** connection. +** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are not +** in the [DBCONFIG arguments|usual format]. +** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two, +** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE +** should have a total of five parameters. +**
      +**
    1. The first argument ("buf") is a ** pointer to a memory buffer to use for lookaside memory. -** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb -** may be NULL in which case SQLite will allocate the -** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the -** size of each lookaside buffer slot. ^The third argument is the number of -** slots. The size of the buffer in the first argument must be greater than -** or equal to the product of the second and third arguments. The buffer -** must be aligned to an 8-byte boundary. ^If the second argument to -** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally -** rounded down to the next smaller multiple of 8. ^(The lookaside memory +** The first argument may be NULL in which case SQLite will allocate the +** lookaside buffer itself using [sqlite3_malloc()]. +**

    2. The second argument ("sz") is the +** size of each lookaside buffer slot. Lookaside is disabled if "sz" +** is less than 8. The "sz" argument should be a multiple of 8 less than +** 65536. If "sz" does not meet this constraint, it is reduced in size until +** it does. +**

    3. The third argument ("cnt") is the number of slots. +** Lookaside is disabled if "cnt"is less than 1. +* The "cnt" value will be reduced, if necessary, so +** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt" +** parameter is usually chosen so that the product of "sz" and "cnt" is less +** than 1,000,000. +**

    +**

    If the "buf" argument is not NULL, then it must +** point to a memory buffer with a size that is greater than +** or equal to the product of "sz" and "cnt". +** The buffer must be aligned to an 8-byte boundary. +** The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words -** when the "current value" returned by -** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero. +** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns -** [SQLITE_BUSY].)^

    +** [SQLITE_BUSY]. +** If the "buf" argument is NULL and an attempt +** to allocate memory based on "sz" and "cnt" fails, then +** lookaside is silently disabled. +**

    +** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the +** default lookaside configuration at initialization. The +** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside +** configuration at compile-time. Typical values for lookaside are 1200 for +** "sz" and 40 to 100 for "cnt". +** ** ** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **

    SQLITE_DBCONFIG_ENABLE_FKEY
    **
    ^This option is used to enable or disable the enforcement of -** [foreign key constraints]. There should be two additional arguments. +** [foreign key constraints]. This is the same setting that is +** enabled or disabled by the [PRAGMA foreign_keys] statement. ** The first argument is an integer which is 0 to disable FK enforcement, ** positive to enable FK enforcement or negative to leave FK enforcement ** unchanged. The second parameter is a pointer to an integer into which @@ -263108,13 +272448,13 @@ struct sqlite3_mem_methods { **

    Originally this option disabled all triggers. ^(However, since ** SQLite version 3.35.0, TEMP triggers are still allowed even if ** this option is off. So, in other words, this option now only disables -** triggers in the main database schema or in the schemas of ATTACH-ed +** triggers in the main database schema or in the schemas of [ATTACH]-ed ** databases.)^

    ** ** [[SQLITE_DBCONFIG_ENABLE_VIEW]] **
    SQLITE_DBCONFIG_ENABLE_VIEW
    **
    ^This option is used to enable or disable [CREATE VIEW | views]. -** There should be two additional arguments. +** There must be two additional arguments. ** The first argument is an integer which is 0 to disable views, ** positive to enable views or negative to leave the setting unchanged. ** The second parameter is a pointer to an integer into which @@ -263130,17 +272470,20 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] **
    SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
    -**
    ^This option is used to enable or disable the -** [fts3_tokenizer()] function which is part of the -** [FTS3] full-text search engine extension. -** There should be two additional arguments. -** The first argument is an integer which is 0 to disable fts3_tokenizer() or -** positive to enable fts3_tokenizer() or negative to leave the setting -** unchanged. -** The second parameter is a pointer to an integer into which -** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled -** following this call. The second parameter may be a NULL pointer, in -** which case the new setting is not reported back.
    +**
    ^This option is used to enable or disable using the +** [fts3_tokenizer()] function - part of the [FTS3] full-text search engine +** extension - without using bound parameters as the parameters. Doing so +** is disabled by default. There must be two additional arguments. The first +** argument is an integer. If it is passed 0, then using fts3_tokenizer() +** without bound parameters is disabled. If it is passed a positive value, +** then calling fts3_tokenizer without bound parameters is enabled. If it +** is passed a negative value, this setting is not modified - this can be +** used to query for the current setting. The second parameter is a pointer +** to an integer into which is written 0 or 1 to indicate the current value +** of this setting (after it is modified, if applicable). The second +** parameter may be a NULL pointer, in which case the value of the setting +** is not reported back. Refer to [FTS3] documentation for further details. +**
    ** ** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]] **
    SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
    @@ -263148,12 +272491,12 @@ struct sqlite3_mem_methods { ** interface independently of the [load_extension()] SQL function. ** The [sqlite3_enable_load_extension()] API enables or disables both the ** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. -** There should be two additional arguments. +** There must be two additional arguments. ** When the first argument to this interface is 1, then only the C-API is ** enabled and the SQL function remains disabled. If the first argument to ** this interface is 0, then both the C-API and the SQL function are disabled. -** If the first argument is -1, then no changes are made to state of either the -** C-API or the SQL function. +** If the first argument is -1, then no changes are made to the state of either +** the C-API or the SQL function. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface ** is disabled or enabled following this call. The second parameter may @@ -263162,23 +272505,30 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_DBCONFIG_MAINDBNAME]]
    SQLITE_DBCONFIG_MAINDBNAME
    **
    ^This option is used to change the name of the "main" database -** schema. ^The sole argument is a pointer to a constant UTF8 string -** which will become the new schema name in place of "main". ^SQLite -** does not make a copy of the new main schema name string, so the application -** must ensure that the argument passed into this DBCONFIG option is unchanged -** until after the database connection closes. +** schema. This option does not follow the +** [DBCONFIG arguments|usual SQLITE_DBCONFIG argument format]. +** This option takes exactly one additional argument so that the +** [sqlite3_db_config()] call has a total of three parameters. The +** extra argument must be a pointer to a constant UTF8 string which +** will become the new schema name in place of "main". ^SQLite does +** not make a copy of the new main schema name string, so the application +** must ensure that the argument passed into SQLITE_DBCONFIG MAINDBNAME +** is unchanged until after the database connection closes. **
    ** ** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] **
    SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
    -**
    Usually, when a database in wal mode is closed or detached from a -** database handle, SQLite checks if this will mean that there are now no -** connections at all to the database. If so, it performs a checkpoint -** operation before closing the connection. This option may be used to -** override this behavior. The first parameter passed to this operation -** is an integer - positive to disable checkpoints-on-close, or zero (the -** default) to enable them, and negative to leave the setting unchanged. -** The second parameter is a pointer to an integer +**
    Usually, when a database in [WAL mode] is closed or detached from a +** database handle, SQLite checks if if there are other connections to the +** same database, and if there are no other database connection (if the +** connection being closed is the last open connection to the database), +** then SQLite performs a [checkpoint] before closing the connection and +** deletes the WAL file. The SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE option can +** be used to override that behavior. The first argument passed to this +** operation (the third parameter to [sqlite3_db_config()]) is an integer +** which is positive to disable checkpoints-on-close, or zero (the default) +** to enable them, and negative to leave the setting unchanged. +** The second argument (the fourth parameter) is a pointer to an integer ** into which is written 0 or 1 to indicate whether checkpoints-on-close ** have been disabled - 0 if they are not disabled, 1 if they are. **
    @@ -263264,7 +272614,7 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]] **
    SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
    **
    The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates -** the legacy behavior of the [ALTER TABLE RENAME] command such it +** the legacy behavior of the [ALTER TABLE RENAME] command such that it ** behaves as it did prior to [version 3.24.0] (2018-06-04). See the ** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for ** additional information. This feature can also be turned on and off @@ -263313,7 +272663,7 @@ struct sqlite3_mem_methods { **
    SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
    **
    The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates ** the legacy file format flag. When activated, this flag causes all newly -** created database file to have a schema format version number (the 4-byte +** created database files to have a schema format version number (the 4-byte ** integer found at offset 44 into the database header) of 1. This in turn ** means that the resulting database file will be readable and writable by ** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting, @@ -263334,13 +272684,16 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]] **
    SQLITE_DBCONFIG_STMT_SCANSTATUS
    **
    The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in -** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears -** a flag that enables collection of the sqlite3_stmt_scanstatus_v2() -** statistics. For statistics to be collected, the flag must be set on -** the database handle both when the SQL statement is prepared and when it -** is stepped. The flag is set (collection of statistics is enabled) -** by default. This option takes two arguments: an integer and a pointer to -** an integer.. The first argument is 1, 0, or -1 to enable, disable, or +** [SQLITE_ENABLE_STMT_SCANSTATUS] builds. In this case, it sets or clears +** a flag that enables collection of run-time performance statistics +** used by [sqlite3_stmt_scanstatus_v2()] and the [nexec and ncycle] +** columns of the [bytecode virtual table]. +** For statistics to be collected, the flag must be set on +** the database handle both when the SQL statement is +** [sqlite3_prepare|prepared] and when it is [sqlite3_step|stepped]. +** The flag is set (collection of statistics is enabled) by default. +**

    This option takes two arguments: an integer and a pointer to +** an integer. The first argument is 1, 0, or -1 to enable, disable, or ** leave unchanged the statement scanstatus option. If the second argument ** is not NULL, then the value of the statement scanstatus setting after ** processing the first argument is written into the integer that the second @@ -263353,7 +272706,7 @@ struct sqlite3_mem_methods { ** in which tables and indexes are scanned so that the scans start at the end ** and work toward the beginning rather than starting at the beginning and ** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the -** same as setting [PRAGMA reverse_unordered_selects]. This option takes +** same as setting [PRAGMA reverse_unordered_selects].

    This option takes ** two arguments which are an integer and a pointer to an integer. The first ** argument is 1, 0, or -1 to enable, disable, or leave unchanged the ** reverse scan order flag, respectively. If the second argument is not NULL, @@ -263362,7 +272715,95 @@ struct sqlite3_mem_methods { ** first argument. **

    ** +** [[SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]] +**
    SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE
    +**
    The SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE option enables or disables +** the ability of the [ATTACH DATABASE] SQL command to create a new database +** file if the database filed named in the ATTACH command does not already +** exist. This ability of ATTACH to create a new database is enabled by +** default. Applications can disable or reenable the ability for ATTACH to +** create new database files using this DBCONFIG option.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is 1, 0, or -1 to enable, disable, or +** leave unchanged the attach-create flag, respectively. If the second +** argument is not NULL, then 0 or 1 is written into the integer that the +** second argument points to depending on if the attach-create flag is set +** after processing the first argument. +**

    +** +** [[SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE]] +**
    SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE
    +**
    The SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE option enables or disables the +** ability of the [ATTACH DATABASE] SQL command to open a database for writing. +** This capability is enabled by default. Applications can disable or +** reenable this capability using the current DBCONFIG option. If +** this capability is disabled, the [ATTACH] command will still work, +** but the database will be opened read-only. If this option is disabled, +** then the ability to create a new database using [ATTACH] is also disabled, +** regardless of the value of the [SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE] +** option.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is 1, 0, or -1 to enable, disable, or +** leave unchanged the ability to ATTACH another database for writing, +** respectively. If the second argument is not NULL, then 0 or 1 is written +** into the integer to which the second argument points, depending on whether +** the ability to ATTACH a read/write database is enabled or disabled +** after processing the first argument. +**

    +** +** [[SQLITE_DBCONFIG_ENABLE_COMMENTS]] +**
    SQLITE_DBCONFIG_ENABLE_COMMENTS
    +**
    The SQLITE_DBCONFIG_ENABLE_COMMENTS option enables or disables the +** ability to include comments in SQL text. Comments are enabled by default. +** An application can disable or reenable comments in SQL text using this +** DBCONFIG option.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is 1, 0, or -1 to enable, disable, or +** leave unchanged the ability to use comments in SQL text, +** respectively. If the second argument is not NULL, then 0 or 1 is written +** into the integer that the second argument points to depending on if +** comments are allowed in SQL text after processing the first argument. +**

    +** +** [[SQLITE_DBCONFIG_FP_DIGITS]] +**
    SQLITE_DBCONFIG_FP_DIGITS
    +**
    The SQLITE_DBCONFIG_FP_DIGITS setting is a small integer that determines +** the number of significant digits that SQLite will attempt to preserve when +** converting floating point numbers (IEEE 754 "doubles") into text. The +** default value 17, as of SQLite version 3.52.0. The value was 15 in all +** prior versions.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is a small integer, between 3 and 23, or +** zero. The FP_DIGITS setting is changed to that small integer, or left +** unaltered if the first argument is zero or out of range. The second argument +** is a pointer to an integer. If the pointer is not NULL, then the value of +** the FP_DIGITS setting, after possibly being modified by the first +** arguments, is written into the integer to which the second argument points. +**

    +** **
    +** +** [[DBCONFIG arguments]]

    Arguments To SQLITE_DBCONFIG Options

    +** +**

    Most of the SQLITE_DBCONFIG options take two arguments, so that the +** overall call to [sqlite3_db_config()] has a total of four parameters. +** The first argument (the third parameter to sqlite3_db_config()) is +** an integer. +** The second argument is a pointer to an integer. If the first argument is 1, +** then the option becomes enabled. If the first integer argument is 0, +** then the option is disabled. +** If the first argument is -1, then the option setting +** is unchanged. The second argument, the pointer to an integer, may be NULL. +** If the second argument is not NULL, then a value of 0 or 1 is written into +** the integer to which the second argument points, depending on whether the +** setting is disabled or enabled after applying any changes specified by +** the first argument. +** +**

    While most SQLITE_DBCONFIG options use the argument format +** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME], +** [SQLITE_DBCONFIG_LOOKASIDE], and [SQLITE_DBCONFIG_FP_DIGITS] options +** are different. See the documentation of those exceptional options for +** details. */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ @@ -263384,7 +272825,11 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ #define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */ #define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE 1020 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE 1021 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_COMMENTS 1022 /* int int* */ +#define SQLITE_DBCONFIG_FP_DIGITS 1023 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1023 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -263476,10 +272921,14 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. ** The two functions are identical except for the type of the return value -** and that if the number of rows modified by the most recent INSERT, UPDATE +** and that if the number of rows modified by the most recent INSERT, UPDATE, ** or DELETE is greater than the maximum value supported by type "int", then ** the return value of sqlite3_changes() is undefined. ^Executing any other ** type of SQL statement does not modify the value returned by these functions. +** For the purposes of this interface, a CREATE TABLE AS SELECT statement +** does not count as an INSERT, UPDATE or DELETE statement and hence the rows +** added to the new table by the CREATE TABLE AS SELECT statement are not +** counted. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], @@ -263632,7 +273081,7 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** ^These routines return 0 if the statement is incomplete. ^If a ** memory allocation fails, then SQLITE_NOMEM is returned. ** -** ^These routines do not parse the SQL statements thus +** ^These routines do not parse the SQL statements and thus ** will not detect syntactically incorrect SQL. ** ** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior @@ -263734,6 +273183,44 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); +/* +** CAPI3REF: Set the Setlk Timeout +** METHOD: sqlite3 +** +** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If +** the VFS supports blocking locks, it sets the timeout in ms used by +** eligible locks taken on wal mode databases by the specified database +** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does +** not support blocking locks, this function is a no-op. +** +** Passing 0 to this function disables blocking locks altogether. Passing +** -1 to this function requests that the VFS blocks for a long time - +** indefinitely if possible. The results of passing any other negative value +** are undefined. +** +** Internally, each SQLite database handle stores two timeout values - the +** busy-timeout (used for rollback mode databases, or if the VFS does not +** support blocking locks) and the setlk-timeout (used for blocking locks +** on wal-mode databases). The sqlite3_busy_timeout() method sets both +** values, this function sets only the setlk-timeout value. Therefore, +** to configure separate busy-timeout and setlk-timeout values for a single +** database handle, call sqlite3_busy_timeout() followed by this function. +** +** Whenever the number of connections to a wal mode database falls from +** 1 to 0, the last connection takes an exclusive lock on the database, +** then checkpoints and deletes the wal file. While it is doing this, any +** new connection that tries to read from the database fails with an +** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is +** passed to this API, the new connection blocks until the exclusive lock +** has been released. +*/ +SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags); + +/* +** CAPI3REF: Flags for sqlite3_setlk_timeout() +*/ +#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01 + /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 @@ -263741,7 +273228,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); ** This is a legacy interface that is preserved for backwards compatibility. ** Use of this interface is not recommended. ** -** Definition: A result table is memory data structure created by the +** Definition: A result table is a memory data structure created by the ** [sqlite3_get_table()] interface. A result table records the ** complete query results from one or more queries. ** @@ -263884,7 +273371,7 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** ^Calling sqlite3_free() with a pointer previously returned ** by sqlite3_malloc() or sqlite3_realloc() releases that memory so ** that it might be reused. ^The sqlite3_free() routine is -** a no-op if is called with a NULL pointer. Passing a NULL pointer +** a no-op if it is called with a NULL pointer. Passing a NULL pointer ** to sqlite3_free() is harmless. After being freed, memory ** should neither be read nor written. Even reading previously freed ** memory might result in a segmentation fault or other severe error. @@ -263902,13 +273389,13 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** sqlite3_free(X). ** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation ** of at least N bytes in size or NULL if insufficient memory is available. -** ^If M is the size of the prior allocation, then min(N,M) bytes -** of the prior allocation are copied into the beginning of buffer returned +** ^If M is the size of the prior allocation, then min(N,M) bytes of the +** prior allocation are copied into the beginning of the buffer returned ** by sqlite3_realloc(X,N) and the prior allocation is freed. ** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the ** prior allocation is not freed. ** -** ^The sqlite3_realloc64(X,N) interfaces works the same as +** ^The sqlite3_realloc64(X,N) interface works the same as ** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead ** of a 32-bit signed integer. ** @@ -263958,7 +273445,7 @@ SQLITE_API sqlite3_uint64 sqlite3_msize(void*); ** was last reset. ^The values returned by [sqlite3_memory_used()] and ** [sqlite3_memory_highwater()] include any overhead ** added by SQLite in its implementation of [sqlite3_malloc()], -** but not overhead added by the any underlying system library +** but not overhead added by any underlying system library ** routines that [sqlite3_malloc()] may call. ** ** ^The memory high-water mark is reset to the current value of @@ -264410,7 +273897,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** there is no harm in trying.) ** ** ^(

    [SQLITE_OPEN_SHAREDCACHE]
    -**
    The database is opened [shared cache] enabled, overriding +**
    The database is opened with [shared cache] enabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** The [use of shared cache mode is discouraged] and hence shared cache @@ -264418,7 +273905,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** this option is a no-op. ** ** ^(
    [SQLITE_OPEN_PRIVATECACHE]
    -**
    The database is opened [shared cache] disabled, overriding +**
    The database is opened with [shared cache] disabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** @@ -264753,7 +274240,7 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); ** ** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of ** database filename D with corresponding journal file J and WAL file W and -** with N URI parameters key/values pairs in the array P. The result from +** an array P of N URI Key/Value pairs. The result from ** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that ** is safe to pass to routines like: **
      @@ -264824,6 +274311,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); **
    • sqlite3_errmsg() **
    • sqlite3_errmsg16() **
    • sqlite3_error_offset() +**
    • sqlite3_db_handle() **
    ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language @@ -264836,7 +274324,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); ** subsequent calls to other SQLite interface functions.)^ ** ** ^The sqlite3_errstr(E) interface returns the English-language text -** that describes the [result code] E, as UTF-8, or NULL if E is not an +** that describes the [result code] E, as UTF-8, or NULL if E is not a ** result code for which a text error message is available. ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. @@ -264844,7 +274332,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); ** ^If the most recent error references a specific token in the input ** SQL, the sqlite3_error_offset() interface returns the byte offset ** of the start of that token. ^The byte offset returned by -** sqlite3_error_offset() assumes that the input SQL is UTF8. +** sqlite3_error_offset() assumes that the input SQL is UTF-8. ** ^If the most recent error does not reference a specific token in the input ** SQL, then the sqlite3_error_offset() function returns -1. ** @@ -264869,6 +274357,34 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3*); SQLITE_API const char *sqlite3_errstr(int); SQLITE_API int sqlite3_error_offset(sqlite3 *db); +/* +** CAPI3REF: Set Error Code And Message +** METHOD: sqlite3 +** +** Set the error code of the database handle passed as the first argument +** to errcode, and the error message to a copy of nul-terminated string +** zErrMsg. If zErrMsg is passed NULL, then the error message is set to +** the default message associated with the supplied error code. Subsequent +** calls to [sqlite3_errcode()] and [sqlite3_errmsg()] and similar will +** return the values set by this routine in place of what was previously +** set by SQLite itself. +** +** This function returns SQLITE_OK if the error code and error message are +** successfully set, SQLITE_NOMEM if an OOM occurs, and SQLITE_MISUSE if +** the database handle is NULL or invalid. +** +** The error code and message set by this routine remains in effect until +** they are changed, either by another call to this routine or until they are +** changed to by SQLite itself to reflect the result of some subsquent +** API call. +** +** This function is intended for use by SQLite extensions or wrappers. The +** idea is that an extension or wrapper can use this routine to set error +** messages and error codes and thus behave more like a core SQLite +** feature from the point of view of an application. +*/ +SQLITE_API int sqlite3_set_errmsg(sqlite3 *db, int errcode, const char *zErrMsg); + /* ** CAPI3REF: Prepared Statement Object ** KEYWORDS: {prepared statement} {prepared statements} @@ -264943,8 +274459,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** These constants define various performance limits ** that can be lowered at run-time using [sqlite3_limit()]. -** The synopsis of the meanings of the various limits is shown below. -** Additional information is available at [limits | Limits in SQLite]. +** A concise description of these limits follows, and additional information +** is available at [limits | Limits in SQLite]. ** **
    ** [[SQLITE_LIMIT_LENGTH]] ^(
    SQLITE_LIMIT_LENGTH
    @@ -264959,7 +274475,12 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** or in an ORDER BY or GROUP BY clause.
    )^ ** ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
    SQLITE_LIMIT_EXPR_DEPTH
    -**
    The maximum depth of the parse tree on any expression.
    )^ +**
    The maximum depth of the parse tree on any expression and +** the maximum nesting depth for subqueries and VIEWs
    )^ +** +** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(
    SQLITE_LIMIT_PARSER_DEPTH
    +**
    The maximum depth of the LALR(1) parser stack used to analyze +** input SQL statements.
    )^ ** ** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(
    SQLITE_LIMIT_COMPOUND_SELECT
    **
    The maximum number of terms in a compound SELECT statement.
    )^ @@ -264986,7 +274507,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); **
    The maximum index number of any [parameter] in an SQL statement.)^ ** ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
    SQLITE_LIMIT_TRIGGER_DEPTH
    -**
    The maximum depth of recursion for triggers.
    )^ +**
    The maximum depth of recursion for triggers, and the maximum +** nesting depth for separate triggers.
    )^ ** ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
    SQLITE_LIMIT_WORKER_THREADS
    **
    The maximum number of auxiliary worker threads that a single @@ -265005,11 +274527,12 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +#define SQLITE_LIMIT_PARSER_DEPTH 12 /* ** CAPI3REF: Prepare Flags ** -** These constants define various flags that can be passed into +** These constants define various flags that can be passed into the ** "prepFlags" parameter of the [sqlite3_prepare_v3()] and ** [sqlite3_prepare16_v3()] interfaces. ** @@ -265039,11 +274562,39 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); **
    The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler ** to return an error (error code SQLITE_ERROR) if the statement uses ** any virtual tables. +** +** [[SQLITE_PREPARE_DONT_LOG]]
    SQLITE_PREPARE_DONT_LOG
    +**
    The SQLITE_PREPARE_DONT_LOG flag prevents SQL compiler +** errors from being sent to the error log defined by +** [SQLITE_CONFIG_LOG]. This can be used, for example, to do test +** compiles to see if some SQL syntax is well-formed, without generating +** messages on the global error log when it is not. If the test compile +** fails, the sqlite3_prepare_v3() call returns the same error indications +** with or without this flag; it just omits the call to [sqlite3_log()] that +** logs the error. +** +** [[SQLITE_PREPARE_FROM_DDL]]
    SQLITE_PREPARE_FROM_DDL
    +**
    The SQLITE_PREPARE_FROM_DDL flag causes the SQL compiler to enforce +** security constraints that would otherwise only be enforced when parsing +** the database schema. In other words, the SQLITE_PREPARE_FROM_DDL flag +** causes the SQL compiler to treat the SQL statement being prepared as if +** it had come from an attacker. When SQLITE_PREPARE_FROM_DDL is used and +** [SQLITE_DBCONFIG_TRUSTED_SCHEMA] is off, SQL functions may only be called +** if they are tagged with [SQLITE_INNOCUOUS] and virtual tables may only +** be used if they are tagged with [SQLITE_VTAB_INNOCUOUS]. Best practice +** is to use the SQLITE_PREPARE_FROM_DDL option when preparing any SQL that +** is derived from parts of the database schema. In particular, virtual +** table implementations that run SQL statements that are derived from +** arguments to their CREATE VIRTUAL TABLE statement should always use +** [sqlite3_prepare_v3()] and set the SQLITE_PREPARE_FROM_DDL flag to +** prevent bypass of the [SQLITE_DBCONFIG_TRUSTED_SCHEMA] security checks. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 #define SQLITE_PREPARE_NORMALIZE 0x02 #define SQLITE_PREPARE_NO_VTAB 0x04 +#define SQLITE_PREPARE_DONT_LOG 0x10 +#define SQLITE_PREPARE_FROM_DDL 0x20 /* ** CAPI3REF: Compiling An SQL Statement @@ -265057,8 +274608,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** The preferred routine to use is [sqlite3_prepare_v2()]. The ** [sqlite3_prepare()] interface is legacy and should be avoided. -** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used -** for special purposes. +** [sqlite3_prepare_v3()] has an extra +** [SQLITE_PREPARE_FROM_DDL|"prepFlags" option] that is sometimes +** needed for special purpose or to pass along security restrictions. ** ** The use of the UTF-8 interfaces is preferred, as SQLite currently ** does all parsing using UTF-8. The UTF-16 interfaces are provided @@ -265085,7 +274637,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** there is a small performance advantage to passing an nByte parameter that ** is the number of bytes in the input string including ** the nul-terminator. -** Note that nByte measure the length of the input in bytes, not +** Note that nByte measures the length of the input in bytes, not ** characters, even for the UTF-16 interfaces. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte @@ -265219,7 +274771,7 @@ SQLITE_API int sqlite3_prepare16_v3( ** ** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory ** is available to hold the result, or if the result would exceed the -** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. +** maximum string length determined by the [SQLITE_LIMIT_LENGTH]. ** ** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time @@ -265407,7 +274959,7 @@ typedef struct sqlite3_value sqlite3_value; ** ** The context in which an SQL function executes is stored in an ** sqlite3_context object. ^A pointer to an sqlite3_context object -** is always first parameter to [application-defined SQL functions]. +** is always the first parameter to [application-defined SQL functions]. ** The application-defined SQL function implementation will pass this ** pointer through into calls to [sqlite3_result_int | sqlite3_result()], ** [sqlite3_aggregate_context()], [sqlite3_user_data()], @@ -265423,7 +274975,7 @@ typedef struct sqlite3_context sqlite3_context; ** METHOD: sqlite3_stmt ** ** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants, -** literals may be replaced by a [parameter] that matches one of following +** literals may be replaced by a [parameter] that matches one of the following ** templates: ** **
      @@ -265463,12 +275015,12 @@ typedef struct sqlite3_context sqlite3_context; ** it should be a pointer to well-formed UTF16 text. ** ^If the third parameter to sqlite3_bind_text64() is not NULL, then ** it should be a pointer to a well-formed unicode string that is -** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16 -** otherwise. +** either UTF8 if the sixth parameter is SQLITE_UTF8 or SQLITE_UTF8_ZT, +** or UTF16 otherwise. ** ** [[byte-order determination rules]] ^The byte-order of ** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF) -** found in first character, which is removed, or in the absence of a BOM +** found in the first character, which is removed, or in the absence of a BOM ** the byte order is the native byte order of the host ** machine for sqlite3_bind_text16() or the byte order specified in ** the 6th parameter for sqlite3_bind_text64().)^ @@ -265488,7 +275040,7 @@ typedef struct sqlite3_context sqlite3_context; ** or sqlite3_bind_text16() or sqlite3_bind_text64() then ** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL -** terminated. If any NUL characters occurs at byte offsets less than +** terminated. If any NUL characters occur at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. @@ -265510,10 +275062,15 @@ typedef struct sqlite3_context sqlite3_context; ** object and pointer to it must remain valid until then. ^SQLite will then ** manage the lifetime of its private copy. ** -** ^The sixth argument to sqlite3_bind_text64() must be one of -** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] -** to specify the encoding of the text in the third parameter. If -** the sixth argument to sqlite3_bind_text64() is not one of the +** ^The sixth argument (the E argument) +** to sqlite3_bind_text64(S,K,Z,N,D,E) must be one of +** [SQLITE_UTF8], [SQLITE_UTF8_ZT], [SQLITE_UTF16], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE] to specify the encoding of the text in the +** third parameter, Z. The special value [SQLITE_UTF8_ZT] means that the +** string argument is both UTF-8 encoded and is zero-terminated. In other +** words, SQLITE_UTF8_ZT means that the Z array is allocated to hold at +** least N+1 bytes and that the Z[N] byte is zero. If +** the E argument to sqlite3_bind_text64(S,K,Z,N,D,E) is not one of the ** allowed values shown above, or if the text encoding is different ** from the encoding specified by the sixth parameter, then the behavior ** is undefined. @@ -265531,9 +275088,11 @@ typedef struct sqlite3_context sqlite3_context; ** associated with the pointer P of type T. ^D is either a NULL pointer or ** a pointer to a destructor function for P. ^SQLite will invoke the ** destructor D with a single argument of P when it is finished using -** P. The T parameter should be a static string, preferably a string -** literal. The sqlite3_bind_pointer() routine is part of the -** [pointer passing interface] added for SQLite 3.20.0. +** P, even if the call to sqlite3_bind_pointer() fails. Due to a +** historical design quirk, results are undefined if D is +** SQLITE_TRANSIENT. The T parameter should be a static string, +** preferably a string literal. The sqlite3_bind_pointer() routine is +** part of the [pointer passing interface] added for SQLite 3.20.0. ** ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer ** for the [prepared statement] or with a prepared statement for which @@ -265700,7 +275259,7 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); ** METHOD: sqlite3_stmt ** ** ^These routines provide a means to determine the database, table, and -** table column that is the origin of a particular result column in +** table column that is the origin of a particular result column in a ** [SELECT] statement. ** ^The name of the database or table or column can be returned as ** either a UTF-8 or UTF-16 string. ^The _database_ routines return @@ -265838,7 +275397,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from -** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], +** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]), ** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility @@ -266144,7 +275703,7 @@ SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); ** ** ^The sqlite3_finalize() function is called to delete a [prepared statement]. ** ^If the most recent evaluation of the statement encountered no errors -** or if the statement is never been evaluated, then sqlite3_finalize() returns +** or if the statement has never been evaluated, then sqlite3_finalize() returns ** SQLITE_OK. ^If the most recent evaluation of statement S failed, then ** sqlite3_finalize(S) returns the appropriate [error code] or ** [extended error code]. @@ -266269,8 +275828,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** ** For best security, the [SQLITE_DIRECTONLY] flag is recommended for ** all application-defined SQL functions that do not need to be -** used inside of triggers, view, CHECK constraints, or other elements of -** the database schema. This flags is especially recommended for SQL +** used inside of triggers, views, CHECK constraints, or other elements of +** the database schema. This flag is especially recommended for SQL ** functions that have side effects or reveal internal application state. ** Without this flag, an attacker might be able to modify the schema of ** a database file to include invocations of the function with parameters @@ -266301,7 +275860,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** [user-defined window functions|available here]. ** ** ^(If the final parameter to sqlite3_create_function_v2() or -** sqlite3_create_window_function() is not NULL, then it is destructor for +** sqlite3_create_window_function() is not NULL, then it is the destructor for ** the application data pointer. The destructor is invoked when the function ** is deleted, either by being overloaded or when the database connection ** closes.)^ ^The destructor is also invoked if the call to @@ -266376,8 +275935,54 @@ SQLITE_API int sqlite3_create_window_function( /* ** CAPI3REF: Text Encodings ** -** These constant define integer codes that represent the various +** These constants define integer codes that represent the various ** text encodings supported by SQLite. +** +**
      +** [[SQLITE_UTF8]]
      SQLITE_UTF8
      Text is encoding as UTF-8
      +** +** [[SQLITE_UTF16LE]]
      SQLITE_UTF16LE
      Text is encoding as UTF-16 +** with each code point being expressed "little endian" - the least significant +** byte first. This is the usual encoding, for example on Windows.
      +** +** [[SQLITE_UTF16BE]]
      SQLITE_UTF16BE
      Text is encoding as UTF-16 +** with each code point being expressed "big endian" - the most significant +** byte first. This encoding is less common, but is still sometimes seen, +** specially on older systems. +** +** [[SQLITE_UTF16]]
      SQLITE_UTF16
      Text is encoding as UTF-16 +** with each code point being expressed either little endian or as big +** endian, according to the native endianness of the host computer. +** +** [[SQLITE_ANY]]
      SQLITE_ANY
      This encoding value may only be used +** to declare the preferred text for [application-defined SQL functions] +** created using [sqlite3_create_function()] and similar. If the preferred +** encoding (the 4th parameter to sqlite3_create_function() - the eTextRep +** parameter) is SQLITE_ANY, that indicates that the function does not have +** a preference regarding the text encoding of its parameters and can take +** any text encoding that the SQLite core find convenient to supply. This +** option is deprecated. Please do not use it in new applications. +** +** [[SQLITE_UTF16_ALIGNED]]
      SQLITE_UTF16_ALIGNED
      This encoding +** value may be used as the 3rd parameter (the eTextRep parameter) to +** [sqlite3_create_collation()] and similar. This encoding value means +** that the application-defined collating sequence created expects its +** input strings to be in UTF16 in native byte order, and that the start +** of the strings must be aligned to a 2-byte boundary. +** +** [[SQLITE_UTF8_ZT]]
      SQLITE_UTF8_ZT
      This option can only be +** used to specify the text encoding to strings input to +** [sqlite3_result_text64()] and [sqlite3_bind_text64()]. +** The SQLITE_UTF8_ZT encoding means that the input string (call it "z") +** is UTF-8 encoded and that it is zero-terminated. If the length parameter +** (call it "n") is non-negative, this encoding option means that the caller +** guarantees that z array contains at least n+1 bytes and that the z[n] +** byte has a value of zero. +** This option gives the same output as SQLITE_UTF8, but can be more efficient +** by avoiding the need to make a copy of the input string, in some cases. +** However, if z is allocated to hold fewer than n+1 bytes or if the +** z[n] byte is not zero, undefined behavior may result. +**
      */ #define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ #define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ @@ -266385,6 +275990,7 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* Deprecated */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ +#define SQLITE_UTF8_ZT 16 /* Zero-terminated UTF8 */ /* ** CAPI3REF: Function Flags @@ -266468,7 +276074,7 @@ SQLITE_API int sqlite3_create_window_function( ** result. ** Every function that invokes [sqlite3_result_subtype()] should have this ** property. If it does not, then the call to [sqlite3_result_subtype()] -** might become a no-op if the function is used as term in an +** might become a no-op if the function is used as a term in an ** [expression index]. On the other hand, SQL functions that never invoke ** [sqlite3_result_subtype()] should avoid setting this property, as the ** purpose of this property is to disable certain optimizations that are @@ -266595,7 +276201,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** sqlite3_value_nochange(X) interface returns true if and only if ** the column corresponding to X is unchanged by the UPDATE operation ** that the xUpdate method call was invoked to implement and if -** and the prior [xColumn] method call that was invoked to extracted +** the prior [xColumn] method call that was invoked to extract ** the value for that column returned without setting a result (probably ** because it queried [sqlite3_vtab_nochange()] and found that the column ** was unchanging). ^Within an [xUpdate] method, any value for which @@ -266619,26 +276225,22 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** the SQL function that supplied the [sqlite3_value*] parameters. ** ** As long as the input parameter is correct, these routines can only -** fail if an out-of-memory error occurs during a format conversion. -** Only the following subset of interfaces are subject to out-of-memory -** errors: -** -**
        -**
      • sqlite3_value_blob() -**
      • sqlite3_value_text() -**
      • sqlite3_value_text16() -**
      • sqlite3_value_text16le() -**
      • sqlite3_value_text16be() -**
      • sqlite3_value_bytes() -**
      • sqlite3_value_bytes16() -**
      -** +** fail if an out-of-memory error occurs while trying to do a +** UTF8→UTF16 or UTF16→UTF8 conversion. ** If an out-of-memory error occurs, then the return value from these ** routines is the same as if the column had contained an SQL NULL value. -** Valid SQL NULL returns can be distinguished from out-of-memory errors -** by invoking the [sqlite3_errcode()] immediately after the suspect +** If the input sqlite3_value was not obtained from [sqlite3_value_dup()], +** then valid SQL NULL returns can also be distinguished from +** out-of-memory errors after extracting the value +** by invoking the [sqlite3_errcode()] immediately after the suspicious ** return value is obtained and before any ** other SQLite interface is called on the same [database connection]. +** If the input sqlite3_value was obtained from sqlite3_value_dup() then +** it is disconnected from the database connection and so sqlite3_errcode() +** will not work. +** In that case, the only way to distinguish an out-of-memory +** condition from a true SQL NULL is to invoke sqlite3_value_type() on the +** input to see if it is NULL prior to trying to extract the value. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); @@ -266665,7 +276267,8 @@ SQLITE_API int sqlite3_value_frombind(sqlite3_value*); ** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X) ** returns something other than SQLITE_TEXT, then the return value from ** sqlite3_value_encoding(X) is meaningless. ^Calls to -** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)], +** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], +** [sqlite3_value_text16be(X)], ** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or ** [sqlite3_value_bytes16(X)] might change the encoding of the value X and ** thus change the return from subsequent calls to sqlite3_value_encoding(X). @@ -266701,7 +276304,7 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); ** METHOD: sqlite3_value ** ** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value] -** object D and returns a pointer to that copy. ^The [sqlite3_value] returned +** object V and returns a pointer to that copy. ^The [sqlite3_value] returned ** is a [protected sqlite3_value] object even if the input is not. ** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a ** memory allocation fails. ^If V is a [pointer value], then the result @@ -266739,7 +276342,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*); ** allocation error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is -** determined by the N parameter on first successful call. Changing the +** determined by the N parameter on the first successful call. Changing the ** value of N in any subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory ** allocation.)^ Within the xFinal callback, it is customary to set @@ -266796,17 +276399,17 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** query execution, under some circumstances the associated auxiliary data ** might be preserved. An example of where this might be useful is in a ** regular-expression matching function. The compiled version of the regular -** expression can be stored as auxiliary data associated with the pattern string. -** Then as long as the pattern string remains the same, +** expression can be stored as auxiliary data associated with the pattern +** string. Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data -** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument -** value to the application-defined function. ^N is zero for the left-most -** function argument. ^If there is no auxiliary data -** associated with the function argument, the sqlite3_get_auxdata(C,N) interface -** returns a NULL pointer. +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary +** data associated by the sqlite3_set_auxdata(C,N,P,X) function with the +** Nth argument value to the application-defined function. ^N is zero +** for the left-most function argument. ^If there is no auxiliary data +** associated with the function argument, the sqlite3_get_auxdata(C,N) +** interface returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the ** N-th argument of the application-defined function. ^Subsequent @@ -266868,6 +276471,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi ** or a NULL pointer if there were no prior calls to ** sqlite3_set_clientdata() with the same values of D and N. ** Names are compared using strcmp() and are thus case sensitive. +** It returns 0 on success and SQLITE_NOMEM on allocation failure. ** ** If P and X are both non-NULL, then the destructor X is invoked with ** argument P on the first of the following occurrences: @@ -266889,10 +276493,14 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi ** ** There is no limit (other than available memory) on the number of different ** client data pointers (with different names) that can be attached to a -** single database connection. However, the implementation is optimized -** for the case of having only one or two different client data names. -** Applications and wrapper libraries are discouraged from using more than -** one client data name each. +** single database connection. However, the current implementation stores +** the content on a linked list. Insert and retrieval performance will +** be proportional to the number of entries. The design use case, and +** the use case for which the implementation is optimized, is +** that an application will store only small number of client data names, +** typically just one or two. This interface is not intended to be a +** generalized key/value store for thousands or millions of keys. It +** will work for that, but performance might be disappointing. ** ** There is no way to enumerate the client data pointers ** associated with a database connection. The N parameter can be thought @@ -266901,7 +276509,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi ** ** Security Warning: These interfaces should not be exposed in scripting ** languages or in other circumstances where it might be possible for an -** an attacker to invoke them. Any agent that can invoke these interfaces +** attacker to invoke them. Any agent that can invoke these interfaces ** can probably also take control of the process. ** ** Database connection client data is only available for SQLite @@ -267000,10 +276608,14 @@ typedef void (*sqlite3_destructor_type)(void*); ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. -** ^The sqlite3_result_text64() interface sets the return value of an +** ^The sqlite3_result_text64(C,Z,N,D,E) interface sets the return value of an ** application-defined function to be a text string in an encoding -** specified by the fifth (and last) parameter, which must be one -** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. +** specified the E parameter, which must be one +** of [SQLITE_UTF8], [SQLITE_UTF8_ZT], [SQLITE_UTF16], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE]. ^The special value [SQLITE_UTF8_ZT] means that +** the result text is both UTF-8 and zero-terminated. In other words, +** SQLITE_UTF8_ZT means that the Z array holds at least N+1 bytes and that +** the Z[N] is zero. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to any of the sqlite3_result_text* interfaces @@ -267015,7 +276627,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** pointed to by the 2nd parameter are taken as the application-defined ** function result. If the 3rd parameter is non-negative, then it ** must be the byte offset into the string where the NUL terminator would -** appear if the string where NUL terminated. If any NUL characters occur +** appear if the string were NUL terminated. If any NUL characters occur ** in the string at a byte offset that is less than the value of the 3rd ** parameter, then the resulting string will contain embedded NULs and the ** result of expressions operating on strings with embedded NULs is undefined. @@ -267073,7 +276685,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** string and preferably a string literal. The sqlite3_result_pointer() ** routine is part of the [pointer passing interface] added for SQLite 3.20.0. ** -** If these routines are called from within the different thread +** If these routines are called from within a different thread ** than the one containing the application-defined function that received ** the [sqlite3_context] pointer, the results are undefined. */ @@ -267090,7 +276702,7 @@ SQLITE_API void sqlite3_result_int(sqlite3_context*, int); SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); SQLITE_API void sqlite3_result_null(sqlite3_context*); SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); -SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, +SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char *z, sqlite3_uint64 n, void(*)(void*), unsigned char encoding); SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); @@ -267479,7 +277091,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); ** METHOD: sqlite3 ** ** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name -** for the N-th database on database connection D, or a NULL pointer of N is +** for the N-th database on database connection D, or a NULL pointer if N is ** out of range. An N value of 0 means the main database file. An N of 1 is ** the "temp" schema. Larger values of N correspond to various ATTACH-ed ** databases. @@ -267574,7 +277186,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); **
      The SQLITE_TXN_READ state means that the database is currently ** in a read transaction. Content has been read from the database file ** but nothing in the database file has changed. The transaction state -** will advanced to SQLITE_TXN_WRITE if any changes occur and there are +** will be advanced to SQLITE_TXN_WRITE if any changes occur and there are ** no other conflicting concurrent write transactions. The transaction ** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or ** [COMMIT].
      @@ -267583,7 +277195,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); **
      The SQLITE_TXN_WRITE state means that the database is currently ** in a write transaction. Content has been written to the database file ** but has not yet committed. The transaction state will change to -** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
      +** SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
    */ #define SQLITE_TXN_NONE 0 #define SQLITE_TXN_READ 1 @@ -267734,6 +277346,8 @@ SQLITE_API int sqlite3_autovacuum_pages( ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. +** ^The update hook is disabled by invoking sqlite3_update_hook() +** with a NULL pointer as the second parameter. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], @@ -267862,7 +277476,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); ** CAPI3REF: Impose A Limit On Heap Size ** ** These interfaces impose limits on the amount of heap memory that will be -** by all database connections within a single process. +** used by all database connections within a single process. ** ** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the ** soft limit on the amount of heap memory that may be allocated by SQLite. @@ -267920,7 +277534,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); ** )^ ** ** The circumstances under which SQLite will enforce the heap limits may -** changes in future releases of SQLite. +** change in future releases of SQLite. */ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N); @@ -268027,7 +277641,7 @@ SQLITE_API int sqlite3_table_column_metadata( ** ^The sqlite3_load_extension() interface attempts to load an ** [SQLite extension] library contained in the file zFile. If ** the file cannot be loaded directly, attempts are made to load -** with various operating-system specific extensions added. +** with various operating-system specific filename extensions added. ** So for example, if "samplelib" cannot be loaded, then names like ** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might ** be tried also. @@ -268035,10 +277649,10 @@ SQLITE_API int sqlite3_table_column_metadata( ** ^The entry point is zProc. ** ^(zProc may be 0, in which case SQLite will try to come up with an ** entry point name on its own. It first tries "sqlite3_extension_init". -** If that does not work, it constructs a name "sqlite3_X_init" where the -** X is consists of the lower-case equivalent of all ASCII alphabetic -** characters in the filename from the last "/" to the first following -** "." and omitting any initial "lib".)^ +** If that does not work, it tries names of the form "sqlite3_X_init" +** where X consists of the lower-case equivalent of all ASCII alphabetic +** characters or all ASCII alphanumeric characters in the filename from +** the last "/" to the first following "." and omitting any initial "lib".)^ ** ^The sqlite3_load_extension() interface returns ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. ** ^If an error occurs and pzErrMsg is not 0, then the @@ -268107,12 +277721,12 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three ** arguments and expects an integer result as if the signature of the -** entry point where as follows: +** entry point were as follows: ** **
     **    int xEntryPoint(
     **      sqlite3 *db,
    -**      const char **pzErrMsg,
    +**      char **pzErrMsg,
     **      const struct sqlite3_api_routines *pThunk
     **    );
     ** 
    )^ @@ -268271,7 +277885,7 @@ struct sqlite3_module { ** virtual table and might not be checked again by the byte code.)^ ^(The ** aConstraintUsage[].omit flag is an optimization hint. When the omit flag ** is left in its default setting of false, the constraint will always be -** checked separately in byte code. If the omit flag is change to true, then +** checked separately in byte code. If the omit flag is changed to true, then ** the constraint may or may not be checked in byte code. In other words, ** when the omit flag is true there is no guarantee that the constraint will ** not be checked again using byte code.)^ @@ -268297,7 +277911,7 @@ struct sqlite3_module { ** The xBestIndex method may optionally populate the idxFlags field with a ** mask of SQLITE_INDEX_SCAN_* flags. One such flag is ** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN] -** output to show the idxNum has hex instead of as decimal. Another flag is +** output to show the idxNum as hex instead of as decimal. Another flag is ** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will ** return at most one row. ** @@ -268438,7 +278052,7 @@ struct sqlite3_index_info { ** the implementation of the [virtual table module]. ^The fourth ** parameter is an arbitrary client data pointer that is passed through ** into the [xCreate] and [xConnect] methods of the virtual table module -** when a new virtual table is be being created or reinitialized. +** when a new virtual table is being created or reinitialized. ** ** ^The sqlite3_create_module_v2() interface has a fifth parameter which ** is a pointer to a destructor for the pClientData. ^SQLite will @@ -268603,7 +278217,7 @@ typedef struct sqlite3_blob sqlite3_blob; ** in *ppBlob. Otherwise an [error code] is returned and, unless the error ** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided ** the API is not misused, it is always safe to call [sqlite3_blob_close()] -** on *ppBlob after this function it returns. +** on *ppBlob after this function returns. ** ** This function fails with SQLITE_ERROR if any of the following are true: **
      @@ -268723,7 +278337,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *); ** ** ^Returns the size in bytes of the BLOB accessible via the ** successfully opened [BLOB handle] in its only argument. ^The -** incremental blob I/O routines can only read or overwriting existing +** incremental blob I/O routines can only read or overwrite existing ** blob content; they cannot change the size of a blob. ** ** This routine only works on a [BLOB handle] which has been created @@ -268862,18 +278476,11 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); ** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix ** and Windows. ** -** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor -** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex -** implementation is included with the library. In this case the -** application must supply a custom mutex implementation using the -** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function -** before calling sqlite3_initialize() or any other public sqlite3_ -** function that calls sqlite3_initialize(). ** ** ^The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc() ** routine returns NULL if it is unable to allocate the requested -** mutex. The argument to sqlite3_mutex_alloc() must one of these +** mutex. The argument to sqlite3_mutex_alloc() must be one of these ** integer constants: ** **
        @@ -269106,7 +278713,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); ** CAPI3REF: Retrieve the mutex for a database connection ** METHOD: sqlite3 ** -** ^This interface returns a pointer the [sqlite3_mutex] object that +** ^This interface returns a pointer to the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument ** when the [threading mode] is Serialized. ** ^If the [threading mode] is Single-thread or Multi-thread then this @@ -269223,13 +278830,14 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */ +#define SQLITE_TESTCTRL_ATOF 34 #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking ** ** These routines provide access to the set of SQL language keywords -** recognized by SQLite. Applications can uses these routines to determine +** recognized by SQLite. Applications can use these routines to determine ** whether or not a specific identifier needs to be escaped (for example, ** by enclosing in double-quotes) so as not to confuse the parser. ** @@ -269331,17 +278939,22 @@ SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); ** pass the returned value to [sqlite3_free()] to avoid a memory leak. ** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any ** errors were encountered during construction of the string. ^The -** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the +** [sqlite3_str_finish(X)] interface might also return a NULL pointer if the ** string in [sqlite3_str] object X is zero bytes long. +** +** ^The [sqlite3_str_free(X)] interface destroys both the sqlite3_str object +** X and the string content it contains. Calling sqlite3_str_free(X) is +** the equivalent of calling [sqlite3_free](sqlite3_str_finish(X)). */ SQLITE_API char *sqlite3_str_finish(sqlite3_str*); +SQLITE_API void sqlite3_str_free(sqlite3_str*); /* ** CAPI3REF: Add Content To A Dynamic String ** METHOD: sqlite3_str ** -** These interfaces add content to an sqlite3_str object previously obtained -** from [sqlite3_str_new()]. +** These interfaces add or remove content to an sqlite3_str object +** previously obtained from [sqlite3_str_new()]. ** ** ^The [sqlite3_str_appendf(X,F,...)] and ** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] @@ -269364,6 +278977,10 @@ SQLITE_API char *sqlite3_str_finish(sqlite3_str*); ** ^The [sqlite3_str_reset(X)] method resets the string under construction ** inside [sqlite3_str] object X back to zero bytes in length. ** +** ^The [sqlite3_str_truncate(X,N)] method changes the length of the string +** under construction to be N bytes or less. This routine is a no-op if +** N is negative or if the string is already N bytes or smaller in size. +** ** These methods do not return a result code. ^If an error occurs, that fact ** is recorded in the [sqlite3_str] object and can be recovered by a ** subsequent call to [sqlite3_str_errcode(X)]. @@ -269374,6 +278991,7 @@ SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn); SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); SQLITE_API void sqlite3_str_reset(sqlite3_str*); +SQLITE_API void sqlite3_str_truncate(sqlite3_str*,int N); /* ** CAPI3REF: Status Of A Dynamic String @@ -269397,7 +279015,7 @@ SQLITE_API void sqlite3_str_reset(sqlite3_str*); ** content of the dynamic string under construction in X. The value ** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X ** and might be freed or altered by any subsequent method on the same -** [sqlite3_str] object. Applications must not used the pointer returned +** [sqlite3_str] object. Applications must not use the pointer returned by ** [sqlite3_str_value(X)] after any subsequent method call on the same ** object. ^Applications may change the content of the string returned ** by [sqlite3_str_value(X)] as long as they do not write into any bytes @@ -269483,7 +279101,7 @@ SQLITE_API int sqlite3_status64( ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] ** buffer and where forced to overflow to [sqlite3_malloc()]. The ** returned value includes allocations that overflowed because they -** where too large (they were larger than the "sz" parameter to +** were too large (they were larger than the "sz" parameter to ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because ** no space was left in the page cache.)^ ** @@ -269542,9 +279160,18 @@ SQLITE_API int sqlite3_status64( ** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a ** non-zero [error code] on failure. ** +** ^The sqlite3_db_status64(D,O,C,H,R) routine works exactly the same +** way as sqlite3_db_status(D,O,C,H,R) routine except that the C and H +** parameters are pointer to 64-bit integers (type: sqlite3_int64) instead +** of pointers to 32-bit integers, which allows larger status values +** to be returned. If a status value exceeds 2,147,483,647 then +** sqlite3_db_status() will truncate the value whereas sqlite3_db_status64() +** will return the full value. +** ** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. */ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); +SQLITE_API int sqlite3_db_status64(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int); /* ** CAPI3REF: Status Parameters for database connections @@ -269567,28 +279194,29 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(
        SQLITE_DBSTATUS_LOOKASIDE_HIT
        **
        This parameter returns the number of malloc attempts that were ** satisfied using lookaside memory. Only the high-water value is meaningful; -** the current value is always zero.)^ +** the current value is always zero.
        )^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] ** ^(
        SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
        -**
        This parameter returns the number malloc attempts that might have +**
        This parameter returns the number of malloc attempts that might have ** been satisfied using lookaside memory but failed due to the amount of ** memory requested being larger than the lookaside slot size. ** Only the high-water value is meaningful; -** the current value is always zero.)^ +** the current value is always zero.
        )^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] ** ^(
        SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
        -**
        This parameter returns the number malloc attempts that might have +**
        This parameter returns the number of malloc attempts that might have ** been satisfied using lookaside memory but failed due to all lookaside ** memory already being in use. ** Only the high-water value is meaningful; -** the current value is always zero.)^ +** the current value is always zero.
        )^ ** ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
        SQLITE_DBSTATUS_CACHE_USED
        **
        This parameter returns the approximate number of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. +**
        ** ** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] ** ^(
        SQLITE_DBSTATUS_CACHE_USED_SHARED
        @@ -269597,10 +279225,10 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** memory used by that pager cache is divided evenly between the attached ** connections.)^ In other words, if none of the pager caches associated ** with the database connection are shared, this request returns the same -** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are +** value as DBSTATUS_CACHE_USED. Or, if one or more of the pager caches are ** shared, the value returned by this call will be smaller than that returned ** by DBSTATUS_CACHE_USED. ^The highwater mark associated with -** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. +** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. ** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
        SQLITE_DBSTATUS_SCHEMA_USED
        **
        This parameter returns the approximate number of bytes of heap @@ -269610,6 +279238,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** schema memory is shared with other database connections due to ** [shared cache mode] being enabled. ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. +**
        ** ** [[SQLITE_DBSTATUS_STMT_USED]] ^(
        SQLITE_DBSTATUS_STMT_USED
        **
        This parameter returns the approximate number of bytes of heap @@ -269639,6 +279268,10 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** If an IO or other error occurs while writing a page to disk, the effect ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. +**

        +** ^(There is overlap between the quantities measured by this parameter +** (SQLITE_DBSTATUS_CACHE_WRITE) and SQLITE_DBSTATUS_TEMPBUF_SPILL. +** Resetting one will reduce the other.)^ **

        ** ** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(
        SQLITE_DBSTATUS_CACHE_SPILL
        @@ -269646,7 +279279,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** been written to disk in the middle of a transaction due to the page ** cache overflowing. Transactions are more efficient if they are written ** to disk all at once. When pages spill mid-transaction, that introduces -** additional overhead. This parameter can be used help identify +** additional overhead. This parameter can be used to help identify ** inefficiencies that can be resolved by increasing the cache size. ** ** @@ -269654,6 +279287,18 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r **
        This parameter returns zero for the current value if and only if ** all foreign key constraints (deferred or immediate) have been ** resolved.)^ ^The highwater mark is always 0. +** +** [[SQLITE_DBSTATUS_TEMPBUF_SPILL] ^(
        SQLITE_DBSTATUS_TEMPBUF_SPILL
        +**
        ^(This parameter returns the number of bytes written to temporary +** files on disk that could have been kept in memory had sufficient memory +** been available. This value includes writes to intermediate tables that +** are part of complex queries, external sorts that spill to disk, and +** writes to TEMP tables.)^ +** ^The highwater mark is always 0. +**

        +** ^(There is overlap between the quantities measured by this parameter +** (SQLITE_DBSTATUS_TEMPBUF_SPILL) and SQLITE_DBSTATUS_CACHE_WRITE. +** Resetting one will reduce the other.)^ **

        ** */ @@ -269670,7 +279315,8 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r #define SQLITE_DBSTATUS_DEFERRED_FKS 10 #define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 #define SQLITE_DBSTATUS_CACHE_SPILL 12 -#define SQLITE_DBSTATUS_MAX 12 /* Largest defined DBSTATUS */ +#define SQLITE_DBSTATUS_TEMPBUF_SPILL 13 +#define SQLITE_DBSTATUS_MAX 13 /* Largest defined DBSTATUS */ /* @@ -269717,13 +279363,13 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** [[SQLITE_STMTSTATUS_SORT]]
        SQLITE_STMTSTATUS_SORT
        **
        ^This is the number of sort operations that have occurred. ** A non-zero value in this counter may indicate an opportunity to -** improvement performance through careful use of indices.
        +** improve performance through careful use of indices. ** ** [[SQLITE_STMTSTATUS_AUTOINDEX]]
        SQLITE_STMTSTATUS_AUTOINDEX
        **
        ^This is the number of rows inserted into transient indices that ** were created automatically in order to help joins run faster. ** A non-zero value in this counter may indicate an opportunity to -** improvement performance by adding permanent indices that do not +** improve performance by adding permanent indices that do not ** need to be reinitialized each time the statement is run.
        ** ** [[SQLITE_STMTSTATUS_VM_STEP]]
        SQLITE_STMTSTATUS_VM_STEP
        @@ -269732,19 +279378,19 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** to 2147483647. The number of virtual machine operations can be ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 -** then the value returned by this statement status code is undefined. +** then the value returned by this statement status code is undefined. ** ** [[SQLITE_STMTSTATUS_REPREPARE]]
        SQLITE_STMTSTATUS_REPREPARE
        **
        ^This is the number of times that the prepare statement has been ** automatically regenerated due to schema changes or changes to -** [bound parameters] that might affect the query plan. +** [bound parameters] that might affect the query plan.
        ** ** [[SQLITE_STMTSTATUS_RUN]]
        SQLITE_STMTSTATUS_RUN
        **
        ^This is the number of times that the prepared statement has ** been run. A single "run" for the purposes of this counter is one ** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()]. ** The counter is incremented on the first [sqlite3_step()] call of each -** cycle. +** cycle.
        ** ** [[SQLITE_STMTSTATUS_FILTER_MISS]] ** [[SQLITE_STMTSTATUS_FILTER HIT]] @@ -269754,7 +279400,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** step was bypassed because a Bloom filter returned not-found. The ** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of ** times that the Bloom filter returned a find, and thus the join step -** had to be processed as normal. +** had to be processed as normal. ** ** [[SQLITE_STMTSTATUS_MEMUSED]]
        SQLITE_STMTSTATUS_MEMUSED
        **
        ^This is the approximate number of bytes of heap memory @@ -269859,9 +279505,9 @@ struct sqlite3_pcache_page { ** SQLite will typically create one cache instance for each open database file, ** though this is not guaranteed. ^The ** first parameter, szPage, is the size in bytes of the pages that must -** be allocated by the cache. ^szPage will always a power of two. ^The +** be allocated by the cache. ^szPage will always be a power of two. ^The ** second parameter szExtra is a number of bytes of extra storage -** associated with each page cache entry. ^The szExtra parameter will +** associated with each page cache entry. ^The szExtra parameter will be ** a number less than 250. SQLite will use the ** extra szExtra bytes on each page to store metadata about the underlying ** database page on disk. The value passed into szExtra depends @@ -269869,17 +279515,17 @@ struct sqlite3_pcache_page { ** ^The third argument to xCreate(), bPurgeable, is true if the cache being ** created will be used to cache database pages of a file stored on disk, or ** false if it is used for an in-memory database. The cache implementation -** does not have to do anything special based with the value of bPurgeable; +** does not have to do anything special based upon the value of bPurgeable; ** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will ** never invoke xUnpin() except to deliberately delete a page. ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to ** false will always have the "discard" flag set to true. -** ^Hence, a cache created with bPurgeable false will +** ^Hence, a cache created with bPurgeable set to false will ** never contain any unpinned pages. ** ** [[the xCachesize() page cache method]] ** ^(The xCachesize() method may be called at any time by SQLite to set the -** suggested maximum cache-size (number of pages stored by) the cache +** suggested maximum cache-size (number of pages stored) for the cache ** instance passed as the first argument. This is the value configured using ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable ** parameter, the implementation is not required to do anything with this @@ -269906,12 +279552,12 @@ struct sqlite3_pcache_page { ** implementation must return a pointer to the page buffer with its content ** intact. If the requested page is not already in the cache, then the ** cache implementation should use the value of the createFlag -** parameter to help it determined what action to take: +** parameter to help it determine what action to take: ** ** ** **
        createFlag Behavior when page is not already in cache **
        0 Do not allocate a new page. Return NULL. -**
        1 Allocate a new page if it easy and convenient to do so. +**
        1 Allocate a new page if it is easy and convenient to do so. ** Otherwise return NULL. **
        2 Make every effort to allocate a new page. Only return ** NULL if allocating a new page is effectively impossible. @@ -269928,7 +279574,7 @@ struct sqlite3_pcache_page { ** as its second argument. If the third parameter, discard, is non-zero, ** then the page must be evicted from the cache. ** ^If the discard parameter is -** zero, then the page may be discarded or retained at the discretion of +** zero, then the page may be discarded or retained at the discretion of the ** page cache implementation. ^The page cache implementation ** may choose to evict unpinned pages at any time. ** @@ -269946,7 +279592,7 @@ struct sqlite3_pcache_page { ** When SQLite calls the xTruncate() method, the cache must discard all ** existing cache entries with page numbers (keys) greater than or equal ** to the value of the iLimit parameter passed to xTruncate(). If any -** of these pages are pinned, they are implicitly unpinned, meaning that +** of these pages are pinned, they become implicitly unpinned, meaning that ** they can be safely discarded. ** ** [[the xDestroy() page cache method]] @@ -270126,7 +279772,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** external process or via a database connection other than the one being ** used by the backup operation, then the backup will be automatically ** restarted by the next call to sqlite3_backup_step(). ^If the source -** database is modified by the using the same database connection as is used +** database is modified by using the same database connection as is used ** by the backup operation, then the backup database is automatically ** updated at the same time. ** @@ -270143,7 +279789,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** and may not be used following a call to sqlite3_backup_finish(). ** ** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no -** sqlite3_backup_step() errors occurred, regardless or whether or not +** sqlite3_backup_step() errors occurred, regardless of whether or not ** sqlite3_backup_step() completed. ** ^If an out-of-memory condition or IO error occurred during any prior ** sqlite3_backup_step() call on the same [sqlite3_backup] object, then @@ -270245,7 +279891,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** application receives an SQLITE_LOCKED error, it may call the ** sqlite3_unlock_notify() method with the blocked connection handle as ** the first argument to register for a callback that will be invoked -** when the blocking connections current transaction is concluded. ^The +** when the blocking connection's current transaction is concluded. ^The ** callback is invoked from within the [sqlite3_step] or [sqlite3_close] ** call that concludes the blocking connection's transaction. ** @@ -270265,7 +279911,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** blocked connection already has a registered unlock-notify callback, ** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is ** called with a NULL pointer as its second argument, then any existing -** unlock-notify callback is canceled. ^The blocked connections +** unlock-notify callback is canceled. ^The blocked connection's ** unlock-notify callback may also be canceled by closing the blocked ** connection using [sqlite3_close()]. ** @@ -270435,7 +280081,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); ** is the number of pages currently in the write-ahead log file, ** including those that were just committed. ** -** The callback function should normally return [SQLITE_OK]. ^If an error +** ^The callback function should normally return [SQLITE_OK]. ^If an error ** code is returned, that error will propagate back up through the ** SQLite code base to cause the statement that provoked the callback ** to report an error, though the commit will have still occurred. If the @@ -270443,13 +280089,26 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); ** that does not correspond to any valid SQLite error code, the results ** are undefined. ** -** A single database handle may have at most a single write-ahead log callback -** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any -** previously registered write-ahead log callback. ^The return value is -** a copy of the third parameter from the previous call, if any, or 0. -** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the -** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will -** overwrite any prior [sqlite3_wal_hook()] settings. +** ^A single database handle may have at most a single write-ahead log +** callback registered at one time. ^Calling [sqlite3_wal_hook()] +** replaces the default behavior or previously registered write-ahead +** log callback. +** +** ^The return value is a copy of the third parameter from the +** previous call, if any, or 0. +** +** ^The [sqlite3_wal_autocheckpoint()] interface and the +** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and +** will overwrite any prior [sqlite3_wal_hook()] settings. +** +** ^If a write-ahead log callback is set using this function then +** [sqlite3_wal_checkpoint_v2()] or [PRAGMA wal_checkpoint] +** should be invoked periodically to keep the write-ahead log file +** from growing without bound. +** +** ^Passing a NULL pointer for the callback disables automatic +** checkpointing entirely. To re-enable the default behavior, call +** sqlite3_wal_autocheckpoint(db,1000) or use [PRAGMA wal_checkpoint]. */ SQLITE_API void *sqlite3_wal_hook( sqlite3*, @@ -270466,7 +280125,7 @@ SQLITE_API void *sqlite3_wal_hook( ** to automatically [checkpoint] ** after committing a transaction if there are N or ** more frames in the [write-ahead log] file. ^Passing zero or -** a negative value as the nFrame parameter disables automatic +** a negative value as the N parameter disables automatic ** checkpoints entirely. ** ** ^The callback registered by this function replaces any existing callback @@ -270482,9 +280141,10 @@ SQLITE_API void *sqlite3_wal_hook( ** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] -** pages. The use of this interface -** is only necessary if the default setting is found to be suboptimal -** for a particular application. +** pages. +** +** ^The use of this interface is only necessary if the default setting +** is found to be suboptimal for a particular application. */ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); @@ -270549,6 +280209,11 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the ** addition that it also truncates the log file to zero bytes just prior ** to a successful return. +** +**
        SQLITE_CHECKPOINT_NOOP
        +** ^This mode always checkpoints zero frames. The only reason to invoke +** a NOOP checkpoint is to access the values returned by +** sqlite3_wal_checkpoint_v2() via output parameters *pnLog and *pnCkpt. ** ** ** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in @@ -270619,6 +280284,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( ** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the ** meaning of each of these checkpoint modes. */ +#define SQLITE_CHECKPOINT_NOOP -1 /* Do no work at all */ #define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ #define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ #define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */ @@ -270663,7 +280329,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** support constraints. In this configuration (which is the default) if ** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire ** statement is rolled back as if [ON CONFLICT | OR ABORT] had been -** specified as part of the users SQL statement, regardless of the actual +** specified as part of the user's SQL statement, regardless of the actual ** ON CONFLICT mode specified. ** ** If X is non-zero, then the virtual table implementation guarantees @@ -270697,7 +280363,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** [[SQLITE_VTAB_INNOCUOUS]]
        SQLITE_VTAB_INNOCUOUS
        **
        Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the -** the [xConnect] or [xCreate] methods of a [virtual table] implementation +** [xConnect] or [xCreate] methods of a [virtual table] implementation ** identify that virtual table as being safe to use from within triggers ** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the ** virtual table can do no serious harm even if it is controlled by a @@ -270856,7 +280522,8 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); **
        sqlite3_vtab_distinct() return value ** Rows are returned in aOrderBy order -** Rows with the same value in all aOrderBy columns are adjacent +** Rows with the same value in all aOrderBy columns are +** adjacent ** Duplicates over all colUsed columns may be omitted **
        0yesyesno **
        1noyesno @@ -270865,8 +280532,8 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); **
        ** ** ^For the purposes of comparing virtual table output values to see if the -** values are same value for sorting purposes, two NULL values are considered -** to be the same. In other words, the comparison operator is "IS" +** values are the same value for sorting purposes, two NULL values are +** considered to be the same. In other words, the comparison operator is "IS" ** (or "IS NOT DISTINCT FROM") and not "==". ** ** If a virtual table implementation is unable to meet the requirements @@ -270875,7 +280542,7 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); ** ** ^A virtual table implementation is always free to return rows in any order ** it wants, as long as the "orderByConsumed" flag is not set. ^When the -** the "orderByConsumed" flag is unset, the query planner will add extra +** "orderByConsumed" flag is unset, the query planner will add extra ** [bytecode] to ensure that the final results returned by the SQL query are ** ordered correctly. The use of the "orderByConsumed" flag and the ** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful @@ -270972,7 +280639,7 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); ** sqlite3_vtab_in_next(X,P) should be one of the parameters to the ** xFilter method which invokes these routines, and specifically ** a parameter that was previously selected for all-at-once IN constraint -** processing use the [sqlite3_vtab_in()] interface in the +** processing using the [sqlite3_vtab_in()] interface in the ** [xBestIndex|xBestIndex method]. ^(If the X parameter is not ** an xFilter argument that was selected for all-at-once IN constraint ** processing, then these routines return [SQLITE_ERROR].)^ @@ -270987,7 +280654,7 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); **   ){ **   // do something with pVal **   } -**   if( rc!=SQLITE_OK ){ +**   if( rc!=SQLITE_DONE ){ **   // an error has occurred **   } ** )^ @@ -271027,7 +280694,7 @@ SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut); ** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V) ** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th ** constraint is not available. ^The sqlite3_vtab_rhs_value() interface -** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if +** can return a result code other than SQLITE_OK or SQLITE_NOTFOUND if ** something goes wrong. ** ** The sqlite3_vtab_rhs_value() interface is usually only successful if @@ -271055,8 +280722,8 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** KEYWORDS: {conflict resolution mode} ** ** These constants are returned by [sqlite3_vtab_on_conflict()] to -** inform a [virtual table] implementation what the [ON CONFLICT] mode -** is for the SQL statement being evaluated. +** inform a [virtual table] implementation of the [ON CONFLICT] mode +** for the SQL statement being evaluated. ** ** Note that the [SQLITE_IGNORE] constant is also used as a potential ** return value from the [sqlite3_set_authorizer()] callback and that @@ -271096,39 +280763,39 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** [[SQLITE_SCANSTAT_EST]]
        SQLITE_SCANSTAT_EST
        **
        ^The "double" variable pointed to by the V parameter will be set to the ** query planner's estimate for the average number of rows output from each -** iteration of the X-th loop. If the query planner's estimates was accurate, +** iteration of the X-th loop. If the query planner's estimate was accurate, ** then this value will approximate the quotient NVISIT/NLOOP and the ** product of this value for all prior loops with the same SELECTID will -** be the NLOOP value for the current loop. +** be the NLOOP value for the current loop.
        ** ** [[SQLITE_SCANSTAT_NAME]]
        SQLITE_SCANSTAT_NAME
        **
        ^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the name of the index or table -** used for the X-th loop. +** used for the X-th loop.
        ** ** [[SQLITE_SCANSTAT_EXPLAIN]]
        SQLITE_SCANSTAT_EXPLAIN
        **
        ^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] -** description for the X-th loop. +** description for the X-th loop.
        ** ** [[SQLITE_SCANSTAT_SELECTID]]
        SQLITE_SCANSTAT_SELECTID
        **
        ^The "int" variable pointed to by the V parameter will be set to the ** id for the X-th query plan element. The id value is unique within the ** statement. The select-id is the same value as is output in the first -** column of an [EXPLAIN QUERY PLAN] query. +** column of an [EXPLAIN QUERY PLAN] query.
        ** ** [[SQLITE_SCANSTAT_PARENTID]]
        SQLITE_SCANSTAT_PARENTID
        **
        The "int" variable pointed to by the V parameter will be set to the -** the id of the parent of the current query element, if applicable, or +** id of the parent of the current query element, if applicable, or ** to zero if the query element has no parent. This is the same value as -** returned in the second column of an [EXPLAIN QUERY PLAN] query. +** returned in the second column of an [EXPLAIN QUERY PLAN] query.
        ** ** [[SQLITE_SCANSTAT_NCYCLE]]
        SQLITE_SCANSTAT_NCYCLE
        **
        The sqlite3_int64 output value is set to the number of cycles, ** according to the processor time-stamp counter, that elapsed while the ** query element was being processed. This value is not available for ** all query elements - if it is unavailable the output variable is -** set to -1. +** set to -1.
        ** */ #define SQLITE_SCANSTAT_NLOOP 0 @@ -271159,9 +280826,9 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** a variable pointed to by the "pOut" parameter. ** ** The "flags" parameter must be passed a mask of flags. At present only -** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX +** one flag is defined - [SQLITE_SCANSTAT_COMPLEX]. If SQLITE_SCANSTAT_COMPLEX ** is specified, then status information is available for all elements -** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If +** of a query plan that are reported by "[EXPLAIN QUERY PLAN]" output. If ** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements ** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of ** the EXPLAIN QUERY PLAN output) are available. Invoking API @@ -271169,13 +280836,14 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter. ** ** Parameter "idx" identifies the specific query element to retrieve statistics -** for. Query elements are numbered starting from zero. A value of -1 may be -** to query for statistics regarding the entire query. ^If idx is out of range +** for. Query elements are numbered starting from zero. A value of -1 may +** retrieve statistics for the entire query. ^If idx is out of range ** - less than -1 or greater than or equal to the total number of query ** elements used to implement the statement - a non-zero value is returned and ** the variable that pOut points to is unchanged. ** -** See also: [sqlite3_stmt_scanstatus_reset()] +** See also: [sqlite3_stmt_scanstatus_reset()] and the +** [nexec and ncycle] columns of the [bytecode virtual table]. */ SQLITE_API int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ @@ -271213,7 +280881,7 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); ** METHOD: sqlite3 ** ** ^If a write-transaction is open on [database connection] D when the -** [sqlite3_db_cacheflush(D)] interface invoked, any dirty +** [sqlite3_db_cacheflush(D)] interface is invoked, any dirty ** pages in the pager-cache that are not currently in use are written out ** to disk. A dirty page may be in use if a database cursor created by an ** active SQL statement is reading from it, or if it is page 1 of a database @@ -271327,8 +280995,8 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** triggers; and so forth. ** ** When the [sqlite3_blob_write()] API is used to update a blob column, -** the pre-update hook is invoked with SQLITE_DELETE. This is because the -** in this case the new values are not available. In this case, when a +** the pre-update hook is invoked with SQLITE_DELETE, because +** the new values are not yet available. In this case, when a ** callback made with op==SQLITE_DELETE is actually a write using the ** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns ** the index of the column being written. In other cases, where the @@ -271446,7 +281114,7 @@ typedef struct sqlite3_snapshot { ** The [sqlite3_snapshot_get()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( +SQLITE_API int sqlite3_snapshot_get( sqlite3 *db, const char *zSchema, sqlite3_snapshot **ppSnapshot @@ -271495,7 +281163,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( ** The [sqlite3_snapshot_open()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( +SQLITE_API int sqlite3_snapshot_open( sqlite3 *db, const char *zSchema, sqlite3_snapshot *pSnapshot @@ -271512,7 +281180,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( ** The [sqlite3_snapshot_free()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); +SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot*); /* ** CAPI3REF: Compare the ages of two snapshot handles. @@ -271539,7 +281207,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); ** This interface is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SNAPSHOT] option. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( +SQLITE_API int sqlite3_snapshot_cmp( sqlite3_snapshot *p1, sqlite3_snapshot *p2 ); @@ -271567,20 +281235,21 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( ** This interface is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SNAPSHOT] option. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); +SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Serialize a database ** -** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory -** that is a serialization of the S database on [database connection] D. +** The sqlite3_serialize(D,S,P,F) interface returns a pointer to +** memory that is a serialization of the S database on +** [database connection] D. If S is a NULL pointer, the main database is used. ** If P is not a NULL pointer, then the size of the database in bytes ** is written into *P. ** ** For an ordinary on-disk database file, the serialization is just a ** copy of the disk file. For an in-memory database or a "TEMP" database, ** the serialization is the same sequence of bytes which would be written -** to disk if that database where backed up to disk. +** to disk if that database were backed up to disk. ** ** The usual case is that sqlite3_serialize() copies the serialization of ** the database into memory obtained from [sqlite3_malloc64()] and returns @@ -271589,7 +281258,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c ** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations ** are made, and the sqlite3_serialize() function will return a pointer ** to the contiguous memory representation of the database that SQLite -** is currently using for that database, or NULL if the no such contiguous +** is currently using for that database, or NULL if no such contiguous ** memory representation of the database exists. A contiguous memory ** representation of the database will usually only exist if there has ** been a prior call to [sqlite3_deserialize(D,S,...)] with the same @@ -271640,12 +281309,13 @@ SQLITE_API unsigned char *sqlite3_serialize( ** ** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the ** [database connection] D to disconnect from database S and then -** reopen S as an in-memory database based on the serialization contained -** in P. The serialized database P is N bytes in size. M is the size of -** the buffer P, which might be larger than N. If M is larger than N, and -** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is -** permitted to add content to the in-memory database as long as the total -** size does not exceed M bytes. +** reopen S as an in-memory database based on the serialization +** contained in P. If S is a NULL pointer, the main database is +** used. The serialized database P is N bytes in size. M is the size +** of the buffer P, which might be larger than N. If M is larger than +** N, and the SQLITE_DESERIALIZE_READONLY bit is not set in F, then +** SQLite is permitted to add content to the in-memory database as +** long as the total size does not exceed M bytes. ** ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will ** invoke sqlite3_free() on the serialization buffer when the database @@ -271660,7 +281330,7 @@ SQLITE_API unsigned char *sqlite3_serialize( ** database is currently in a read transaction or is involved in a backup ** operation. ** -** It is not possible to deserialized into the TEMP database. If the +** It is not possible to deserialize into the TEMP database. If the ** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the ** function returns SQLITE_ERROR. ** @@ -271682,7 +281352,7 @@ SQLITE_API int sqlite3_deserialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which DB to reopen with the deserialization */ unsigned char *pData, /* The serialized database content */ - sqlite3_int64 szDb, /* Number bytes in the deserialization */ + sqlite3_int64 szDb, /* Number of bytes in the deserialization */ sqlite3_int64 szBuf, /* Total size of buffer pData[] */ unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ ); @@ -271690,7 +281360,7 @@ SQLITE_API int sqlite3_deserialize( /* ** CAPI3REF: Flags for sqlite3_deserialize() ** -** The following are allowed values for 6th argument (the F argument) to +** The following are allowed values for the 6th argument (the F argument) to ** the [sqlite3_deserialize(D,S,P,N,M,F)] interface. ** ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization @@ -271712,6 +281382,77 @@ SQLITE_API int sqlite3_deserialize( #define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */ #define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */ +/* +** CAPI3REF: Bind array values to the CARRAY table-valued function +** +** The sqlite3_carray_bind_v2(S,I,P,N,F,X,D) interface binds an array value to +** parameter that is the first argument of the [carray() table-valued function]. +** The S parameter is a pointer to the [prepared statement] that uses the +** carray() functions. I is the parameter index to be bound. I must be the +** index of the parameter that is the first argument to the carray() +** table-valued function. P is a pointer to the array to be bound, and N +** is the number of elements in the array. The F argument is one of +** constants [SQLITE_CARRAY_INT32], [SQLITE_CARRAY_INT64], +** [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT], +** or [SQLITE_CARRAY_BLOB] to indicate the datatype of the array P. +** +** If the X argument is not a NULL pointer or one of the special +** values [SQLITE_STATIC] or [SQLITE_TRANSIENT], then SQLite will invoke +** the function X with argument D when it is finished using the data in P. +** The call to X(D) is a destructor for the array P. The destructor X(D) +** is invoked even if the call to sqlite3_carray_bind_v2() fails. If the X +** parameter is the special-case value [SQLITE_STATIC], then SQLite assumes +** that the data static and the destructor is never invoked. If the X +** parameter is the special-case value [SQLITE_TRANSIENT], then +** sqlite3_carray_bind_v2() makes its own private copy of the data prior +** to returning and never invokes the destructor X. +** +** The sqlite3_carray_bind() function works the same as sqlite3_carray_bind_v2() +** with a D parameter set to P. In other words, +** sqlite3_carray_bind(S,I,P,N,F,X) is same as +** sqlite3_carray_bind_v2(S,I,P,N,F,X,P). +*/ +SQLITE_API int sqlite3_carray_bind_v2( + sqlite3_stmt *pStmt, /* Statement to be bound */ + int i, /* Parameter index */ + void *aData, /* Pointer to array data */ + int nData, /* Number of data elements */ + int mFlags, /* CARRAY flags */ + void (*xDel)(void*), /* Destructor for aData */ + void *pDel /* Optional argument to xDel() */ +); +SQLITE_API int sqlite3_carray_bind( + sqlite3_stmt *pStmt, /* Statement to be bound */ + int i, /* Parameter index */ + void *aData, /* Pointer to array data */ + int nData, /* Number of data elements */ + int mFlags, /* CARRAY flags */ + void (*xDel)(void*) /* Destructor for aData */ +); + +/* +** CAPI3REF: Datatypes for the CARRAY table-valued function +** +** The fifth argument to the [sqlite3_carray_bind()] interface musts be +** one of the following constants, to specify the datatype of the array +** that is being bound into the [carray table-valued function]. +*/ +#define SQLITE_CARRAY_INT32 0 /* Data is 32-bit signed integers */ +#define SQLITE_CARRAY_INT64 1 /* Data is 64-bit signed integers */ +#define SQLITE_CARRAY_DOUBLE 2 /* Data is doubles */ +#define SQLITE_CARRAY_TEXT 3 /* Data is char* */ +#define SQLITE_CARRAY_BLOB 4 /* Data is struct iovec */ + +/* +** Versions of the above #defines that omit the initial SQLITE_, for +** legacy compatibility. +*/ +#define CARRAY_INT32 0 /* Data is 32-bit signed integers */ +#define CARRAY_INT64 1 /* Data is 64-bit signed integers */ +#define CARRAY_DOUBLE 2 /* Data is doubles */ +#define CARRAY_TEXT 3 /* Data is char* */ +#define CARRAY_BLOB 4 /* Data is struct iovec */ + /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. @@ -271734,7 +281475,7 @@ SQLITE_API int sqlite3_deserialize( #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif -#endif /* SQLITE3_H */ +/* #endif for SQLITE3_H will be added by mksqlite3.tcl */ /******** Begin file sqlite3rtree.h *********/ /* @@ -272215,9 +281956,10 @@ SQLITE_API void sqlite3session_table_filter( ** is inserted while a session object is enabled, then later deleted while ** the same session object is disabled, no INSERT record will appear in the ** changeset, even though the delete took place while the session was disabled. -** Or, if one field of a row is updated while a session is disabled, and -** another field of the same row is updated while the session is enabled, the -** resulting changeset will contain an UPDATE change that updates both fields. +** Or, if one field of a row is updated while a session is enabled, and +** then another field of the same row is updated while the session is disabled, +** the resulting changeset will contain an UPDATE change that updates both +** fields. */ SQLITE_API int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ @@ -272289,8 +282031,9 @@ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession ** database zFrom the contents of the two compatible tables would be ** identical. ** -** It an error if database zFrom does not exist or does not contain the -** required compatible table. +** Unless the call to this function is a no-op as described above, it is an +** error if database zFrom does not exist or does not contain the required +** compatible table. ** ** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg @@ -272425,7 +282168,7 @@ SQLITE_API int sqlite3changeset_start_v2( ** The following flags may passed via the 4th parameter to ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: ** -**
        SQLITE_CHANGESETAPPLY_INVERT
        +**
        SQLITE_CHANGESETSTART_INVERT
        ** Invert the changeset while iterating through it. This is equivalent to ** inverting a changeset using sqlite3changeset_invert() before applying it. ** It is an error to specify this flag with a patchset. @@ -272740,19 +282483,6 @@ SQLITE_API int sqlite3changeset_concat( void **ppOut /* OUT: Buffer containing output changeset */ ); - -/* -** CAPI3REF: Upgrade the Schema of a Changeset/Patchset -*/ -SQLITE_API int sqlite3changeset_upgrade( - sqlite3 *db, - const char *zDb, - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ -); - - - /* ** CAPI3REF: Changegroup Handle ** @@ -272982,14 +282712,32 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); ** update the "main" database attached to handle db with the changes found in ** the changeset passed via the second and third arguments. ** +** All changes made by these functions are enclosed in a savepoint transaction. +** If any other error (aside from a constraint failure when attempting to +** write to the target database) occurs, then the savepoint transaction is +** rolled back, restoring the target database to its original state, and an +** SQLite error code returned. Additionally, starting with version 3.51.0, +** an error code and error message that may be accessed using the +** [sqlite3_errcode()] and [sqlite3_errmsg()] APIs are left in the database +** handle. +** ** The fourth argument (xFilter) passed to these functions is the "filter -** callback". If it is not NULL, then for each table affected by at least one -** change in the changeset, the filter callback is invoked with -** the table name as the second argument, and a copy of the context pointer -** passed as the sixth argument as the first. If the "filter callback" -** returns zero, then no attempt is made to apply any changes to the table. -** Otherwise, if the return value is non-zero or the xFilter argument to -** is NULL, all changes related to the table are attempted. +** callback". This may be passed NULL, in which case all changes in the +** changeset are applied to the database. For sqlite3changeset_apply() and +** sqlite3_changeset_apply_v2(), if it is not NULL, then it is invoked once +** for each table affected by at least one change in the changeset. In this +** case the table name is passed as the second argument, and a copy of +** the context pointer passed as the sixth argument to apply() or apply_v2() +** as the first. If the "filter callback" returns zero, then no attempt is +** made to apply any changes to the table. Otherwise, if the return value is +** non-zero, all changes related to the table are attempted. +** +** For sqlite3_changeset_apply_v3(), the xFilter callback is invoked once +** per change. The second argument in this case is an sqlite3_changeset_iter +** that may be queried using the usual APIs for the details of the current +** change. If the "filter callback" returns zero in this case, then no attempt +** is made to apply the current change. If it returns non-zero, the change +** is applied. ** ** For each table that is not excluded by the filter callback, this function ** tests that the target database contains a compatible table. A table is @@ -273010,11 +282758,11 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); ** one such warning is issued for each table in the changeset. ** ** For each change for which there is a compatible table, an attempt is made -** to modify the table contents according to the UPDATE, INSERT or DELETE -** change. If a change cannot be applied cleanly, the conflict handler -** function passed as the fifth argument to sqlite3changeset_apply() may be -** invoked. A description of exactly when the conflict handler is invoked for -** each type of change is below. +** to modify the table contents according to each UPDATE, INSERT or DELETE +** change that is not excluded by a filter callback. If a change cannot be +** applied cleanly, the conflict handler function passed as the fifth argument +** to sqlite3changeset_apply() may be invoked. A description of exactly when +** the conflict handler is invoked for each type of change is below. ** ** Unlike the xFilter argument, xConflict may not be passed NULL. The results ** of passing anything other than a valid function pointer as the xConflict @@ -273110,12 +282858,6 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); ** This can be used to further customize the application's conflict ** resolution strategy. ** -** All changes made by these functions are enclosed in a savepoint transaction. -** If any other error (aside from a constraint failure when attempting to -** write to the target database) occurs, then the savepoint transaction is -** rolled back, restoring the target database to its original state, and an -** SQLite error code returned. -** ** If the output parameters (ppRebase) and (pnRebase) are non-NULL and ** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2() ** may set (*ppRebase) to point to a "rebase" that may be used with the @@ -273165,6 +282907,23 @@ SQLITE_API int sqlite3changeset_apply_v2( void **ppRebase, int *pnRebase, /* OUT: Rebase data */ int flags /* SESSION_CHANGESETAPPLY_* flags */ ); +SQLITE_API int sqlite3changeset_apply_v3( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + sqlite3_changeset_iter *p /* Handle describing change */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, /* OUT: Rebase data */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ +); /* ** CAPI3REF: Flags for sqlite3changeset_apply_v2 @@ -273205,11 +282964,23 @@ SQLITE_API int sqlite3changeset_apply_v2( ** database behave as if they were declared with "ON UPDATE NO ACTION ON ** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL ** or SET DEFAULT. +** +**
        SQLITE_CHANGESETAPPLY_NOUPDATELOOP
        +** Sometimes, a changeset contains two or more update statements such that +** although after applying all updates the database will contain no +** constraint violations, no single update can be applied before the others. +** The simplest example of this is a pair of UPDATEs that have "swapped" +** two column values with a UNIQUE constraint. +**

        +** Usually, sqlite3changeset_apply() and similar functions work hard to try +** to find a way to apply such a changeset. However, if this flag is set, +** then all such updates are considered CONSTRAINT conflicts. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 #define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004 #define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008 +#define SQLITE_CHANGESETAPPLY_NOUPDATELOOP 0x0010 /* ** CAPI3REF: Constants Passed To The Conflict Handler @@ -273584,6 +283355,23 @@ SQLITE_API int sqlite3changeset_apply_v2_strm( void **ppRebase, int *pnRebase, int flags ); +SQLITE_API int sqlite3changeset_apply_v3_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + sqlite3_changeset_iter *p + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, + int flags +); SQLITE_API int sqlite3changeset_concat_strm( int (*xInputA)(void *pIn, void *pData, int *pnData), void *pInA, @@ -273675,6 +283463,232 @@ SQLITE_API int sqlite3session_config(int op, void *pArg); */ #define SQLITE_SESSION_CONFIG_STRMSIZE 1 +/* +** CAPI3REF: Configure a changegroup object +** +** Configure the changegroup object passed as the first argument. +** At present the only valid value for the second parameter is +** [SQLITE_CHANGEGROUP_CONFIG_PATCHSET]. +*/ +SQLITE_API int sqlite3changegroup_config(sqlite3_changegroup*, int, void *pArg); + +/* +** CAPI3REF: Options for sqlite3changegroup_config(). +** +** The following values may be passed as the 2nd parameter to +** sqlite3changegroup_config(). +** +**

        SQLITE_CHANGEGROUP_CONFIG_PATCHSET
        +** A changegroup object generates either a changeset or patchset. Usually, +** this is determined by whether the first call to sqlite3changegroup_add() +** is passed a changeset or a patchset. Or, if the first changes are added +** to the changegroup object using the sqlite3changegroup_change_xxx() +** APIs, then this option may be used to configure whether the changegroup +** object generates a changeset or patchset. +** +** When this option is invoked, parameter pArg must point to a value of +** type int. If the changegroup currently contains zero changes, and the +** value of the int variable is zero or greater than zero, then the +** changegroup is configured to generate a changeset or patchset, +** respectively. It is a no-op, not an error, if the changegroup is not +** configured because it has already started accumulating changes. +** +** Before returning, the int variable is set to 0 if the changegroup is +** configured to generate a changeset, or 1 if it is configured to generate +** a patchset. +*/ +#define SQLITE_CHANGEGROUP_CONFIG_PATCHSET 1 + + +/* +** CAPI3REF: Begin adding a change to a changegroup +** +** This API is used, in concert with other sqlite3changegroup_change_xxx() +** APIs, to add changes to a changegroup object one at a time. To add a +** single change, the caller must: +** +** 1. Invoke sqlite3changegroup_change_begin() to indicate the type of +** change (INSERT, UPDATE or DELETE), the affected table and whether +** or not the change should be marked as indirect. +** +** 2. Invoke sqlite3changegroup_change_int64() or one of the other four +** value functions - _null(), _double(), _text() or _blob() - one or +** more times to specify old.* and new.* values for the change being +** constructed. +** +** 3. Invoke sqlite3changegroup_change_finish() to either finish adding +** the change to the group, or to discard the change altogether. +** +** The first argument to this function must be a pointer to the existing +** changegroup object that the change will be added to. The second argument +** must be SQLITE_INSERT, SQLITE_UPDATE or SQLITE_DELETE. The third is the +** name of the table that the change affects, and the fourth is a boolean +** flag specifying whether the change should be marked as "indirect" (if +** bIndirect is non-zero) or not indirect (if bIndirect is zero). +** +** Following a successful call to this function, this function may not be +** called again on the same changegroup object until after +** sqlite3changegroup_change_finish() has been called. Doing so is an +** SQLITE_MISUSE error. +** +** The changegroup object passed as the first argument must be already +** configured with schema data for the specified table. It may be configured +** either by calling sqlite3changegroup_schema() with a database that contains +** the table, or sqlite3changegroup_add() with a changeset that contains the +** table. If the changegroup object has not been configured with a schema for +** the specified table when this function is called, SQLITE_ERROR is returned. +** +** If successful, SQLITE_OK is returned. Otherwise, if an error occurs, an +** SQLite error code is returned. In this case, if argument pzErr is non-NULL, +** then (*pzErr) may be set to point to a buffer containing a utf-8 formated, +** nul-terminated, English language error message. It is the responsibility +** of the caller to eventually free this buffer using sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_change_begin( + sqlite3_changegroup*, + int eOp, + const char *zTab, + int bIndirect, + char **pzErr +); + +/* +** CAPI3REF: Add a 64-bit integer to a changegroup +** +** This function may only be called between a successful call to +** sqlite3changegroup_change_begin() and its matching +** sqlite3changegroup_change_finish() call. If it is called at any +** other time, it is an SQLITE_MISUSE error. Calling this function +** specifies a 64-bit integer value to be used in the change currently being +** added to the changegroup object passed as the first argument. +** +** The second parameter, bNew, specifies whether the value is to be part of +** the new.* (if bNew is non-zero) or old.* (if bNew is zero) record of +** the change under construction. If this does not match the type of change +** specified by the preceding call to sqlite3changegroup_change_begin() (i.e. +** an old.* value for an SQLITE_INSERT change, or a new.* value for an +** SQLITE_DELETE), then SQLITE_ERROR is returned. +** +** The third parameter specifies the column of the old.* or new.* record that +** the value will be a part of. If the specified table has an explicit primary +** key, then this is the index of the table column, numbered from 0 in the order +** specified within the CREATE TABLE statement. Or, if the table uses an +** implicit rowid key, then the column 0 is the rowid and the explicit columns +** are numbered starting from 1. If the iCol parameter is less than 0 or greater +** than the index of the last column in the table, SQLITE_RANGE is returned. +** +** The fourth parameter is the integer value to use as part of the old.* or +** new.* record. +** +** If this call is successful, SQLITE_OK is returned. Otherwise, if an +** error occurs, an SQLite error code is returned. +*/ +SQLITE_API int sqlite3changegroup_change_int64( + sqlite3_changegroup*, + int bNew, + int iCol, + sqlite3_int64 iVal +); + +/* +** CAPI3REF: Add a NULL to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). Except that +** it configures the change currently under construction with a NULL value +** instead of a 64-bit integer. +*/ +SQLITE_API int sqlite3changegroup_change_null(sqlite3_changegroup*, int, int); + +/* +** CAPI3REF: Add an double to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). Except that +** it configures the change currently being constructed with a real value +** instead of a 64-bit integer. +*/ +SQLITE_API int sqlite3changegroup_change_double(sqlite3_changegroup*, int, int, double); + +/* +** CAPI3REF: Add a text value to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). It configures +** the currently accumulated change with a text value instead of a 64-bit +** integer. Parameter pVal points to a buffer containing the text encoded using +** utf-8. Parameter nVal may either be the size of the text value in bytes, or +** else a negative value, in which case the buffer pVal points to is assumed to +** be nul-terminated. +*/ +SQLITE_API int sqlite3changegroup_change_text( + sqlite3_changegroup*, int, int, const char *pVal, int nVal +); + +/* +** CAPI3REF: Add a blob to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). It configures +** the currently accumulated change with a blob value instead of a 64-bit +** integer. Parameter pVal points to a buffer containing the blob. Parameter +** nVal is the size of the blob in bytes. +*/ +SQLITE_API int sqlite3changegroup_change_blob( + sqlite3_changegroup*, int, int, const void *pVal, int nVal +); + +/* +** CAPI3REF: Finish adding one-at-at-time changes to a changegroup +** +** This function may only be called following a successful call to +** sqlite3changegroup_change_begin(). Otherwise, it is an SQLITE_MISUSE error. +** +** If parameter bDiscard is non-zero, then the current change is simply +** discarded. In this case this function is always successful and SQLITE_OK +** returned. +** +** If parameter bDiscard is zero, then an attempt is made to add the current +** change to the changegroup. Assuming the changegroup is configured to +** produce a changeset (not a patchset), this requires that: +** +** * If the change is an INSERT or DELETE, then a value must be specified +** for all columns of the new.* or old.* record, respectively. +** +** * If the change is an UPDATE record, then values must be provided for +** the PRIMARY KEY columns of the old.* record, but must not be provided +** for PRIMARY KEY columns of the new.* record. +** +** * If the change is an UPDATE record, then for each non-PRIMARY KEY +** column in the old.* record for which a value has been provided, a +** value must also be provided for the same column in the new.* record. +** Similarly, for each non-PK column in the old.* record for which +** a value is not provided, a value must not be provided for the same +** column in the new.* record. +** +** * All values specified for PRIMARY KEY columns must be non-NULL. +** +** Otherwise, it is an error. +** +** If the changegroup already contains a change for the same row (identified +** by PRIMARY KEY columns), then the current change is combined with the +** existing change in the same way as for sqlite3changegroup_add(). +** +** For a patchset, all of the above rules apply except that it doesn't matter +** whether or not values are provided for the non-PK old.* record columns +** for an UPDATE or DELETE change. This means that code used to produce +** a changeset using the sqlite3changegroup_change_xxx() APIs may also +** be used to produce patchsets. +** +** If the call is successful, SQLITE_OK is returned. Otherwise, if an error +** occurs, an SQLite error code is returned. If an error is returned and +** parameter pzErr is not NULL, then (*pzErr) may be set to point to a buffer +** containing a nul-terminated, utf-8 encoded, English language error message. +** It is the responsibility of the caller to eventually free any such error +** message buffer using sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_change_finish( + sqlite3_changegroup*, + int bDiscard, + char **pzErr +); + /* ** Make sure we can call this stuff from C++. */ @@ -273985,14 +283999,29 @@ struct Fts5PhraseIter { ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, ** output variable (*ppToken) is set to point to a buffer containing the ** matching document token, and (*pnToken) to the size of that buffer in -** bytes. This API is not available if the specified token matches a -** prefix query term. In that case both output variables are always set -** to 0. +** bytes. ** ** The output text is not a copy of the document text that was tokenized. ** It is the output of the tokenizer module. For tokendata=1 tables, this ** includes any embedded 0x00 and trailing data. ** +** This API may be slow in some cases if the token identified by parameters +** iIdx and iToken matched a prefix token in the query. In most cases, the +** first call to this API for each prefix token in the query is forced +** to scan the portion of the full-text index that matches the prefix +** token to collect the extra data required by this API. If the prefix +** token matches a large number of token instances in the document set, +** this may be a performance problem. +** +** If the user knows in advance that a query may use this API for a +** prefix token, FTS5 may be configured to collect all required data as part +** of the initial querying of the full-text index, avoiding the second scan +** entirely. This also causes prefix queries that do not use this API to +** run more slowly and use more memory. FTS5 may be configured in this way +** either on a per-table basis using the [FTS5 insttoken | 'insttoken'] +** option, or on a per-query basis using the +** [fts5_insttoken | fts5_insttoken()] user function. +** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. ** @@ -274426,110 +284455,12 @@ struct fts5_api { #endif /* _FTS5_H */ /******** End of fts5.h *********/ +#endif /* SQLITE3_H */ /*** End of #include "sqlite3.h" ***/ #ifdef SQLITE_USER_AUTHENTICATION -/* #include "sqlite3userauth.h" */ -/*** Begin of #include "sqlite3userauth.h" ***/ -/* -** 2014-09-08 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This file contains the application interface definitions for the -** user-authentication extension feature. -** -** To compile with the user-authentication feature, append this file to -** end of an SQLite amalgamation header file ("sqlite3.h"), then add -** the SQLITE_USER_AUTHENTICATION compile-time option. See the -** user-auth.txt file in the same source directory as this file for -** additional information. -*/ -#ifdef SQLITE_USER_AUTHENTICATION - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** If a database contains the SQLITE_USER table, then the -** sqlite3_user_authenticate() interface must be invoked with an -** appropriate username and password prior to enable read and write -** access to the database. -** -** Return SQLITE_OK on success or SQLITE_ERROR if the username/password -** combination is incorrect or unknown. -** -** If the SQLITE_USER table is not present in the database file, then -** this interface is a harmless no-op returnning SQLITE_OK. -*/ -SQLITE_API int sqlite3_user_authenticate( - sqlite3 *db, /* The database connection */ - const char *zUsername, /* Username */ - const char *aPW, /* Password or credentials */ - int nPW /* Number of bytes in aPW[] */ -); - -/* -** The sqlite3_user_add() interface can be used (by an admin user only) -** to create a new user. When called on a no-authentication-required -** database, this routine converts the database into an authentication- -** required database, automatically makes the added user an -** administrator, and logs in the current connection as that user. -** The sqlite3_user_add() interface only works for the "main" database, not -** for any ATTACH-ed databases. Any call to sqlite3_user_add() by a -** non-admin user results in an error. -*/ -SQLITE_API int sqlite3_user_add( - sqlite3 *db, /* Database connection */ - const char *zUsername, /* Username to be added */ - const char *aPW, /* Password or credentials */ - int nPW, /* Number of bytes in aPW[] */ - int isAdmin /* True to give new user admin privilege */ -); - -/* -** The sqlite3_user_change() interface can be used to change a users -** login credentials or admin privilege. Any user can change their own -** login credentials. Only an admin user can change another users login -** credentials or admin privilege setting. No user may change their own -** admin privilege setting. -*/ -SQLITE_API int sqlite3_user_change( - sqlite3 *db, /* Database connection */ - const char *zUsername, /* Username to change */ - const char *aPW, /* New password or credentials */ - int nPW, /* Number of bytes in aPW[] */ - int isAdmin /* Modified admin privilege for the user */ -); - -/* -** The sqlite3_user_delete() interface can be used (by an admin user only) -** to delete a user. The currently logged-in user cannot be deleted, -** which guarantees that there is always an admin user and hence that -** the database cannot be converted into a no-authentication-required -** database. -*/ -SQLITE_API int sqlite3_user_delete( - sqlite3 *db, /* Database connection */ - const char *zUsername /* Username to remove */ -); - -#ifdef __cplusplus -} /* end of the 'extern "C"' block */ -#endif - -#endif /* SQLITE_USER_AUTHENTICATION */ -/*** End of #include "sqlite3userauth.h" ***/ - +#undef SQLITE_USER_AUTHENTICATION #endif /* @@ -274542,7 +284473,8 @@ SQLITE_API int sqlite3_user_delete( #define CODEC_TYPE_SQLCIPHER 4 #define CODEC_TYPE_RC4 5 #define CODEC_TYPE_ASCON128 6 -#define CODEC_TYPE_MAX_BUILTIN 6 +#define CODEC_TYPE_AEGIS 7 +#define CODEC_TYPE_MAX_BUILTIN 7 /* ** Definition of API functions @@ -274614,6 +284546,7 @@ SQLITE_API void sqlite3_activate_see(const char* zPassPhrase); SQLITE_API int sqlite3mc_cipher_count(); SQLITE_API int sqlite3mc_cipher_index(const char* cipherName); SQLITE_API const char* sqlite3mc_cipher_name(int cipherIndex); +SQLITE_API int sqlite3mc_cipher_name_copy(int cipherIndex, char* cipherName, int maxCipherNameSize); SQLITE_API int sqlite3mc_config(sqlite3* db, const char* paramName, int newValue); SQLITE_API int sqlite3mc_config_cipher(sqlite3* db, const char* cipherName, const char* paramName, int newValue); SQLITE_API unsigned char* sqlite3mc_codec_data(sqlite3* db, const char* zDbName, const char* paramName); @@ -274749,7 +284682,933 @@ SQLITE_API void sqlite3mc_vfs_shutdown(); /*** End of #include "sqlite3mc_vfs.h" ***/ +/* +** Dispatch table support +*/ + +#ifdef SQLITE3MC_USE_DISPATCH_TABLE + +/* +** Instead of making the SQLite symbols public dispatch tables can be +** used. In that case only the pointers to the dispatch tables are +** made public, hiding all other SQLite symbols. This is useful for +** modules which want to use an embedded SQLite version without +** conflicts with other SQLite implementation. +** +** The only rule to obey is that such an embedded SQLite instance +** should not access the same database files as a separate SQLite +** instance within the same process, because that could lead to +** database corruption. +** +** Define symbol SQLITE3MC_USE_DISPATCH_TABLE to activate the use of +** dispatch tables. +** +** Define symbol SQLITE3MC_API_TABLE_PREFIX to specify your own +** global symbols for the dispatch tables to avoid name clashes. +** +** Example: #define SQLITE3MC_API_TABLE_PREFIX MyApplication +** +** The default prefix is "sqlite3mc". +*/ + +#ifndef SQLITE3MC_API_TABLE_PREFIX +#define SQLITE3MC_API_TABLE_PREFIX sqlite3mc #endif + +#define SQLITE3MC_CONCAT(A,B) SQLITE3MC_CONCAT_(A,B) +#define SQLITE3MC_CONCAT_(A,B) A##B +#define SQLITE3MC_API_TABLE(name) SQLITE3MC_CONCAT(SQLITE3MC_API_TABLE_PREFIX,SQLITE3MC_CONCAT(_,name)) + +#define SQLITE3MC_API_TABLE_EXT SQLITE3MC_API_TABLE(api_ext) +#define SQLITE3MC_API_TABLE_CORE SQLITE3MC_API_TABLE(api_core) +#define SQLITE3MC_API_TABLE_MC SQLITE3MC_API_TABLE(api_mc) + +/* Define the dispatch table name for sqlite3ext.h */ +#define sqlite3_api SQLITE3MC_API_TABLE_EXT + +/* #include "sqlite3ext.h" */ +/*** Begin of #include "sqlite3ext.h" ***/ +/* +** 2006 June 7 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This header file defines the SQLite interface for use by +** shared libraries that want to be imported as extensions into +** an SQLite instance. Shared libraries that intend to be loaded +** as extensions by SQLite should #include this file instead of +** sqlite3.h. +*/ +#ifndef SQLITE3EXT_H +#define SQLITE3EXT_H +/* #include "sqlite3.h" */ + + +/* +** The following structure holds pointers to all of the SQLite API +** routines. +** +** WARNING: In order to maintain backwards compatibility, add new +** interfaces to the end of this structure only. If you insert new +** interfaces in the middle of this structure, then older different +** versions of SQLite will not be able to load each other's shared +** libraries! +*/ +struct sqlite3_api_routines { + void * (*aggregate_context)(sqlite3_context*,int nBytes); + int (*aggregate_count)(sqlite3_context*); + int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); + int (*bind_double)(sqlite3_stmt*,int,double); + int (*bind_int)(sqlite3_stmt*,int,int); + int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64); + int (*bind_null)(sqlite3_stmt*,int); + int (*bind_parameter_count)(sqlite3_stmt*); + int (*bind_parameter_index)(sqlite3_stmt*,const char*zName); + const char * (*bind_parameter_name)(sqlite3_stmt*,int); + int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); + int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*)); + int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*); + int (*busy_handler)(sqlite3*,int(*)(void*,int),void*); + int (*busy_timeout)(sqlite3*,int ms); + int (*changes)(sqlite3*); + int (*close)(sqlite3*); + int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*, + int eTextRep,const char*)); + int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*, + int eTextRep,const void*)); + const void * (*column_blob)(sqlite3_stmt*,int iCol); + int (*column_bytes)(sqlite3_stmt*,int iCol); + int (*column_bytes16)(sqlite3_stmt*,int iCol); + int (*column_count)(sqlite3_stmt*pStmt); + const char * (*column_database_name)(sqlite3_stmt*,int); + const void * (*column_database_name16)(sqlite3_stmt*,int); + const char * (*column_decltype)(sqlite3_stmt*,int i); + const void * (*column_decltype16)(sqlite3_stmt*,int); + double (*column_double)(sqlite3_stmt*,int iCol); + int (*column_int)(sqlite3_stmt*,int iCol); + sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol); + const char * (*column_name)(sqlite3_stmt*,int); + const void * (*column_name16)(sqlite3_stmt*,int); + const char * (*column_origin_name)(sqlite3_stmt*,int); + const void * (*column_origin_name16)(sqlite3_stmt*,int); + const char * (*column_table_name)(sqlite3_stmt*,int); + const void * (*column_table_name16)(sqlite3_stmt*,int); + const unsigned char * (*column_text)(sqlite3_stmt*,int iCol); + const void * (*column_text16)(sqlite3_stmt*,int iCol); + int (*column_type)(sqlite3_stmt*,int iCol); + sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol); + void * (*commit_hook)(sqlite3*,int(*)(void*),void*); + int (*complete)(const char*sql); + int (*complete16)(const void*sql); + int (*create_collation)(sqlite3*,const char*,int,void*, + int(*)(void*,int,const void*,int,const void*)); + int (*create_collation16)(sqlite3*,const void*,int,void*, + int(*)(void*,int,const void*,int,const void*)); + int (*create_function)(sqlite3*,const char*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*)); + int (*create_function16)(sqlite3*,const void*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*)); + int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); + int (*data_count)(sqlite3_stmt*pStmt); + sqlite3 * (*db_handle)(sqlite3_stmt*); + int (*declare_vtab)(sqlite3*,const char*); + int (*enable_shared_cache)(int); + int (*errcode)(sqlite3*db); + const char * (*errmsg)(sqlite3*); + const void * (*errmsg16)(sqlite3*); + int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); + int (*expired)(sqlite3_stmt*); + int (*finalize)(sqlite3_stmt*pStmt); + void (*free)(void*); + void (*free_table)(char**result); + int (*get_autocommit)(sqlite3*); + void * (*get_auxdata)(sqlite3_context*,int); + int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); + int (*global_recover)(void); + void (*interruptx)(sqlite3*); + sqlite_int64 (*last_insert_rowid)(sqlite3*); + const char * (*libversion)(void); + int (*libversion_number)(void); + void *(*malloc)(int); + char * (*mprintf)(const char*,...); + int (*open)(const char*,sqlite3**); + int (*open16)(const void*,sqlite3**); + int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); + int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); + void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*); + void (*progress_handler)(sqlite3*,int,int(*)(void*),void*); + void *(*realloc)(void*,int); + int (*reset)(sqlite3_stmt*pStmt); + void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_double)(sqlite3_context*,double); + void (*result_error)(sqlite3_context*,const char*,int); + void (*result_error16)(sqlite3_context*,const void*,int); + void (*result_int)(sqlite3_context*,int); + void (*result_int64)(sqlite3_context*,sqlite_int64); + void (*result_null)(sqlite3_context*); + void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*)); + void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_value)(sqlite3_context*,sqlite3_value*); + void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); + int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, + const char*,const char*),void*); + void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); + char * (*xsnprintf)(int,char*,const char*,...); + int (*step)(sqlite3_stmt*); + int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, + char const**,char const**,int*,int*,int*); + void (*thread_cleanup)(void); + int (*total_changes)(sqlite3*); + void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); + int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); + void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*, + sqlite_int64),void*); + void * (*user_data)(sqlite3_context*); + const void * (*value_blob)(sqlite3_value*); + int (*value_bytes)(sqlite3_value*); + int (*value_bytes16)(sqlite3_value*); + double (*value_double)(sqlite3_value*); + int (*value_int)(sqlite3_value*); + sqlite_int64 (*value_int64)(sqlite3_value*); + int (*value_numeric_type)(sqlite3_value*); + const unsigned char * (*value_text)(sqlite3_value*); + const void * (*value_text16)(sqlite3_value*); + const void * (*value_text16be)(sqlite3_value*); + const void * (*value_text16le)(sqlite3_value*); + int (*value_type)(sqlite3_value*); + char *(*vmprintf)(const char*,va_list); + /* Added ??? */ + int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); + /* Added by 3.3.13 */ + int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); + int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); + int (*clear_bindings)(sqlite3_stmt*); + /* Added by 3.4.1 */ + int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*, + void (*xDestroy)(void *)); + /* Added by 3.5.0 */ + int (*bind_zeroblob)(sqlite3_stmt*,int,int); + int (*blob_bytes)(sqlite3_blob*); + int (*blob_close)(sqlite3_blob*); + int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64, + int,sqlite3_blob**); + int (*blob_read)(sqlite3_blob*,void*,int,int); + int (*blob_write)(sqlite3_blob*,const void*,int,int); + int (*create_collation_v2)(sqlite3*,const char*,int,void*, + int(*)(void*,int,const void*,int,const void*), + void(*)(void*)); + int (*file_control)(sqlite3*,const char*,int,void*); + sqlite3_int64 (*memory_highwater)(int); + sqlite3_int64 (*memory_used)(void); + sqlite3_mutex *(*mutex_alloc)(int); + void (*mutex_enter)(sqlite3_mutex*); + void (*mutex_free)(sqlite3_mutex*); + void (*mutex_leave)(sqlite3_mutex*); + int (*mutex_try)(sqlite3_mutex*); + int (*open_v2)(const char*,sqlite3**,int,const char*); + int (*release_memory)(int); + void (*result_error_nomem)(sqlite3_context*); + void (*result_error_toobig)(sqlite3_context*); + int (*sleep)(int); + void (*soft_heap_limit)(int); + sqlite3_vfs *(*vfs_find)(const char*); + int (*vfs_register)(sqlite3_vfs*,int); + int (*vfs_unregister)(sqlite3_vfs*); + int (*xthreadsafe)(void); + void (*result_zeroblob)(sqlite3_context*,int); + void (*result_error_code)(sqlite3_context*,int); + int (*test_control)(int, ...); + void (*randomness)(int,void*); + sqlite3 *(*context_db_handle)(sqlite3_context*); + int (*extended_result_codes)(sqlite3*,int); + int (*limit)(sqlite3*,int,int); + sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*); + const char *(*sql)(sqlite3_stmt*); + int (*status)(int,int*,int*,int); + int (*backup_finish)(sqlite3_backup*); + sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*); + int (*backup_pagecount)(sqlite3_backup*); + int (*backup_remaining)(sqlite3_backup*); + int (*backup_step)(sqlite3_backup*,int); + const char *(*compileoption_get)(int); + int (*compileoption_used)(const char*); + int (*create_function_v2)(sqlite3*,const char*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void(*xDestroy)(void*)); + int (*db_config)(sqlite3*,int,...); + sqlite3_mutex *(*db_mutex)(sqlite3*); + int (*db_status)(sqlite3*,int,int*,int*,int); + int (*extended_errcode)(sqlite3*); + void (*log)(int,const char*,...); + sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); + const char *(*sourceid)(void); + int (*stmt_status)(sqlite3_stmt*,int,int); + int (*strnicmp)(const char*,const char*,int); + int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); + int (*wal_autocheckpoint)(sqlite3*,int); + int (*wal_checkpoint)(sqlite3*,const char*); + void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); + int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); + int (*vtab_config)(sqlite3*,int op,...); + int (*vtab_on_conflict)(sqlite3*); + /* Version 3.7.16 and later */ + int (*close_v2)(sqlite3*); + const char *(*db_filename)(sqlite3*,const char*); + int (*db_readonly)(sqlite3*,const char*); + int (*db_release_memory)(sqlite3*); + const char *(*errstr)(int); + int (*stmt_busy)(sqlite3_stmt*); + int (*stmt_readonly)(sqlite3_stmt*); + int (*stricmp)(const char*,const char*); + int (*uri_boolean)(const char*,const char*,int); + sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); + const char *(*uri_parameter)(const char*,const char*); + char *(*xvsnprintf)(int,char*,const char*,va_list); + int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); + /* Version 3.8.7 and later */ + int (*auto_extension)(void(*)(void)); + int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, + void(*)(void*)); + int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, + void(*)(void*),unsigned char); + int (*cancel_auto_extension)(void(*)(void)); + int (*load_extension)(sqlite3*,const char*,const char*,char**); + void *(*malloc64)(sqlite3_uint64); + sqlite3_uint64 (*msize)(void*); + void *(*realloc64)(void*,sqlite3_uint64); + void (*reset_auto_extension)(void); + void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, + void(*)(void*)); + void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, + void(*)(void*), unsigned char); + int (*strglob)(const char*,const char*); + /* Version 3.8.11 and later */ + sqlite3_value *(*value_dup)(const sqlite3_value*); + void (*value_free)(sqlite3_value*); + int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64); + int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64); + /* Version 3.9.0 and later */ + unsigned int (*value_subtype)(sqlite3_value*); + void (*result_subtype)(sqlite3_context*,unsigned int); + /* Version 3.10.0 and later */ + int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); + int (*strlike)(const char*,const char*,unsigned int); + int (*db_cacheflush)(sqlite3*); + /* Version 3.12.0 and later */ + int (*system_errno)(sqlite3*); + /* Version 3.14.0 and later */ + int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); + char *(*expanded_sql)(sqlite3_stmt*); + /* Version 3.18.0 and later */ + void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); + /* Version 3.20.0 and later */ + int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, + sqlite3_stmt**,const char**); + int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, + sqlite3_stmt**,const void**); + int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); + void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); + void *(*value_pointer)(sqlite3_value*,const char*); + int (*vtab_nochange)(sqlite3_context*); + int (*value_nochange)(sqlite3_value*); + const char *(*vtab_collation)(sqlite3_index_info*,int); + /* Version 3.24.0 and later */ + int (*keyword_count)(void); + int (*keyword_name)(int,const char**,int*); + int (*keyword_check)(const char*,int); + sqlite3_str *(*str_new)(sqlite3*); + char *(*str_finish)(sqlite3_str*); + void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); + void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); + void (*str_append)(sqlite3_str*, const char *zIn, int N); + void (*str_appendall)(sqlite3_str*, const char *zIn); + void (*str_appendchar)(sqlite3_str*, int N, char C); + void (*str_reset)(sqlite3_str*); + int (*str_errcode)(sqlite3_str*); + int (*str_length)(sqlite3_str*); + char *(*str_value)(sqlite3_str*); + /* Version 3.25.0 and later */ + int (*create_window_function)(sqlite3*,const char*,int,int,void*, + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInv)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*)); + /* Version 3.26.0 and later */ + const char *(*normalized_sql)(sqlite3_stmt*); + /* Version 3.28.0 and later */ + int (*stmt_isexplain)(sqlite3_stmt*); + int (*value_frombind)(sqlite3_value*); + /* Version 3.30.0 and later */ + int (*drop_modules)(sqlite3*,const char**); + /* Version 3.31.0 and later */ + sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64); + const char *(*uri_key)(const char*,int); + const char *(*filename_database)(const char*); + const char *(*filename_journal)(const char*); + const char *(*filename_wal)(const char*); + /* Version 3.32.0 and later */ + const char *(*create_filename)(const char*,const char*,const char*, + int,const char**); + void (*free_filename)(const char*); + sqlite3_file *(*database_file_object)(const char*); + /* Version 3.34.0 and later */ + int (*txn_state)(sqlite3*,const char*); + /* Version 3.36.1 and later */ + sqlite3_int64 (*changes64)(sqlite3*); + sqlite3_int64 (*total_changes64)(sqlite3*); + /* Version 3.37.0 and later */ + int (*autovacuum_pages)(sqlite3*, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, void(*)(void*)); + /* Version 3.38.0 and later */ + int (*error_offset)(sqlite3*); + int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**); + int (*vtab_distinct)(sqlite3_index_info*); + int (*vtab_in)(sqlite3_index_info*,int,int); + int (*vtab_in_first)(sqlite3_value*,sqlite3_value**); + int (*vtab_in_next)(sqlite3_value*,sqlite3_value**); + /* Version 3.39.0 and later */ + int (*deserialize)(sqlite3*,const char*,unsigned char*, + sqlite3_int64,sqlite3_int64,unsigned); + unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*, + unsigned int); + const char *(*db_name)(sqlite3*,int); + /* Version 3.40.0 and later */ + int (*value_encoding)(sqlite3_value*); + /* Version 3.41.0 and later */ + int (*is_interrupted)(sqlite3*); + /* Version 3.43.0 and later */ + int (*stmt_explain)(sqlite3_stmt*,int); + /* Version 3.44.0 and later */ + void *(*get_clientdata)(sqlite3*,const char*); + int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); + /* Version 3.50.0 and later */ + int (*setlk_timeout)(sqlite3*,int,int); + /* Version 3.51.0 and later */ + int (*set_errmsg)(sqlite3*,int,const char*); + int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int); + /* Version 3.52.0 and later */ + void (*str_truncate)(sqlite3_str*,int); + void (*str_free)(sqlite3_str*); + int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*)); + int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*); +}; + +/* +** This is the function signature used for all extension entry points. It +** is also defined in the file "loadext.c". +*/ +typedef int (*sqlite3_loadext_entry)( + sqlite3 *db, /* Handle to the database. */ + char **pzErrMsg, /* Used to set error string on failure. */ + const sqlite3_api_routines *pThunk /* Extension API function pointers. */ +); + +/* +** The following macros redefine the API routines so that they are +** redirected through the global sqlite3_api structure. +** +** This header file is also used by the loadext.c source file +** (part of the main SQLite library - not an extension) so that +** it can get access to the sqlite3_api_routines structure +** definition. But the main library does not want to redefine +** the API. So the redefinition macros are only valid if the +** SQLITE_CORE macros is undefined. +*/ +#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) +#define sqlite3_aggregate_context sqlite3_api->aggregate_context +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_aggregate_count sqlite3_api->aggregate_count +#endif +#define sqlite3_bind_blob sqlite3_api->bind_blob +#define sqlite3_bind_double sqlite3_api->bind_double +#define sqlite3_bind_int sqlite3_api->bind_int +#define sqlite3_bind_int64 sqlite3_api->bind_int64 +#define sqlite3_bind_null sqlite3_api->bind_null +#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count +#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index +#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name +#define sqlite3_bind_text sqlite3_api->bind_text +#define sqlite3_bind_text16 sqlite3_api->bind_text16 +#define sqlite3_bind_value sqlite3_api->bind_value +#define sqlite3_busy_handler sqlite3_api->busy_handler +#define sqlite3_busy_timeout sqlite3_api->busy_timeout +#define sqlite3_changes sqlite3_api->changes +#define sqlite3_close sqlite3_api->close +#define sqlite3_collation_needed sqlite3_api->collation_needed +#define sqlite3_collation_needed16 sqlite3_api->collation_needed16 +#define sqlite3_column_blob sqlite3_api->column_blob +#define sqlite3_column_bytes sqlite3_api->column_bytes +#define sqlite3_column_bytes16 sqlite3_api->column_bytes16 +#define sqlite3_column_count sqlite3_api->column_count +#define sqlite3_column_database_name sqlite3_api->column_database_name +#define sqlite3_column_database_name16 sqlite3_api->column_database_name16 +#define sqlite3_column_decltype sqlite3_api->column_decltype +#define sqlite3_column_decltype16 sqlite3_api->column_decltype16 +#define sqlite3_column_double sqlite3_api->column_double +#define sqlite3_column_int sqlite3_api->column_int +#define sqlite3_column_int64 sqlite3_api->column_int64 +#define sqlite3_column_name sqlite3_api->column_name +#define sqlite3_column_name16 sqlite3_api->column_name16 +#define sqlite3_column_origin_name sqlite3_api->column_origin_name +#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16 +#define sqlite3_column_table_name sqlite3_api->column_table_name +#define sqlite3_column_table_name16 sqlite3_api->column_table_name16 +#define sqlite3_column_text sqlite3_api->column_text +#define sqlite3_column_text16 sqlite3_api->column_text16 +#define sqlite3_column_type sqlite3_api->column_type +#define sqlite3_column_value sqlite3_api->column_value +#define sqlite3_commit_hook sqlite3_api->commit_hook +#define sqlite3_complete sqlite3_api->complete +#define sqlite3_complete16 sqlite3_api->complete16 +#define sqlite3_create_collation sqlite3_api->create_collation +#define sqlite3_create_collation16 sqlite3_api->create_collation16 +#define sqlite3_create_function sqlite3_api->create_function +#define sqlite3_create_function16 sqlite3_api->create_function16 +#define sqlite3_create_module sqlite3_api->create_module +#define sqlite3_create_module_v2 sqlite3_api->create_module_v2 +#define sqlite3_data_count sqlite3_api->data_count +#define sqlite3_db_handle sqlite3_api->db_handle +#define sqlite3_declare_vtab sqlite3_api->declare_vtab +#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache +#define sqlite3_errcode sqlite3_api->errcode +#define sqlite3_errmsg sqlite3_api->errmsg +#define sqlite3_errmsg16 sqlite3_api->errmsg16 +#define sqlite3_exec sqlite3_api->exec +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_expired sqlite3_api->expired +#endif +#define sqlite3_finalize sqlite3_api->finalize +#define sqlite3_free sqlite3_api->free +#define sqlite3_free_table sqlite3_api->free_table +#define sqlite3_get_autocommit sqlite3_api->get_autocommit +#define sqlite3_get_auxdata sqlite3_api->get_auxdata +#define sqlite3_get_table sqlite3_api->get_table +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_global_recover sqlite3_api->global_recover +#endif +#define sqlite3_interrupt sqlite3_api->interruptx +#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid +#define sqlite3_libversion sqlite3_api->libversion +#define sqlite3_libversion_number sqlite3_api->libversion_number +#define sqlite3_malloc sqlite3_api->malloc +#define sqlite3_mprintf sqlite3_api->mprintf +#define sqlite3_open sqlite3_api->open +#define sqlite3_open16 sqlite3_api->open16 +#define sqlite3_prepare sqlite3_api->prepare +#define sqlite3_prepare16 sqlite3_api->prepare16 +#define sqlite3_prepare_v2 sqlite3_api->prepare_v2 +#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 +#define sqlite3_profile sqlite3_api->profile +#define sqlite3_progress_handler sqlite3_api->progress_handler +#define sqlite3_realloc sqlite3_api->realloc +#define sqlite3_reset sqlite3_api->reset +#define sqlite3_result_blob sqlite3_api->result_blob +#define sqlite3_result_double sqlite3_api->result_double +#define sqlite3_result_error sqlite3_api->result_error +#define sqlite3_result_error16 sqlite3_api->result_error16 +#define sqlite3_result_int sqlite3_api->result_int +#define sqlite3_result_int64 sqlite3_api->result_int64 +#define sqlite3_result_null sqlite3_api->result_null +#define sqlite3_result_text sqlite3_api->result_text +#define sqlite3_result_text16 sqlite3_api->result_text16 +#define sqlite3_result_text16be sqlite3_api->result_text16be +#define sqlite3_result_text16le sqlite3_api->result_text16le +#define sqlite3_result_value sqlite3_api->result_value +#define sqlite3_rollback_hook sqlite3_api->rollback_hook +#define sqlite3_set_authorizer sqlite3_api->set_authorizer +#define sqlite3_set_auxdata sqlite3_api->set_auxdata +#define sqlite3_snprintf sqlite3_api->xsnprintf +#define sqlite3_step sqlite3_api->step +#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata +#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup +#define sqlite3_total_changes sqlite3_api->total_changes +#define sqlite3_trace sqlite3_api->trace +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings +#endif +#define sqlite3_update_hook sqlite3_api->update_hook +#define sqlite3_user_data sqlite3_api->user_data +#define sqlite3_value_blob sqlite3_api->value_blob +#define sqlite3_value_bytes sqlite3_api->value_bytes +#define sqlite3_value_bytes16 sqlite3_api->value_bytes16 +#define sqlite3_value_double sqlite3_api->value_double +#define sqlite3_value_int sqlite3_api->value_int +#define sqlite3_value_int64 sqlite3_api->value_int64 +#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type +#define sqlite3_value_text sqlite3_api->value_text +#define sqlite3_value_text16 sqlite3_api->value_text16 +#define sqlite3_value_text16be sqlite3_api->value_text16be +#define sqlite3_value_text16le sqlite3_api->value_text16le +#define sqlite3_value_type sqlite3_api->value_type +#define sqlite3_vmprintf sqlite3_api->vmprintf +#define sqlite3_vsnprintf sqlite3_api->xvsnprintf +#define sqlite3_overload_function sqlite3_api->overload_function +#define sqlite3_prepare_v2 sqlite3_api->prepare_v2 +#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 +#define sqlite3_clear_bindings sqlite3_api->clear_bindings +#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob +#define sqlite3_blob_bytes sqlite3_api->blob_bytes +#define sqlite3_blob_close sqlite3_api->blob_close +#define sqlite3_blob_open sqlite3_api->blob_open +#define sqlite3_blob_read sqlite3_api->blob_read +#define sqlite3_blob_write sqlite3_api->blob_write +#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2 +#define sqlite3_file_control sqlite3_api->file_control +#define sqlite3_memory_highwater sqlite3_api->memory_highwater +#define sqlite3_memory_used sqlite3_api->memory_used +#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc +#define sqlite3_mutex_enter sqlite3_api->mutex_enter +#define sqlite3_mutex_free sqlite3_api->mutex_free +#define sqlite3_mutex_leave sqlite3_api->mutex_leave +#define sqlite3_mutex_try sqlite3_api->mutex_try +#define sqlite3_open_v2 sqlite3_api->open_v2 +#define sqlite3_release_memory sqlite3_api->release_memory +#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem +#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig +#define sqlite3_sleep sqlite3_api->sleep +#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit +#define sqlite3_vfs_find sqlite3_api->vfs_find +#define sqlite3_vfs_register sqlite3_api->vfs_register +#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister +#define sqlite3_threadsafe sqlite3_api->xthreadsafe +#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob +#define sqlite3_result_error_code sqlite3_api->result_error_code +#define sqlite3_test_control sqlite3_api->test_control +#define sqlite3_randomness sqlite3_api->randomness +#define sqlite3_context_db_handle sqlite3_api->context_db_handle +#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes +#define sqlite3_limit sqlite3_api->limit +#define sqlite3_next_stmt sqlite3_api->next_stmt +#define sqlite3_sql sqlite3_api->sql +#define sqlite3_status sqlite3_api->status +#define sqlite3_backup_finish sqlite3_api->backup_finish +#define sqlite3_backup_init sqlite3_api->backup_init +#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount +#define sqlite3_backup_remaining sqlite3_api->backup_remaining +#define sqlite3_backup_step sqlite3_api->backup_step +#define sqlite3_compileoption_get sqlite3_api->compileoption_get +#define sqlite3_compileoption_used sqlite3_api->compileoption_used +#define sqlite3_create_function_v2 sqlite3_api->create_function_v2 +#define sqlite3_db_config sqlite3_api->db_config +#define sqlite3_db_mutex sqlite3_api->db_mutex +#define sqlite3_db_status sqlite3_api->db_status +#define sqlite3_extended_errcode sqlite3_api->extended_errcode +#define sqlite3_log sqlite3_api->log +#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64 +#define sqlite3_sourceid sqlite3_api->sourceid +#define sqlite3_stmt_status sqlite3_api->stmt_status +#define sqlite3_strnicmp sqlite3_api->strnicmp +#define sqlite3_unlock_notify sqlite3_api->unlock_notify +#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint +#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint +#define sqlite3_wal_hook sqlite3_api->wal_hook +#define sqlite3_blob_reopen sqlite3_api->blob_reopen +#define sqlite3_vtab_config sqlite3_api->vtab_config +#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict +/* Version 3.7.16 and later */ +#define sqlite3_close_v2 sqlite3_api->close_v2 +#define sqlite3_db_filename sqlite3_api->db_filename +#define sqlite3_db_readonly sqlite3_api->db_readonly +#define sqlite3_db_release_memory sqlite3_api->db_release_memory +#define sqlite3_errstr sqlite3_api->errstr +#define sqlite3_stmt_busy sqlite3_api->stmt_busy +#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly +#define sqlite3_stricmp sqlite3_api->stricmp +#define sqlite3_uri_boolean sqlite3_api->uri_boolean +#define sqlite3_uri_int64 sqlite3_api->uri_int64 +#define sqlite3_uri_parameter sqlite3_api->uri_parameter +#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf +#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 +/* Version 3.8.7 and later */ +#define sqlite3_auto_extension sqlite3_api->auto_extension +#define sqlite3_bind_blob64 sqlite3_api->bind_blob64 +#define sqlite3_bind_text64 sqlite3_api->bind_text64 +#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension +#define sqlite3_load_extension sqlite3_api->load_extension +#define sqlite3_malloc64 sqlite3_api->malloc64 +#define sqlite3_msize sqlite3_api->msize +#define sqlite3_realloc64 sqlite3_api->realloc64 +#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension +#define sqlite3_result_blob64 sqlite3_api->result_blob64 +#define sqlite3_result_text64 sqlite3_api->result_text64 +#define sqlite3_strglob sqlite3_api->strglob +/* Version 3.8.11 and later */ +#define sqlite3_value_dup sqlite3_api->value_dup +#define sqlite3_value_free sqlite3_api->value_free +#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64 +#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64 +/* Version 3.9.0 and later */ +#define sqlite3_value_subtype sqlite3_api->value_subtype +#define sqlite3_result_subtype sqlite3_api->result_subtype +/* Version 3.10.0 and later */ +#define sqlite3_status64 sqlite3_api->status64 +#define sqlite3_strlike sqlite3_api->strlike +#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush +/* Version 3.12.0 and later */ +#define sqlite3_system_errno sqlite3_api->system_errno +/* Version 3.14.0 and later */ +#define sqlite3_trace_v2 sqlite3_api->trace_v2 +#define sqlite3_expanded_sql sqlite3_api->expanded_sql +/* Version 3.18.0 and later */ +#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid +/* Version 3.20.0 and later */ +#define sqlite3_prepare_v3 sqlite3_api->prepare_v3 +#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3 +#define sqlite3_bind_pointer sqlite3_api->bind_pointer +#define sqlite3_result_pointer sqlite3_api->result_pointer +#define sqlite3_value_pointer sqlite3_api->value_pointer +/* Version 3.22.0 and later */ +#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange +#define sqlite3_value_nochange sqlite3_api->value_nochange +#define sqlite3_vtab_collation sqlite3_api->vtab_collation +/* Version 3.24.0 and later */ +#define sqlite3_keyword_count sqlite3_api->keyword_count +#define sqlite3_keyword_name sqlite3_api->keyword_name +#define sqlite3_keyword_check sqlite3_api->keyword_check +#define sqlite3_str_new sqlite3_api->str_new +#define sqlite3_str_finish sqlite3_api->str_finish +#define sqlite3_str_appendf sqlite3_api->str_appendf +#define sqlite3_str_vappendf sqlite3_api->str_vappendf +#define sqlite3_str_append sqlite3_api->str_append +#define sqlite3_str_appendall sqlite3_api->str_appendall +#define sqlite3_str_appendchar sqlite3_api->str_appendchar +#define sqlite3_str_reset sqlite3_api->str_reset +#define sqlite3_str_errcode sqlite3_api->str_errcode +#define sqlite3_str_length sqlite3_api->str_length +#define sqlite3_str_value sqlite3_api->str_value +/* Version 3.25.0 and later */ +#define sqlite3_create_window_function sqlite3_api->create_window_function +/* Version 3.26.0 and later */ +#define sqlite3_normalized_sql sqlite3_api->normalized_sql +/* Version 3.28.0 and later */ +#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain +#define sqlite3_value_frombind sqlite3_api->value_frombind +/* Version 3.30.0 and later */ +#define sqlite3_drop_modules sqlite3_api->drop_modules +/* Version 3.31.0 and later */ +#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64 +#define sqlite3_uri_key sqlite3_api->uri_key +#define sqlite3_filename_database sqlite3_api->filename_database +#define sqlite3_filename_journal sqlite3_api->filename_journal +#define sqlite3_filename_wal sqlite3_api->filename_wal +/* Version 3.32.0 and later */ +#define sqlite3_create_filename sqlite3_api->create_filename +#define sqlite3_free_filename sqlite3_api->free_filename +#define sqlite3_database_file_object sqlite3_api->database_file_object +/* Version 3.34.0 and later */ +#define sqlite3_txn_state sqlite3_api->txn_state +/* Version 3.36.1 and later */ +#define sqlite3_changes64 sqlite3_api->changes64 +#define sqlite3_total_changes64 sqlite3_api->total_changes64 +/* Version 3.37.0 and later */ +#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages +/* Version 3.38.0 and later */ +#define sqlite3_error_offset sqlite3_api->error_offset +#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value +#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct +#define sqlite3_vtab_in sqlite3_api->vtab_in +#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first +#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next +/* Version 3.39.0 and later */ +#ifndef SQLITE_OMIT_DESERIALIZE +#define sqlite3_deserialize sqlite3_api->deserialize +#define sqlite3_serialize sqlite3_api->serialize +#endif +#define sqlite3_db_name sqlite3_api->db_name +/* Version 3.40.0 and later */ +#define sqlite3_value_encoding sqlite3_api->value_encoding +/* Version 3.41.0 and later */ +#define sqlite3_is_interrupted sqlite3_api->is_interrupted +/* Version 3.43.0 and later */ +#define sqlite3_stmt_explain sqlite3_api->stmt_explain +/* Version 3.44.0 and later */ +#define sqlite3_get_clientdata sqlite3_api->get_clientdata +#define sqlite3_set_clientdata sqlite3_api->set_clientdata +/* Version 3.50.0 and later */ +#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout +/* Version 3.51.0 and later */ +#define sqlite3_set_errmsg sqlite3_api->set_errmsg +#define sqlite3_db_status64 sqlite3_api->db_status64 +/* Version 3.52.0 and later */ +#define sqlite3_str_truncate sqlite3_api->str_truncate +#define sqlite3_str_free sqlite3_api->str_free +#define sqlite3_carray_bind sqlite3_api->carray_bind +#define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2 +#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ + +#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) + /* This case when the file really is being compiled as a loadable + ** extension */ +# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; +# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; +# define SQLITE_EXTENSION_INIT3 \ + extern const sqlite3_api_routines *sqlite3_api; +#else + /* This case when the file is being statically linked into the + ** application */ +# define SQLITE_EXTENSION_INIT1 /*no-op*/ +# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ +# define SQLITE_EXTENSION_INIT3 /*no-op*/ +#endif + +#endif /* SQLITE3EXT_H */ +/*** End of #include "sqlite3ext.h" ***/ + + +struct sqlite3mc_core_routines { + int (*initialize)(void); + int (*shutdown)(void); + int (*config)(int, ...); + int (*enable_load_extension)(sqlite3*, int); + int (*memory_alarm)(void(*)(void*, sqlite3_int64, int), void*, sqlite3_int64); + int (*mutex_held)(sqlite3_mutex*); + int (*mutex_notheld)(sqlite3_mutex*); + int (*os_init)(void); + int (*os_end)(void); + int (*preupdate_blobwrite)(sqlite3*); + int (*preupdate_count)(sqlite3*); + int (*preupdate_depth)(sqlite3*); + void* (*preupdate_hook)(sqlite3*, + void(*xPreUpdate)(void*, sqlite3*, int, char const*, char const*, sqlite3_int64, sqlite3_int64), + void*); + int (*preupdate_old)(sqlite3*, int, sqlite3_value**); + int (*preupdate_new)(sqlite3*, int, sqlite3_value**); + + int (*snapshot_cmp)(sqlite3_snapshot*, sqlite3_snapshot*); + void (*snapshot_free)(sqlite3_snapshot*); + int (*snapshot_get)(sqlite3*, const char*, sqlite3_snapshot**); + int (*snapshot_open)(sqlite3*, const char*, sqlite3_snapshot*); + int (*snapshot_recover)(sqlite3*, const char*); + + int (*stmt_scanstatus)(sqlite3_stmt*, int, int, void*); + int (*stmt_scanstatus_v2)(sqlite3_stmt*, int, int, int, void*); + void (*stmt_scanstatus_reset)(sqlite3_stmt*); + + int (*win32_set_directory)(unsigned long type, void* zValue); + int (*win32_set_directory8)(unsigned long type, const char* zValue); + int (*win32_set_directory16)(unsigned long type, const void* zValue); +}; + +struct sqlite3mc_api_routines { + void (*activate_see)(const char* zPassPhrase); + int (*key)(sqlite3* db, const void* pKey, int nKey); + int (*key_v2)(sqlite3*, const char* zDbName, const void* pKey, int nKey); + int (*rekey)(sqlite3*, const void* pKey, int nKey); + int (*rekey_v2)(sqlite3*, const char* zDbName, const void* pKey, int nKey); + + const char* (*mc_version)(); + int (*mc_cipher_count)(); + int (*mc_cipher_index)(const char* cipherName); + const char* (*mc_cipher_name)(int cipherIndex); + int (*mc_cipher_name_copy)(int cipherIndex, char* cipherName, int maxCipherNameSize); + int (*mc_config)(sqlite3* db, const char* paramName, int newValue); + int (*mc_config_cipher)(sqlite3* db, const char* cipherName, const char* paramName, int newValue); + unsigned char* (*mc_codec_data)(sqlite3* db, const char* zDbName, const char* paramName); + + int (*mc_vfs_create)(const char* zVfsReal, int makeDefault); + void (*mc_vfs_destroy)(const char* zName); + void (*mc_vfs_shutdown)(); +}; + +typedef struct sqlite3mc_core_routines sqlite3mc_core_routines; +typedef struct sqlite3mc_api_routines sqlite3mc_api_routines; + +#ifndef SQLITE3MC_DISPATCH_API +#if defined(_WIN32) +#define SQLITE3MC_DISPATCH_API __declspec(dllexport) +#else +#define SQLITE3MC_DISPATCH_API +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +SQLITE3MC_DISPATCH_API extern const sqlite3_api_routines* SQLITE3MC_API_TABLE_EXT; +SQLITE3MC_DISPATCH_API extern const sqlite3mc_core_routines* SQLITE3MC_API_TABLE_CORE; +SQLITE3MC_DISPATCH_API extern const sqlite3mc_api_routines* SQLITE3MC_API_TABLE_MC; + +#ifdef __cplusplus +} /* End of the 'extern "C"' block */ +#endif + +#if !defined(SQLITE_CORE) + +/* SQLite core API - not defined in sqlite3ext.h */ + +#define sqlite3_initialize SQLITE3MC_API_TABLE_CORE->initialize +#define sqlite3_shutdown SQLITE3MC_API_TABLE_CORE->shutdown +#define sqlite3_config SQLITE3MC_API_TABLE_CORE->config +#define sqlite3_enable_load_extension SQLITE3MC_API_TABLE_CORE->enable_load_extension +#define sqlite3_memory_alarm SQLITE3MC_API_TABLE_CORE->memory_alarm +#define sqlite3_mutex_held SQLITE3MC_API_TABLE_CORE->mutex_held +#define sqlite3_mutex_notheld SQLITE3MC_API_TABLE_CORE->mutex_notheld +#define sqlite3_os_init SQLITE3MC_API_TABLE_CORE->os_init +#define sqlite3_os_end SQLITE3MC_API_TABLE_CORE->os_end +#define sqlite3_preupdate_blobwrite SQLITE3MC_API_TABLE_CORE->preupdate_blobwrite +#define sqlite3_preupdate_count SQLITE3MC_API_TABLE_CORE->preupdate_count +#define sqlite3_preupdate_depth SQLITE3MC_API_TABLE_CORE->preupdate_depth +#define sqlite3_preupdate_hook SQLITE3MC_API_TABLE_CORE->preupdate_hook +#define sqlite3_preupdate_old SQLITE3MC_API_TABLE_CORE->preupdate_old +#define sqlite3_preupdate_new SQLITE3MC_API_TABLE_CORE->preupdate_new + +#define sqlite3_snapshot_cmp SQLITE3MC_API_TABLE_CORE->snapshot_cmp +#define sqlite3_snapshot_free SQLITE3MC_API_TABLE_CORE->snapshot_free +#define sqlite3_snapshot_get SQLITE3MC_API_TABLE_CORE->snapshot_get +#define sqlite3_snapshot_open SQLITE3MC_API_TABLE_CORE->snapshot_open +#define sqlite3_snapshot_recover SQLITE3MC_API_TABLE_CORE->snapshot_recover + +#define sqlite3_stmt_scanstatus SQLITE3MC_API_TABLE_CORE->stmt_scanstatus +#define sqlite3_stmt_scanstatus_v2 SQLITE3MC_API_TABLE_CORE->stmt_scanstatus_v2 +#define sqlite3_stmt_scanstatus_reset SQLITE3MC_API_TABLE_CORE->stmt_scanstatus_reset + +#define sqlite3_win32_set_directory SQLITE3MC_API_TABLE_CORE->win32_set_directory +#define sqlite3_win32_set_directory8 SQLITE3MC_API_TABLE_CORE->win32_set_directory8 +#define sqlite3_win32_set_directory16 SQLITE3MC_API_TABLE_CORE->win32_set_directory16 + +/* SQLite3 Multiple Ciphers API */ + +#define sqlite3_activate_see SQLITE3MC_API_TABLE_MC->activate_see +#define sqlite3_key SQLITE3MC_API_TABLE_MC->key +#define sqlite3_key_v2 SQLITE3MC_API_TABLE_MC->key_v2 +#define sqlite3_rekey SQLITE3MC_API_TABLE_MC->rekey +#define sqlite3_rekey_v2 SQLITE3MC_API_TABLE_MC->rekey_v2 + +#define sqlite3mc_version SQLITE3MC_API_TABLE_MC->mc_version +#define sqlite3mc_cipher_count SQLITE3MC_API_TABLE_MC->mc_cipher_count +#define sqlite3mc_cipher_index SQLITE3MC_API_TABLE_MC->mc_cipher_index +#define sqlite3mc_cipher_name SQLITE3MC_API_TABLE_MC->mc_cipher_name +#define sqlite3mc_cipher_name_copy SQLITE3MC_API_TABLE_MC->mc_cipher_name_copy +#define sqlite3mc_config SQLITE3MC_API_TABLE_MC->mc_config +#define sqlite3mc_config_cipher SQLITE3MC_API_TABLE_MC->mc_config_cipher +#define sqlite3mc_codec_data SQLITE3MC_API_TABLE_MC->mc_codec_data + +#define sqlite3mc_vfs_create SQLITE3MC_API_TABLE_MC->mc_vfs_create +#define sqlite3mc_vfs_destroy SQLITE3MC_API_TABLE_MC->mc_vfs_destroy +#define sqlite3mc_vfs_shutdown SQLITE3MC_API_TABLE_MC->mc_vfs_shutdown + +#endif /* !SQLITE_CORE */ + +#endif /* SQLITE3MC_USE_DISPATCH_TABLE */ + +#endif /* SQLITE3MC_H_ */ /*** End of #include "sqlite3mc.h" ***/ @@ -276617,7 +287476,7 @@ int main() /*** End of #include "sha2.c" ***/ -#if HAVE_CIPHER_CHACHA20 || HAVE_CIPHER_SQLCIPHER || HAVE_CIPHER_ASCON128 +#if HAVE_CIPHER_CHACHA20 || HAVE_CIPHER_SQLCIPHER || HAVE_CIPHER_ASCON128 || HAVE_CIPHER_AEGIS /* #include "fastpbkdf2.c" */ /*** Begin of #include "fastpbkdf2.c" ***/ /* @@ -276731,9 +287590,6 @@ void sqlcipher_hmac(int algorithm, #include #include -#if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__clang__) && !defined(__QNX__) -#include -#endif /* #include "sha1.h" */ @@ -276741,7 +287597,7 @@ void sqlcipher_hmac(int algorithm, /* --- MSVC doesn't support C99 --- */ -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) #define restrict #define inline __inline #define _Pragma __pragma @@ -276754,23 +287610,41 @@ void sqlcipher_hmac(int algorithm, static inline void write32_be(uint32_t n, uint8_t out[4]) { -#if defined(__GNUC__) && __GNUC__ >= 4 && __BYTE_ORDER == __LITTLE_ENDIAN - *(uint32_t *)(out) = __builtin_bswap32(n); +#if SQLITE_BYTEORDER==4321 + memcpy(out, &n, 4); +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + u32 x = __builtin_bswap32(n); + memcpy(out, &x, 4); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + u32 x = _byteswap_ulong(n); + memcpy(out, &x, 4); #else - out[0] = (n >> 24) & 0xff; - out[1] = (n >> 16) & 0xff; - out[2] = (n >> 8) & 0xff; - out[3] = n & 0xff; + out[0] = (n >> 24) & 0xFF; + out[1] = (n >> 16) & 0xFF; + out[2] = (n >> 8) & 0xFF; + out[3] = (n >> 0) & 0xFF; #endif } static inline void write64_be(uint64_t n, uint8_t out[8]) { -#if defined(__GNUC__) && __GNUC__ >= 4 && __BYTE_ORDER == __LITTLE_ENDIAN - *(uint64_t *)(out) = __builtin_bswap64(n); +#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + n = __builtin_bswap64(n); + memcpy(out, &n, 8); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + n = _byteswap_uint64(n); + memcpy(out, &n, 8); +#elif SQLITE_BYTEORDER==4321 + memcpy(out, &n, 8); #else - write32_be((n >> 32) & 0xffffffff, out); - write32_be(n & 0xffffffff, out + 4); + out[0] = (n >> 56) & 0xFF; + out[1] = (n >> 48) & 0xFF; + out[2] = (n >> 40) & 0xFF; + out[3] = (n >> 32) & 0xFF; + out[4] = (n >> 24) & 0xFF; + out[5] = (n >> 16) & 0xFF; + out[6] = (n >> 8) & 0xFF; + out[7] = (n >> 0) & 0xFF; #endif } @@ -277581,18 +288455,23 @@ static size_t read_urandom(void* buf, size_t n) } #if defined(__APPLE__) -#include + #if defined(__clang__) || defined(__GNUC__) + #if __has_include() + #include + #define HAVE_COMMONCRYPTO_COMMONRANDOM_H 1 + #endif + #endif #endif static size_t entropy(void* buf, size_t n) { -#if defined(__APPLE__) - if (SecRandomCopyBytes(kSecRandomDefault, n, (uint8_t*) buf) == 0) +#if defined(__APPLE__) && defined(HAVE_COMMONCRYPTO_COMMONRANDOM_H) + if (CCRandomGenerateBytes(buf, n) == kCCSuccess) return n; #elif defined(__linux__) && defined(SYS_getrandom) if (syscall(SYS_getrandom, buf, n, 0) == n) return n; -#elif defined(SYS_getentropy) +#elif defined(__linux__) && defined(SYS_getentropy) if (syscall(SYS_getentropy, buf, n) == 0) return n; #endif @@ -277648,372 +288527,6 @@ void chacha20_rng(void* out, size_t n) #endif -#ifdef SQLITE_USER_AUTHENTICATION -/* #include "userauth.c" */ -/*** Begin of #include "userauth.c" ***/ -/* -** 2014-09-08 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This file contains the bulk of the implementation of the -** user-authentication extension feature. Some parts of the user- -** authentication code are contained within the SQLite core (in the -** src/ subdirectory of the main source code tree) but those parts -** that could reasonable be separated out are moved into this file. -** -** To compile with the user-authentication feature, append this file to -** end of an SQLite amalgamation, then add the SQLITE_USER_AUTHENTICATION -** compile-time option. See the user-auth.txt file in the same source -** directory as this file for additional information. -*/ -#ifdef SQLITE_USER_AUTHENTICATION -#ifndef SQLITEINT_H -# include "sqliteInt.h" -#endif - -/* -** Prepare an SQL statement for use by the user authentication logic. -** Return a pointer to the prepared statement on success. Return a -** NULL pointer if there is an error of any kind. -*/ -static sqlite3_stmt *sqlite3UserAuthPrepare( - sqlite3 *db, - const char *zFormat, - ... -){ - sqlite3_stmt *pStmt; - char *zSql; - int rc; - va_list ap; - u64 savedFlags = db->flags; - - va_start(ap, zFormat); - zSql = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - if( zSql==0 ) return 0; - db->flags |= SQLITE_WriteSchema; - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - db->flags = savedFlags; - sqlite3_free(zSql); - if( rc ){ - sqlite3_finalize(pStmt); - pStmt = 0; - } - return pStmt; -} - -/* -** Check to see if the sqlite_user table exists in database zDb. -*/ -static int userTableExists(sqlite3 *db, const char *zDb){ - int rc; - sqlite3_mutex_enter(db->mutex); - sqlite3BtreeEnterAll(db); - if( db->init.busy==0 ){ - char *zErr = 0; - sqlite3Init(db, &zErr); - sqlite3DbFree(db, zErr); - } - rc = sqlite3FindTable(db, "sqlite_user", zDb)!=0; - sqlite3BtreeLeaveAll(db); - sqlite3_mutex_leave(db->mutex); - return rc; -} - -/* -** Check to see if database zDb has a "sqlite_user" table and if it does -** whether that table can authenticate zUser with nPw,zPw. Write one of -** the UAUTH_* user authorization level codes into *peAuth and return a -** result code. -*/ -static int userAuthCheckLogin( - sqlite3 *db, /* The database connection to check */ - const char *zDb, /* Name of specific database to check */ - u8 *peAuth /* OUT: One of UAUTH_* constants */ -){ - sqlite3_stmt *pStmt; - int rc; - - *peAuth = UAUTH_Unknown; - if( !userTableExists(db, zDb) ){ - *peAuth = UAUTH_Admin; /* No sqlite_user table. Everybody is admin. */ - return SQLITE_OK; - } - if( db->auth.zAuthUser==0 ){ - *peAuth = UAUTH_Fail; - return SQLITE_OK; - } - pStmt = sqlite3UserAuthPrepare(db, - "SELECT pw=sqlite_crypt(?1,pw), isAdmin FROM \"%w\".sqlite_user" - " WHERE uname=?2", zDb); - if( pStmt==0 ) return SQLITE_NOMEM; - sqlite3_bind_blob(pStmt, 1, db->auth.zAuthPW, db->auth.nAuthPW,SQLITE_STATIC); - sqlite3_bind_text(pStmt, 2, db->auth.zAuthUser, -1, SQLITE_STATIC); - rc = sqlite3_step(pStmt); - if( rc==SQLITE_ROW && sqlite3_column_int(pStmt,0) ){ - *peAuth = sqlite3_column_int(pStmt, 1) + UAUTH_User; - }else{ - *peAuth = UAUTH_Fail; - } - return sqlite3_finalize(pStmt); -} -int sqlite3UserAuthCheckLogin( - sqlite3 *db, /* The database connection to check */ - const char *zDb, /* Name of specific database to check */ - u8 *peAuth /* OUT: One of UAUTH_* constants */ -){ - int rc; - u8 savedAuthLevel; - assert( zDb!=0 ); - assert( peAuth!=0 ); - savedAuthLevel = db->auth.authLevel; - db->auth.authLevel = UAUTH_Admin; - rc = userAuthCheckLogin(db, zDb, peAuth); - db->auth.authLevel = savedAuthLevel; - return rc; -} - -/* -** If the current authLevel is UAUTH_Unknown, the take actions to figure -** out what authLevel should be -*/ -void sqlite3UserAuthInit(sqlite3 *db){ - if( db->auth.authLevel==UAUTH_Unknown ){ - u8 authLevel = UAUTH_Fail; - sqlite3UserAuthCheckLogin(db, "main", &authLevel); - db->auth.authLevel = authLevel; - if( authLevelflags &= ~SQLITE_WriteSchema; - } -} - -/* -** Implementation of the sqlite_crypt(X,Y) function. -** -** If Y is NULL then generate a new hash for password X and return that -** hash. If Y is not null, then generate a hash for password X using the -** same salt as the previous hash Y and return the new hash. -*/ -void sqlite3CryptFunc( - sqlite3_context *context, - int NotUsed, - sqlite3_value **argv -){ - const char *zIn; - int nIn; - u8 *zData; - u8 *zOut; - char zSalt[16]; - int nHash = 32; - zIn = sqlite3_value_blob(argv[0]); - nIn = sqlite3_value_bytes(argv[0]); - if( sqlite3_value_type(argv[1])==SQLITE_BLOB - && sqlite3_value_bytes(argv[1])==nHash+sizeof(zSalt) - ){ - memcpy(zSalt, sqlite3_value_blob(argv[1]), sizeof(zSalt)); - }else{ - sqlite3_randomness(sizeof(zSalt), zSalt); - } - zData = sqlite3_malloc( nIn+sizeof(zSalt) ); - zOut = sqlite3_malloc( nHash+sizeof(zSalt) ); - if( zOut==0 ){ - sqlite3_result_error_nomem(context); - }else{ - memcpy(zData, zSalt, sizeof(zSalt)); - memcpy(zData+sizeof(zSalt), zIn, nIn); - memcpy(zOut, zSalt, sizeof(zSalt)); - sha256(zData, (unsigned int) nIn+sizeof(zSalt), zOut+sizeof(zSalt)); - sqlite3_result_blob(context, zOut, nHash+sizeof(zSalt), sqlite3_free); - } - if (zData != 0) sqlite3_free(zData); -} - -/* -** If a database contains the SQLITE_USER table, then the -** sqlite3_user_authenticate() interface must be invoked with an -** appropriate username and password prior to enable read and write -** access to the database. -** -** Return SQLITE_OK on success or SQLITE_ERROR if the username/password -** combination is incorrect or unknown. -** -** If the SQLITE_USER table is not present in the database file, then -** this interface is a harmless no-op returnning SQLITE_OK. -*/ -SQLITE_API int sqlite3_user_authenticate( - sqlite3 *db, /* The database connection */ - const char *zUsername, /* Username */ - const char *zPW, /* Password or credentials */ - int nPW /* Number of bytes in aPW[] */ -){ - int rc; - u8 authLevel = UAUTH_Fail; - db->auth.authLevel = UAUTH_Unknown; - sqlite3_free(db->auth.zAuthUser); - sqlite3_free(db->auth.zAuthPW); - memset(&db->auth, 0, sizeof(db->auth)); - db->auth.zAuthUser = sqlite3_mprintf("%s", zUsername); - if( db->auth.zAuthUser==0 ) return SQLITE_NOMEM; - db->auth.zAuthPW = sqlite3_malloc( nPW+1 ); - if( db->auth.zAuthPW==0 ) return SQLITE_NOMEM; - memcpy(db->auth.zAuthPW,zPW,nPW); - db->auth.nAuthPW = nPW; - rc = sqlite3UserAuthCheckLogin(db, "main", &authLevel); - db->auth.authLevel = authLevel; - sqlite3ExpirePreparedStatements(db, 0); - if( rc ){ - return rc; /* OOM error, I/O error, etc. */ - } - if( authLevelauth.authLevelauth.zAuthUser==0 ){ - assert( isAdmin!=0 ); - sqlite3_user_authenticate(db, zUsername, aPW, nPW); - } - return SQLITE_OK; -} - -/* -** The sqlite3_user_change() interface can be used to change a users -** login credentials or admin privilege. Any user can change their own -** login credentials. Only an admin user can change another users login -** credentials or admin privilege setting. No user may change their own -** admin privilege setting. -*/ -SQLITE_API int sqlite3_user_change( - sqlite3 *db, /* Database connection */ - const char *zUsername, /* Username to change */ - const char *aPW, /* Modified password or credentials */ - int nPW, /* Number of bytes in aPW[] */ - int isAdmin /* Modified admin privilege for the user */ -){ - sqlite3_stmt *pStmt; - int rc = SQLITE_OK; - u8 authLevel; - - authLevel = db->auth.authLevel; - if( authLevelauth.zAuthUser, zUsername)!=0 ){ - if( db->auth.authLevelauth.authLevel = UAUTH_Admin; - if( !userTableExists(db, "main") ){ - /* This routine is a no-op if the user to be modified does not exist */ - }else{ - pStmt = sqlite3UserAuthPrepare(db, - "UPDATE sqlite_user SET isAdmin=%d, pw=sqlite_crypt(?1,NULL)" - " WHERE uname=%Q", isAdmin, zUsername); - if( pStmt==0 ){ - rc = SQLITE_NOMEM; - }else{ - sqlite3_bind_blob(pStmt, 1, aPW, nPW, SQLITE_STATIC); - sqlite3_step(pStmt); - rc = sqlite3_finalize(pStmt); - } - } - db->auth.authLevel = authLevel; - return rc; -} - -/* -** The sqlite3_user_delete() interface can be used (by an admin user only) -** to delete a user. The currently logged-in user cannot be deleted, -** which guarantees that there is always an admin user and hence that -** the database cannot be converted into a no-authentication-required -** database. -*/ -SQLITE_API int sqlite3_user_delete( - sqlite3 *db, /* Database connection */ - const char *zUsername /* Username to remove */ -){ - sqlite3_stmt *pStmt; - if( db->auth.authLevelauth.zAuthUser, zUsername)==0 ){ - /* Cannot delete self */ - return SQLITE_AUTH; - } - if( !userTableExists(db, "main") ){ - /* This routine is a no-op if the user to be deleted does not exist */ - return SQLITE_OK; - } - pStmt = sqlite3UserAuthPrepare(db, - "DELETE FROM sqlite_user WHERE uname=%Q", zUsername); - if( pStmt==0 ) return SQLITE_NOMEM; - sqlite3_step(pStmt); - return sqlite3_finalize(pStmt); -} - -#endif /* SQLITE_USER_AUTHENTICATION */ -/*** End of #include "userauth.c" ***/ - -#endif - /* ** Declare function prototype for registering the codec extension functions */ @@ -278396,6 +288909,9 @@ SQLITE_PRIVATE void RijndaelDecrypt(Rijndael* rijndael, UINT8 a[16], UINT8 b[16] #endif /* SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT */ +#if defined(__GNUC__) +#pragma GCC push_options +#endif #if HAS_AES_HARDWARE != AES_HARDWARE_NONE /* --- Implementation of common data and functions for any AES hardware --- */ @@ -278419,6 +288935,37 @@ toUint32FromLE(const void* buffer) #if HAS_AES_HARDWARE == AES_HARDWARE_NI /* --- Implementation for AES-NI --- */ +/* Define SQLITE3MC_COMPILER_HAS_ATTRIBUTE */ +#if defined(__has_attribute) + #define SQLITE3MC_COMPILER_HAS_ATTRIBUTE(x) __has_attribute(x) + #define SQLITE3MC_COMPILER_ATTRIBUTE(x) __attribute__((x)) +#else + #define SQLITE3MC_COMPILER_HAS_ATTRIBUTE(x) 0 + #define SQLITE3MC_COMPILER_ATTRIBUTE(x) /**/ +#endif + +/* Define SQLITE3MC_FORCE_INLINE */ +#if !defined(SQLITE3MC_FORCE_INLINE) + #if SQLITE3MC_COMPILER_HAS_ATTRIBUTE(always_inline) + #define SQLITE3MC_FORCE_INLINE inline SQLITE3MC_COMPILER_ATTRIBUTE(always_inline) + #elif defined(_MSC_VER) + #define SQLITE3MC_FORCE_INLINE __forceinline + #else + #define SQLITE3MC_FORCE_INLINE inline + #endif +#endif + +/* Define SQLITE3MC_FUNC_ISA */ +#if SQLITE3MC_COMPILER_HAS_ATTRIBUTE(target) + #define SQLITE3MC_FUNC_ISA(isa) SQLITE3MC_COMPILER_ATTRIBUTE(target(isa)) +#else + #define SQLITE3MC_FUNC_ISA(isa) +#endif + +/* Define SQLITE3MC_FUNC_ISA_INLINE */ +#define SQLITE3MC_FUNC_ISA_INLINE(isa) SQLITE3MC_FUNC_ISA(isa) SQLITE3MC_FORCE_INLINE + + /* ** Define function for detecting hardware AES support at runtime */ @@ -278452,9 +288999,18 @@ aesHardwareCheck() #endif /* defined(__clang__) || defined(__GNUC__) */ +#if defined(__GNUC__) +#pragma GCC push_options +#endif + #include #include +#if defined(__GNUC__) +#pragma GCC pop_options +#endif + +SQLITE3MC_FUNC_ISA("sse4.2,aes") static int aesGenKeyEncryptInternal(const unsigned char* userKey, const int bits, __m128i* keyData) { @@ -278508,6 +289064,7 @@ aesGenKeyEncryptInternal(const unsigned char* userKey, const int bits, __m128i* return rc; } +SQLITE3MC_FUNC_ISA("sse4.2,aes") static int aesGenKeyEncrypt(const unsigned char* userKey, const int bits, unsigned char* keyData) { @@ -278530,6 +289087,7 @@ aesGenKeyEncrypt(const unsigned char* userKey, const int bits, unsigned char* ke return rc; } +SQLITE3MC_FUNC_ISA("sse4.2,aes") static int aesGenKeyDecrypt(const unsigned char* userKey, const int bits, unsigned char* keyData) { @@ -278564,6 +289122,7 @@ aesGenKeyDecrypt(const unsigned char* userKey, const int bits, unsigned char* ke ** AES CBC CTS Encryption */ +SQLITE3MC_FUNC_ISA("sse4.2,aes") static void aesEncryptCBC(const unsigned char* in, unsigned char* out, @@ -278631,6 +289190,7 @@ aesEncryptCBC(const unsigned char* in, /* ** AES CBC CTS decryption */ +SQLITE3MC_FUNC_ISA("sse4.2,aes") static void aesDecryptCBC(const unsigned char* in, unsigned char* out, @@ -279079,6 +289639,10 @@ aesHardwareCheck() #endif +#if defined(__GNUC__) +#pragma GCC pop_options +#endif + /* ** The top-level selection function, caching the results of ** aesHardwareCheck() so it only has to run once. @@ -280829,821 +291393,42916 @@ void RijndaelInvalidate(Rijndael* rijndael) /*** End of #include "rijndael.c" ***/ #endif -/* #include "codec_algos.c" */ -/*** Begin of #include "codec_algos.c" ***/ -/* -** Name: codec_algos.c -** Purpose: Implementation of SQLite codec algorithms -** Author: Ulrich Telle -** Created: 2020-02-02 -** Copyright: (c) 2006-2020 Ulrich Telle -** License: MIT -*/ -/* #include "cipher_common.h" */ -/*** Begin of #include "cipher_common.h" ***/ -/* -** Name: cipher_common.h -** Purpose: Header for the ciphers of SQLite3 Multiple Ciphers -** Author: Ulrich Telle -** Created: 2020-02-02 -** Copyright: (c) 2006-2022 Ulrich Telle -** License: MIT -*/ - -#ifndef CIPHER_COMMON_H_ -#define CIPHER_COMMON_H_ - -/* #include "sqlite3mc.h" */ +#if HAVE_CIPHER_AEGIS +/* Incremental encryption/decryption not needed */ +#define AEGIS_OMIT_INCREMENTAL +/* API for generating MAC not needed */ +#define AEGIS_OMIT_MAC_API +/* #include "aegis/libaegis.c" */ +/*** Begin of #include "aegis/libaegis.c" ***/ /* -// ATTENTION: Macro similar to that in pager.c -// TODO: Check in case of new version of SQLite +** Name: libaegis.c +** Purpose: Amalgamation of the AEGIS library +** Copyright: (c) 2024-2026 Ulrich Telle +** SPDX-License-Identifier: MIT */ -#define WX_PAGER_MJ_PGNO(x) ((PENDING_BYTE/(x))+1) -#define CODEC_TYPE_DEFAULT CODEC_TYPE_CHACHA20 +/* +** AEGIS library source code +*/ -#ifndef CODEC_TYPE -#define CODEC_TYPE CODEC_TYPE_DEFAULT +#ifndef AEGIS_API +#define AEGIS_API static #endif - -#if CODEC_TYPE < 1 || CODEC_TYPE > CODEC_TYPE_MAX_BUILTIN -#error "Invalid codec type selected" +#ifndef AEGIS_PRIVATE +#define AEGIS_PRIVATE static +#endif +#ifndef AEGIS_EXTERN +#define AEGIS_EXTERN static #endif -/* -** Define the maximum number of ciphers that can be registered -*/ +/* Namespacing to avoid conflicts with libsodium 1.0.21+ */ -/* Use a reasonable upper limit for the maximum number of ciphers */ -#define CODEC_COUNT_LIMIT 16 +/* Base Implementation Structs */ +#define aegis128l_implementation sqlite3mc_aegis128l_implementation +#define aegis128x2_implementation sqlite3mc_aegis128x2_implementation +#define aegis128x4_implementation sqlite3mc_aegis128x4_implementation +#define aegis256_implementation sqlite3mc_aegis256_implementation +#define aegis256x2_implementation sqlite3mc_aegis256x2_implementation +#define aegis256x4_implementation sqlite3mc_aegis256x4_implementation -#ifdef SQLITE3MC_MAX_CODEC_COUNT -/* Allow at least to register all built-in ciphers, but use a reasonable upper limit */ -#if SQLITE3MC_MAX_CODEC_COUNT >= CODEC_TYPE_MAX_BUILTIN && SQLITE3MC_MAX_CODEC_COUNT <= CODEC_COUNT_LIMIT -#define CODEC_COUNT_MAX SQLITE3MC_MAX_CODEC_COUNT -#else -#error "Maximum cipher count not in range [CODEC_TYPE_MAX_BUILTIN .. CODEC_COUNT_LIMIT]" -#endif -#else -#define CODEC_COUNT_MAX CODEC_COUNT_LIMIT -#endif +/* Variants without hardware acceleration */ +#define aegis128l_soft_implementation sqlite3mc_aegis128l_soft_implementation +#define aegis128x2_soft_implementation sqlite3mc_aegis128x2_soft_implementation +#define aegis128x4_soft_implementation sqlite3mc_aegis128x4_soft_implementation +#define aegis256_soft_implementation sqlite3mc_aegis256_soft_implementation +#define aegis256x2_soft_implementation sqlite3mc_aegis256x2_soft_implementation +#define aegis256x4_soft_implementation sqlite3mc_aegis256x4_soft_implementation -#define CIPHER_NAME_MAXLEN 32 -#define CIPHER_PARAMS_COUNT_MAX 64 +#define softaes_block_encrypt sqlite3mc_softaes_block_encrypt -#define MAXKEYLENGTH 32 -#define KEYLENGTH_AES128 16 -#define KEYLENGTH_AES256 32 -#define KEYSALT_LENGTH 16 +/* Variants with support for AES and AVX instruction sets */ +#define aegis128l_aesni_implementation sqlite3mc_aegis128l_aesni_implementation +#define aegis128x2_aesni_implementation sqlite3mc_aegis128x2_aesni_implementation +#define aegis128x4_aesni_implementation sqlite3mc_aegis128x4_aesni_implementation +#define aegis256_aesni_implementation sqlite3mc_aegis256_aesni_implementation +#define aegis256x2_aesni_implementation sqlite3mc_aegis256x2_aesni_implementation +#define aegis256x4_aesni_implementation sqlite3mc_aegis256x4_aesni_implementation -#define CODEC_SHA_ITER 4001 +/* Variants with support for VAES and AVX2 instruction sets */ +#define aegis128x2_avx2_implementation sqlite3mc_aegis128x2_avx2_implementation +#define aegis128x4_avx2_implementation sqlite3mc_aegis128x4_avx2_implementation +#define aegis256x2_avx2_implementation sqlite3mc_aegis256x2_avx2_implementation +#define aegis256x4_avx2_implementation sqlite3mc_aegis256x4_avx2_implementation -typedef struct _CodecParameter -{ - char* m_name; - int m_id; - CipherParams* m_params; -} CodecParameter; +/* Variants with support for AVX512F instruction sets */ +#define aegis128x4_avx512_implementation sqlite3mc_aegis128x4_avx512_implementation +#define aegis256x4_avx512_implementation sqlite3mc_aegis256x4_avx512_implementation -typedef struct _Codec -{ - int m_isEncrypted; - int m_hmacCheck; - int m_walLegacy; - /* Read cipher */ - int m_hasReadCipher; - int m_readCipherType; - void* m_readCipher; - int m_readReserved; - /* Write cipher */ - int m_hasWriteCipher; - int m_writeCipherType; - void* m_writeCipher; - int m_writeReserved; +/* Variants with support for AltiVec instruction sets */ +#define aegis128l_altivec_implementation sqlite3mc_aegis128l_altivec_implementation +#define aegis128x2_altivec_implementation sqlite3mc_aegis128x2_altivec_implementation +#define aegis128x4_altivec_implementation sqlite3mc_aegis128x4_altivec_implementation +#define aegis256_altivec_implementation sqlite3mc_aegis256_altivec_implementation +#define aegis256x2_altivec_implementation sqlite3mc_aegis256x2_altivec_implementation +#define aegis256x4_altivec_implementation sqlite3mc_aegis256x4_altivec_implementation - sqlite3* m_db; /* Pointer to DB */ -#if 0 - Btree* m_bt; /* Pointer to B-tree used by DB */ -#endif - BtShared* m_btShared; /* Pointer to shared B-tree used by DB */ - unsigned char m_page[SQLITE_MAX_PAGE_SIZE + 24]; - int m_pageSize; - int m_reserved; - int m_lastError; - int m_hasKeySalt; - unsigned char m_keySalt[KEYSALT_LENGTH]; -} Codec; +/* Variants with support for ARM Neon instruction sets */ +#define aegis128l_armcrypto_implementation sqlite3mc_aegis128l_armcrypto_implementation +#define aegis128x2_armcrypto_implementation sqlite3mc_aegis128x2_armcrypto_implementation +#define aegis128x4_armcrypto_implementation sqlite3mc_aegis128x4_armcrypto_implementation +#define aegis256_armcrypto_implementation sqlite3mc_aegis256_armcrypto_implementation +#define aegis256x2_armcrypto_implementation sqlite3mc_aegis256x2_armcrypto_implementation +#define aegis256x4_armcrypto_implementation sqlite3mc_aegis256x4_armcrypto_implementation -#define CIPHER_PARAMS_SENTINEL { "", 0, 0, 0, 0 } -#define CIPHER_PAGE1_OFFSET 24 +/* Internal Tables (can conflict under -flto) */ +#define _aes_lut sqlite3mc_aegis_aes_lut -SQLITE_PRIVATE int sqlite3mcGetCipherParameter(CipherParams* cipherParams, const char* paramName); +/* #include "common/cpu.h" */ +/*** Begin of #include "common/cpu.h" ***/ +/* +** Name: cpu.h +** Purpose: Header for CPU identification and AES hardware support detection +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ -SQLITE_PRIVATE int sqlite3mcGetCipherType(sqlite3* db); +#ifndef AEGIS_CPU_H +#define AEGIS_CPU_H -SQLITE_PRIVATE CipherParams* sqlite3mcGetCipherParams(sqlite3* db, const char* cipherName); +/* #include "aeshardware.h" */ +/*** Begin of #include "aeshardware.h" ***/ +/* +** Name: aeshardware.h +** Purpose: Header for AES hardware support detection +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ -SQLITE_PRIVATE int sqlite3mcCodecInit(Codec* codec); +#ifndef AEGIS_AES_HARDWARE_H +#define AEGIS_AES_HARDWARE_H -SQLITE_PRIVATE void sqlite3mcCodecTerm(Codec* codec); +#define AEGIS_AES_HARDWARE_NONE 0 +#define AEGIS_AES_HARDWARE_NI 1 +#define AEGIS_AES_HARDWARE_NEON 2 +#define AEGIS_AES_HARDWARE_ALTIVEC 3 -SQLITE_PRIVATE void sqlite3mcClearKeySalt(Codec* codec); +#ifndef AEGIS_OMIT_AES_HARDWARE_SUPPORT -SQLITE_PRIVATE int sqlite3mcCodecSetup(Codec* codec, int cipherType, char* userPassword, int passwordLength); +#if defined __ARM_FEATURE_CRYPTO +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NEON -SQLITE_PRIVATE int sqlite3mcSetupWriteCipher(Codec* codec, int cipherType, char* userPassword, int passwordLength); -SQLITE_PRIVATE void sqlite3mcSetIsEncrypted(Codec* codec, int isEncrypted); +/* --- CLang --- */ +#elif defined(__clang__) -SQLITE_PRIVATE void sqlite3mcSetReadCipherType(Codec* codec, int cipherType); +#if __has_attribute(target) && __has_include() && (defined(__x86_64__) || defined(__i386)) +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NI -SQLITE_PRIVATE void sqlite3mcSetWriteCipherType(Codec* codec, int cipherType); +#elif __has_attribute(target) && __has_include() && (defined(__aarch64__)) +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NEON -SQLITE_PRIVATE void sqlite3mcSetHasReadCipher(Codec* codec, int hasReadCipher); +#endif -SQLITE_PRIVATE void sqlite3mcSetHasWriteCipher(Codec* codec, int hasWriteCipher); -SQLITE_PRIVATE void sqlite3mcSetDb(Codec* codec, sqlite3* db); +/* --- GNU C/C++ */ +#elif defined(__GNUC__) -SQLITE_PRIVATE void sqlite3mcSetBtree(Codec* codec, Btree* bt); +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) && (defined(__x86_64__) || defined(__i386)) +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NI +#elif defined(__aarch64__) || (defined(__arm__) && defined(__ARM_NEON)) +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NEON +#endif -SQLITE_PRIVATE void sqlite3mcSetReadReserved(Codec* codec, int reserved); -SQLITE_PRIVATE void sqlite3mcSetWriteReserved(Codec* codec, int reserved); +/* --- Visual C/C++ --- */ +#elif defined (_MSC_VER) -SQLITE_PRIVATE int sqlite3mcIsEncrypted(Codec* codec); +#if defined(_M_ARM64EC) +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NEON -SQLITE_PRIVATE int sqlite3mcHasReadCipher(Codec* codec); +/* Use header instead of */ +#ifndef USE_ARM64_NEON_H +#define USE_ARM64_NEON_H +#endif -SQLITE_PRIVATE int sqlite3mcHasWriteCipher(Codec* codec); +/* Architecture: x86 or x86_64 */ +#elif (defined(_M_X64) || defined(_M_IX86)) && _MSC_FULL_VER >= 150030729 +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NI -SQLITE_PRIVATE BtShared* sqlite3mcGetBtShared(Codec* codec); +/* Architecture: ARM 64-bit */ +#elif defined(_M_ARM64) || defined(_M_ARM64EC) +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NEON -SQLITE_PRIVATE int sqlite3mcGetPageSize(Codec* codec); +/* Use header instead of */ +#ifndef USE_ARM64_NEON_H +#define USE_ARM64_NEON_H +#endif -SQLITE_PRIVATE int sqlite3mcGetReadReserved(Codec* codec); +/* Architecture: ARM 32-bit */ +#elif defined _M_ARM +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NEON -SQLITE_PRIVATE int sqlite3mcGetWriteReserved(Codec* codec); +/* The following #define is required to enable intrinsic definitions + that do not omit one of the parameters for vaes[ed]q_u8 */ +#ifndef _ARM_USE_NEW_NEON_INTRINSICS +#define _ARM_USE_NEW_NEON_INTRINSICS +#endif -SQLITE_PRIVATE unsigned char* sqlite3mcGetPageBuffer(Codec* codec); +#endif -SQLITE_PRIVATE int sqlite3mcGetLegacyReadCipher(Codec* codec); +#else -SQLITE_PRIVATE int sqlite3mcGetLegacyWriteCipher(Codec* codec); +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NONE -SQLITE_PRIVATE int sqlite3mcGetPageSizeReadCipher(Codec* codec); +#endif -SQLITE_PRIVATE int sqlite3mcGetPageSizeWriteCipher(Codec* codec); +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NONE -SQLITE_PRIVATE int sqlite3mcGetReservedReadCipher(Codec* codec); +/* Original checks of libaegis */ +#if defined(__ARM_FEATURE_CRYPTO) && defined(__ARM_FEATURE_AES) && defined(__ARM_NEON) +# define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NEON +#elif defined(__AES__) && defined(__AVX__) +# define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NI +#elif defined(__ALTIVEC__) && defined(__CRYPTO__) +# define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_ALTIVEC +#endif -SQLITE_PRIVATE int sqlite3mcGetReservedWriteCipher(Codec* codec); +#endif -SQLITE_PRIVATE int sqlite3mcReservedEqual(Codec* codec); +#else /* AEGIS_OMIT_AES_HARDWARE_SUPPORT defined */ -SQLITE_PRIVATE void sqlite3mcSetCodecLastError(Codec* codec, int error); -SQLITE_PRIVATE int sqlite3mcGetCodecLastError(Codec* codec); +/* Omit AES hardware support */ +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NONE -SQLITE_PRIVATE unsigned char* sqlite3mcGetSaltWriteCipher(Codec* codec); +#endif /* SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT */ -SQLITE_PRIVATE int sqlite3mcCodecCopy(Codec* codec, Codec* other); +#endif /* AEGIS_AES_HARDWARE_H */ +/*** End of #include "aeshardware.h" ***/ -SQLITE_PRIVATE void sqlite3mcGenerateReadKey(Codec* codec, char* userPassword, int passwordLength, unsigned char* cipherSalt); -SQLITE_PRIVATE void sqlite3mcGenerateWriteKey(Codec* codec, char* userPassword, int passwordLength, unsigned char* cipherSalt); +AEGIS_PRIVATE +int aegis_runtime_get_cpu_features(void); -SQLITE_PRIVATE int sqlite3mcEncrypt(Codec* codec, int page, unsigned char* data, int len, int useWriteKey); +AEGIS_PRIVATE +int aegis_runtime_has_neon(void); -SQLITE_PRIVATE int sqlite3mcDecrypt(Codec* codec, int page, unsigned char* data, int len); +AEGIS_PRIVATE +int aegis_runtime_has_armcrypto(void); -SQLITE_PRIVATE int sqlite3mcCopyCipher(Codec* codec, int read2write); +AEGIS_PRIVATE +int aegis_runtime_has_avx(void); -SQLITE_PRIVATE void sqlite3mcPadPassword(char* password, int pswdlen, unsigned char pswd[32]); +AEGIS_PRIVATE +int aegis_runtime_has_avx2(void); -SQLITE_PRIVATE void sqlite3mcRC4(unsigned char* key, int keylen, unsigned char* textin, int textlen, unsigned char* textout); +AEGIS_PRIVATE +int aegis_runtime_has_avx512f(void); -SQLITE_PRIVATE void sqlite3mcGetMD5Binary(unsigned char* data, int length, unsigned char* digest); +AEGIS_PRIVATE +int aegis_runtime_has_aesni(void); -SQLITE_PRIVATE void sqlite3mcGetSHABinary(unsigned char* data, int length, unsigned char* digest); +AEGIS_PRIVATE +int aegis_runtime_has_vaes(void); -SQLITE_PRIVATE void sqlite3mcGenerateInitialVector(int seed, unsigned char iv[16]); +AEGIS_PRIVATE +int aegis_runtime_has_altivec(void); -SQLITE_PRIVATE int sqlite3mcIsHexKey(const unsigned char* hex, int len); +#endif /* AEGIS_CPU_H */ +/*** End of #include "common/cpu.h" ***/ -SQLITE_PRIVATE int sqlite3mcConvertHex2Int(char c); -SQLITE_PRIVATE void sqlite3mcConvertHex2Bin(const unsigned char* hex, int len, unsigned char* bin); +/* AEGIS common functions */ +/* #include "common/common.c" */ +/*** Begin of #include "common/common.c" ***/ +/* +** Name: common.c +** Purpose: Implementation of common utility functions +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ -SQLITE_PRIVATE int sqlite3mcConfigureFromUri(sqlite3* db, const char *zDbName, int configDefault); +#include +#include -SQLITE_PRIVATE void sqlite3mcConfigureSQLCipherVersion(sqlite3* db, int configDefault, int legacyVersion); +/* #include "common.h" */ +/*** Begin of #include "common.h" ***/ +/* +** Name: common.h +** Purpose: Common header for AEGIS implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ -SQLITE_PRIVATE int sqlite3mcCodecAttach(sqlite3* db, int nDb, const char* zPath, const void* zKey, int nKey); +#ifndef AEGIS_COMMON_H +#define AEGIS_COMMON_H -SQLITE_PRIVATE void sqlite3mcCodecGetKey(sqlite3* db, int nDb, void** zKey, int* nKey); +#include +#include +#include +#include -SQLITE_PRIVATE void sqlite3mcSecureZeroMemory(void* v, size_t n); +/* #include "../include/aegis.h" */ +/*** Begin of #include "../include/aegis.h" ***/ +/* +** Name: aegis.h +** Purpose: Header for AEGIS API +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ -/* Debugging */ +#ifndef AEGIS_H +#define AEGIS_H -#if 0 -#define SQLITE3MC_DEBUG -#define SQLITE3MC_DEBUG_DATA +#include + +#if !defined(__clang__) && !defined(__GNUC__) +# ifdef __attribute__ +# undef __attribute__ +# endif +# define __attribute__(a) #endif -#ifdef SQLITE3MC_DEBUG -#define SQLITE3MC_DEBUG_LOG(...) { fprintf(stdout, __VA_ARGS__); fflush(stdout); } -#else -#define SQLITE3MC_DEBUG_LOG(...) +#ifndef CRYPTO_ALIGN +# if defined(__INTEL_COMPILER) || defined(_MSC_VER) +# define CRYPTO_ALIGN(x) __declspec(align(x)) +# else +# define CRYPTO_ALIGN(x) __attribute__((aligned(x))) +# endif #endif -#ifdef SQLITE3MC_DEBUG_DATA -#define SQLITE3MC_DEBUG_HEX(DESC,BUFFER,LEN) \ - { \ - int count; \ - printf(DESC); \ - for (count = 0; count < LEN; ++count) \ - { \ - if (count % 16 == 0) printf("\n%05x: ", count); \ - printf("%02x ", ((unsigned char*) BUFFER)[count]); \ - } \ - printf("\n"); \ - fflush(stdout); \ - } -#else -#define SQLITE3MC_DEBUG_HEX(DESC,BUFFER,LEN) +#ifndef AEGIS_API +#define AEGIS_API +#endif +#ifndef AEGIS_PRIVATE +#define AEGIS_PRIVATE static +#endif +#ifndef AEGIS_EXTERN +#define AEGIS_EXTERN extern #endif +/* #include "aegis128l.h" */ +/*** Begin of #include "aegis128l.h" ***/ /* -** If encryption was enabled and WAL journal mode was used, -** SQLite3 Multiple Ciphers encrypted the WAL journal frames up to version 1.2.5 -** within the VFS implementation. As a consequence the WAL journal file was not -** compatible with legacy encryption implementations (for example, System.Data.SQLite -** or SQLCipher). Additionally, the implementation of the WAL journal encryption -** was broken, because reading and writing of complete WAL frames was not handled -** correctly. Usually, operating in WAL journal mode worked nevertheless, but after -** crashes the WAL journal file could be corrupted leading to data loss. -** -** Version 1.3.0 introduced a new way to handle WAL journal encryption. The advantage -** is that the WAL journal file is now compatible with legacy encryption implementations. -** Unfortunately the new implementation is not compatible with that used up to version -** 1.2.5. To be able to access WAL journals created by prior versions, the configuration -** parameter 'mc_legacy_wal' was introduced. If the parameter is set to 1, then the -** prior WAL journal encryption mode is used. The default of this parameter can be set -** at compile time by setting the symbol SQLITE3MC_LEGACY_WAL accordingly, but the actual -** value can also be set at runtime using the pragma or the URI parameter 'mc_legacy_wal'. -** -** In principle, operating generally in WAL legacy mode is possible, but it is strongly -** recommended to use the WAL legacy mode only to recover WAL journals left behind by -** prior versions without data loss. +** Name: aegis128l.h +** Purpose: Header for AEGIS-128L API +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT */ -#ifndef SQLITE3MC_LEGACY_WAL -#define SQLITE3MC_LEGACY_WAL 0 -#endif -#endif -/*** End of #include "cipher_common.h" ***/ +#ifndef AEGIS128L_H +#define AEGIS128L_H -#if HAVE_CIPHER_AES_128_CBC || HAVE_CIPHER_AES_256_CBC || HAVE_CIPHER_SQLCIPHER -/* #include "rijndael.h" */ +#include +#include +#ifdef __cplusplus +extern "C" { #endif -/* -** RC4 implementation -*/ +/* The length of an AEGIS key, in bytes */ +#define aegis128l_KEYBYTES 16 -SQLITE_PRIVATE void -sqlite3mcRC4(unsigned char* key, int keylen, - unsigned char* textin, int textlen, - unsigned char* textout) -{ - int i; - int j; - int t; - unsigned char rc4[256]; +/* The length of an AEGIS nonce, in bytes */ +#define aegis128l_NPUBBYTES 16 - int a = 0; - int b = 0; - unsigned char k; +/* The minimum length of an AEGIS authentication tag, in bytes */ +#define aegis128l_ABYTES_MIN 16 - for (i = 0; i < 256; i++) - { - rc4[i] = i; - } - j = 0; - for (i = 0; i < 256; i++) - { - t = rc4[i]; - j = (j + t + key[i % keylen]) % 256; - rc4[i] = rc4[j]; - rc4[j] = t; - } +/* The maximum length of an AEGIS authentication tag, in bytes */ +#define aegis128l_ABYTES_MAX 32 - for (i = 0; i < textlen; i++) - { - a = (a + 1) % 256; - t = rc4[a]; - b = (b + t) % 256; - rc4[a] = rc4[b]; - rc4[b] = t; - k = rc4[(rc4[a] + rc4[b]) % 256]; - textout[i] = textin[i] ^ k; - } -} +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +#define aegis128l_TAILBYTES_MAX 31 -SQLITE_PRIVATE void -sqlite3mcGetMD5Binary(unsigned char* data, int length, unsigned char* digest) -{ - MD5_CTX ctx; - MD5_Init(&ctx); - MD5_Update(&ctx, data, length); - MD5_Final(digest,&ctx); -} +/* An AEGIS state, for incremental updates */ +typedef struct aegis128l_state { + CRYPTO_ALIGN(32) uint8_t opaque[256]; +} aegis128l_state; -SQLITE_PRIVATE void -sqlite3mcGetSHABinary(unsigned char* data, int length, unsigned char* digest) -{ - sha256(data, (unsigned int) length, digest); -} +/* An AEGIS state, only for MAC updates */ +typedef struct aegis128l_mac_state { + CRYPTO_ALIGN(32) uint8_t opaque[384]; +} aegis128l_mac_state; -#define MODMULT(a, b, c, m, s) q = s / a; s = b * (s - a * q) - c * q; if (s < 0) s += m -SQLITE_PRIVATE void -sqlite3mcGenerateInitialVector(int seed, unsigned char iv[16]) -{ - unsigned char initkey[16]; - int j, q; - int z = seed + 1; - for (j = 0; j < 4; j++) - { - MODMULT(52774, 40692, 3791, 2147483399L, z); - initkey[4*j+0] = 0xff & z; - initkey[4*j+1] = 0xff & (z >> 8); - initkey[4*j+2] = 0xff & (z >> 16); - initkey[4*j+3] = 0xff & (z >> 24); - } - sqlite3mcGetMD5Binary((unsigned char*) initkey, 16, iv); -} +/* The length of an AEGIS key, in bytes */ +AEGIS_API +size_t aegis128l_keybytes(void); -#if HAVE_CIPHER_AES_128_CBC +/* The length of an AEGIS nonce, in bytes */ +AEGIS_API +size_t aegis128l_npubbytes(void); -SQLITE_PRIVATE int -sqlite3mcAES128(Rijndael* aesCtx, int page, int encrypt, unsigned char encryptionKey[KEYLENGTH_AES128], - unsigned char* datain, int datalen, unsigned char* dataout) -{ - int rc = SQLITE_OK; - unsigned char initial[16]; - unsigned char pagekey[KEYLENGTH_AES128]; - unsigned char nkey[KEYLENGTH_AES128+4+4]; - int keyLength = KEYLENGTH_AES128; - int nkeylen = keyLength + 4 + 4; - int j; - int direction = (encrypt) ? RIJNDAEL_Direction_Encrypt : RIJNDAEL_Direction_Decrypt; - int len = 0; +/* The minimum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis128l_abytes_min(void); - for (j = 0; j < keyLength; j++) - { - nkey[j] = encryptionKey[j]; - } - nkey[keyLength+0] = 0xff & page; - nkey[keyLength+1] = 0xff & (page >> 8); - nkey[keyLength+2] = 0xff & (page >> 16); - nkey[keyLength+3] = 0xff & (page >> 24); +/* The maximum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis128l_abytes_max(void); - /* AES encryption needs some 'salt' */ - nkey[keyLength+4] = 0x73; - nkey[keyLength+5] = 0x41; - nkey[keyLength+6] = 0x6c; - nkey[keyLength+7] = 0x54; +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +AEGIS_API +size_t aegis128l_tailbytes_max(void); - sqlite3mcGetMD5Binary(nkey, nkeylen, pagekey); - sqlite3mcGenerateInitialVector(page, initial); - RijndaelInit(aesCtx, RIJNDAEL_Direction_Mode_CBC, direction, pagekey, RIJNDAEL_Direction_KeyLength_Key16Bytes, initial); - if (encrypt) - { - len = RijndaelBlockEncrypt(aesCtx, datain, datalen*8, dataout); - } - else - { - len = RijndaelBlockDecrypt(aesCtx, datain, datalen*8, dataout); - } +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * c: ciphertext output buffer + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +int aegis128l_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, + size_t mlen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); - /* It is a good idea to check the error code */ - if (len < 0) - { - /* AES: Error on encrypting. */ - rc = SQLITE_ERROR; - } - return rc; -} +/* + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis128l_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) __attribute__((warn_unused_result)); -#endif +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * c: ciphertext output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +int aegis128l_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k); -#if HAVE_CIPHER_AES_256_CBC +/* + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis128l_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) + __attribute__((warn_unused_result)); -SQLITE_PRIVATE int -sqlite3mcAES256(Rijndael* aesCtx, int page, int encrypt, unsigned char encryptionKey[KEYLENGTH_AES256], - unsigned char* datain, int datalen, unsigned char* dataout) -{ - int rc = SQLITE_OK; - unsigned char initial[16]; - unsigned char pagekey[KEYLENGTH_AES256]; - unsigned char nkey[KEYLENGTH_AES256+4+4]; - int keyLength = KEYLENGTH_AES256; - int nkeylen = keyLength + 4 + 4; - int j; - int direction = (encrypt) ? RIJNDAEL_Direction_Encrypt : RIJNDAEL_Direction_Decrypt; - int len = 0; +#ifndef AEGIS_OMIT_INCREMENTAL - for (j = 0; j < keyLength; j++) - { - nkey[j] = encryptionKey[j]; - } - nkey[keyLength+0] = 0xff & page; - nkey[keyLength+1] = 0xff & (page >> 8); - nkey[keyLength+2] = 0xff & (page >> 16); - nkey[keyLength+3] = 0xff & (page >> 24); +/* + * Initialize a state for incremental encryption or decryption. + * + * st_: state to initialize + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128l_state_init(aegis128l_state *st_, const uint8_t *ad, size_t adlen, + const uint8_t *npub, const uint8_t *k); - /* AES encryption needs some 'salt' */ - nkey[keyLength+4] = 0x73; - nkey[keyLength+5] = 0x41; - nkey[keyLength+6] = 0x6c; - nkey[keyLength+7] = 0x54; +/* + * Encrypt a message chunk. + * The same function can be used regardless of whether the tag will be attached or not. + * + * st_: state to update + * c: ciphertext output buffer + * clen_max: length of the ciphertext chunk buffer (must be >= mlen) + * written: number of ciphertext bytes actually written + * m: plaintext input buffer + * mlen: length of the plaintext + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128l_state_encrypt_update(aegis128l_state *st_, uint8_t *c, size_t clen_max, + size_t *written, const uint8_t *m, size_t mlen); - sqlite3mcGetSHABinary(nkey, nkeylen, pagekey); - sqlite3mcGenerateInitialVector(page, initial); - RijndaelInit(aesCtx, RIJNDAEL_Direction_Mode_CBC, direction, pagekey, RIJNDAEL_Direction_KeyLength_Key32Bytes, initial); - if (encrypt) - { - len = RijndaelBlockEncrypt(aesCtx, datain, datalen*8, dataout); - } - else - { - len = RijndaelBlockDecrypt(aesCtx, datain, datalen*8, dataout); - } +/* + * Finalize the incremental encryption and generate the authentication tag. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes) + * written: number of ciphertext bytes actually written + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128l_state_encrypt_detached_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); - /* It is a good idea to check the error code */ - if (len < 0) - { - /* AES: Error on encrypting. */ - rc = SQLITE_ERROR; - } - return rc; -} +/* + * Finalize the incremental encryption and attach the authentication tag + * to the final ciphertext chunk. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes+maclen) + * written: number of ciphertext bytes actually written + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128l_state_encrypt_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, + size_t *written, size_t maclen); -#endif +/* + * Decrypt a message chunk. + * + * The output should never be released to the caller until the tag has been verified. + * + * st_: state to update + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= clen) + * written: number of plaintext bytes actually written + * c: ciphertext chunk input buffer + * clen: length of the ciphertext chunk + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128l_state_decrypt_detached_update(aegis128l_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) + __attribute__((warn_unused_result)); -/* Check hex encoding */ -SQLITE_PRIVATE int -sqlite3mcIsHexKey(const unsigned char* hex, int len) -{ - int j; - for (j = 0; j < len; ++j) - { - unsigned char c = hex[j]; - if ((c < '0' || c > '9') && (c < 'A' || c > 'F') && (c < 'a' || c > 'f')) - { - return 0; - } - } - return 1; -} +/* + * Decrypt the final message chunk and verify the authentication tag. + * + * st_: state to finalize + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= remaining bytes) + * written: number of plaintext bytes actually written + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128l_state_decrypt_detached_final(aegis128l_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) + __attribute__((warn_unused_result)); -/* Convert single hex digit */ -SQLITE_PRIVATE int -sqlite3mcConvertHex2Int(char c) -{ - return (c >= '0' && c <= '9') ? (c)-'0' : - (c >= 'A' && c <= 'F') ? (c)-'A' + 10 : - (c >= 'a' && c <= 'f') ? (c)-'a' + 10 : 0; -} +#endif /* AEGIS_OMIT_INCREMENTAL */ -/* Convert hex encoded string to binary */ -SQLITE_PRIVATE void -sqlite3mcConvertHex2Bin(const unsigned char* hex, int len, unsigned char* bin) -{ - int j; - for (j = 0; j < len; j += 2) - { - bin[j / 2] = (sqlite3mcConvertHex2Int(hex[j]) << 4) | sqlite3mcConvertHex2Int(hex[j + 1]); - } -} -/*** End of #include "codec_algos.c" ***/ +/* + * Return a deterministic pseudo-random byte sequence. + * + * out: output buffer + * len: number of bytes to generate + * npub: nonce input buffer (16 bytes) - Can be set to `NULL` if only one sequence has to be + * generated from a given key. + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128l_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); +/* + * Encrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * c: ciphertext output buffer + * m: plaintext input buffer + * mlen: length of the plaintext + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128l_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, + const uint8_t *npub, const uint8_t *k); -/* #include "cipher_wxaes128.c" */ -/*** Begin of #include "cipher_wxaes128.c" ***/ /* -** Name: cipher_wxaes128.c -** Purpose: Implementation of cipher wxSQLite3 AES 128-bit -** Author: Ulrich Telle -** Created: 2020-02-02 -** Copyright: (c) 2006-2024 Ulrich Telle -** License: MIT -*/ + * Decrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128l_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, + const uint8_t *npub, const uint8_t *k); -/* #include "cipher_common.h" */ +#ifndef AEGIS_OMIT_MAC_API +/* + * Initialize a state for generating a MAC. + * + * st_: state to initialize + * k: key input buffer (16 bytes) + * + * - The same key MUST NOT be used both for MAC and encryption. + * - If the key is secret, the MAC is secure against forgery. + * - However, if the key is known, arbitrary inputs matching a tag can be efficiently computed. + * + * The recommended way to use the MAC mode is to generate a random key and keep it secret. + * + * After initialization, the state can be reused to generate multiple MACs by cloning it + * with `aegis128l_mac_state_clone()`. It is only safe to copy a state directly without using + * the clone function if the state is guaranteed to be properly aligned. + * + * A state can also be reset for reuse without cloning with `aegis128l_mac_reset()`. + */ +AEGIS_API +void aegis128l_mac_init(aegis128l_mac_state *st_, const uint8_t *k, const uint8_t *npub); -/* --- AES 128-bit cipher (wxSQLite3) --- */ -#if HAVE_CIPHER_AES_128_CBC +/* + * Update the MAC state with input data. + * + * st_: state to update + * m: input data + * mlen: length of the input data + * + * This function can be called multiple times. + * + * Once the full input has been absorb, call either `_mac_final` or `_mac_verify`. + */ +AEGIS_API +int aegis128l_mac_update(aegis128l_mac_state *st_, const uint8_t *m, size_t mlen); -#define CIPHER_NAME_AES128 "aes128cbc" +/* + * Finalize the MAC and generate the authentication tag. + * + * st_: state to finalize + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32. 32 is recommended). + */ +AEGIS_API +int aegis128l_mac_final(aegis128l_mac_state *st_, uint8_t *mac, size_t maclen); /* -** Configuration parameters for "aes128cbc" -** -** - legacy mode : compatibility with first version (page 1 encrypted) -** possible values: 1 = yes, 0 = no (default) -*/ + * Verify a MAC in constant time. + * + * st_: state to verify + * mac: authentication tag to verify + * maclen: length of the authentication tag (16 or 32) + * + * Returns 0 if the tag is authentic, -1 otherwise. + */ +AEGIS_API +int aegis128l_mac_verify(aegis128l_mac_state *st_, const uint8_t *mac, size_t maclen); -#ifdef WXSQLITE3_USE_OLD_ENCRYPTION_SCHEME -#define AES128_LEGACY_DEFAULT 1 -#else -#define AES128_LEGACY_DEFAULT 0 -#endif +/* + * Reset an AEGIS_MAC state. + */ +AEGIS_API +void aegis128l_mac_reset(aegis128l_mac_state *st_); -SQLITE_PRIVATE CipherParams mcAES128Params[] = -{ - { "legacy", AES128_LEGACY_DEFAULT, AES128_LEGACY_DEFAULT, 0, 1 }, - { "legacy_page_size", 0, 0, 0, SQLITE_MAX_PAGE_SIZE }, - CIPHER_PARAMS_SENTINEL -}; +/* + * Clone an AEGIS-MAC state. + * + * dst: destination state + * src: source state + * + * This function MUST be used in order to clone states. + */ +AEGIS_API +void aegis128l_mac_state_clone(aegis128l_mac_state *dst, const aegis128l_mac_state *src); -typedef struct _AES128Cipher -{ - int m_legacy; - int m_legacyPageSize; - int m_keyLength; - uint8_t m_key[KEYLENGTH_AES128]; - Rijndael* m_aes; -} AES128Cipher; +#endif /* AEGIS_OMIT_MAC_API */ -static void* -AllocateAES128Cipher(sqlite3* db) -{ - AES128Cipher* aesCipher = (AES128Cipher*) sqlite3_malloc(sizeof(AES128Cipher)); - if (aesCipher != NULL) - { - aesCipher->m_aes = (Rijndael*) sqlite3_malloc(sizeof(Rijndael)); - if (aesCipher->m_aes != NULL) - { - aesCipher->m_keyLength = KEYLENGTH_AES128; - memset(aesCipher->m_key, 0, KEYLENGTH_AES128); - RijndaelCreate(aesCipher->m_aes); - } - else - { - sqlite3_free(aesCipher); - aesCipher = NULL; - } - } - if (aesCipher != NULL) - { - CipherParams* cipherParams = sqlite3mcGetCipherParams(db, CIPHER_NAME_AES128); - aesCipher->m_legacy = sqlite3mcGetCipherParameter(cipherParams, "legacy"); - aesCipher->m_legacyPageSize = sqlite3mcGetCipherParameter(cipherParams, "legacy_page_size"); - } - return aesCipher; +#ifdef __cplusplus } +#endif -static void -FreeAES128Cipher(void* cipher) -{ - AES128Cipher* localCipher = (AES128Cipher*) cipher; - memset(localCipher->m_aes, 0, sizeof(Rijndael)); - sqlite3_free(localCipher->m_aes); - memset(localCipher, 0, sizeof(AES128Cipher)); - sqlite3_free(localCipher); -} +#endif /* AEGIS128L_H */ +/*** End of #include "aegis128l.h" ***/ -static void -CloneAES128Cipher(void* cipherTo, void* cipherFrom) -{ - AES128Cipher* aesCipherTo = (AES128Cipher*) cipherTo; - AES128Cipher* aesCipherFrom = (AES128Cipher*) cipherFrom; - aesCipherTo->m_legacy = aesCipherFrom->m_legacy; - aesCipherTo->m_legacyPageSize = aesCipherFrom->m_legacyPageSize; - aesCipherTo->m_keyLength = aesCipherFrom->m_keyLength; - memcpy(aesCipherTo->m_key, aesCipherFrom->m_key, KEYLENGTH_AES128); - RijndaelInvalidate(aesCipherTo->m_aes); - RijndaelInvalidate(aesCipherFrom->m_aes); -} +/* #include "aegis128x2.h" */ +/*** Begin of #include "aegis128x2.h" ***/ +/* +** Name: aegis128x2.h +** Purpose: Header for AEGIS-128x2 API +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ -static int -GetLegacyAES128Cipher(void* cipher) -{ - AES128Cipher* aesCipher = (AES128Cipher*)cipher; - return aesCipher->m_legacy; -} +#ifndef AEGIS128X2_H +#define AEGIS128X2_H -static int -GetPageSizeAES128Cipher(void* cipher) -{ - AES128Cipher* aesCipher = (AES128Cipher*) cipher; - int pageSize = 0; - if (aesCipher->m_legacy != 0) - { - pageSize = aesCipher->m_legacyPageSize; - if ((pageSize < 512) || (pageSize > SQLITE_MAX_PAGE_SIZE) || (((pageSize - 1) & pageSize) != 0)) - { - pageSize = 0; - } - } - return pageSize; -} +#include +#include -static int -GetReservedAES128Cipher(void* cipher) -{ - return 0; -} +#ifdef __cplusplus +extern "C" { +#endif -static unsigned char* -GetSaltAES128Cipher(void* cipher) -{ - return NULL; -} +/* The length of an AEGIS key, in bytes */ +#define aegis128x2_KEYBYTES 16 -static void -GenerateKeyAES128Cipher(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt) -{ - AES128Cipher* aesCipher = (AES128Cipher*) cipher; - unsigned char userPad[32]; - unsigned char ownerPad[32]; - unsigned char ownerKey[32]; +/* The length of an AEGIS nonce, in bytes */ +#define aegis128x2_NPUBBYTES 16 - unsigned char mkey[MD5_HASHBYTES]; - unsigned char digest[MD5_HASHBYTES]; - int keyLength = MD5_HASHBYTES; - int i, j, k; - MD5_CTX ctx; +/* The minimum length of an AEGIS authentication tag, in bytes */ +#define aegis128x2_ABYTES_MIN 16 - /* Pad passwords */ - sqlite3mcPadPassword(userPassword, passwordLength, userPad); - sqlite3mcPadPassword("", 0, ownerPad); +/* The maximum length of an AEGIS authentication tag, in bytes */ +#define aegis128x2_ABYTES_MAX 32 - /* Compute owner key */ +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +#define aegis128x2_TAILBYTES_MAX 63 - MD5_Init(&ctx); - MD5_Update(&ctx, ownerPad, 32); - MD5_Final(digest, &ctx); +/* An AEGIS state, for incremental updates */ +typedef struct aegis128x2_state { + CRYPTO_ALIGN(64) uint8_t opaque[448]; +} aegis128x2_state; - /* only use for the input as many bit as the key consists of */ - for (k = 0; k < 50; ++k) - { - MD5_Init(&ctx); - MD5_Update(&ctx, digest, keyLength); - MD5_Final(digest, &ctx); - } - memcpy(ownerKey, userPad, 32); - for (i = 0; i < 20; ++i) - { - for (j = 0; j < keyLength; ++j) - { - mkey[j] = (digest[j] ^ i); - } - sqlite3mcRC4(mkey, keyLength, ownerKey, 32, ownerKey); - } +/* An AEGIS state, only for MAC updates */ +typedef struct aegis128x2_mac_state { + CRYPTO_ALIGN(64) uint8_t opaque[704]; +} aegis128x2_mac_state; - /* Compute encryption key */ +/* The length of an AEGIS key, in bytes */ +AEGIS_API +size_t aegis128x2_keybytes(void); - MD5_Init(&ctx); - MD5_Update(&ctx, userPad, 32); - MD5_Update(&ctx, ownerKey, 32); - MD5_Final(digest, &ctx); +/* The length of an AEGIS nonce, in bytes */ +AEGIS_API +size_t aegis128x2_npubbytes(void); - /* only use the really needed bits as input for the hash */ - for (k = 0; k < 50; ++k) - { - MD5_Init(&ctx); - MD5_Update(&ctx, digest, keyLength); - MD5_Final(digest, &ctx); - } - memcpy(aesCipher->m_key, digest, aesCipher->m_keyLength); -} +/* The minimum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis128x2_abytes_min(void); -static int -EncryptPageAES128Cipher(void* cipher, int page, unsigned char* data, int len, int reserved) -{ - AES128Cipher* aesCipher = (AES128Cipher*) cipher; - int rc = SQLITE_OK; - if (aesCipher->m_legacy != 0) - { - /* Use the legacy encryption scheme */ - unsigned char* key = aesCipher->m_key; - rc = sqlite3mcAES128(aesCipher->m_aes, page, 1, key, data, len, data); - } - else - { - unsigned char dbHeader[8]; - int offset = 0; - unsigned char* key = aesCipher->m_key; - if (page == 1) - { - /* Save the header bytes remaining unencrypted */ - memcpy(dbHeader, data + 16, 8); - offset = 16; - sqlite3mcAES128(aesCipher->m_aes, page, 1, key, data, 16, data); - } - rc = sqlite3mcAES128(aesCipher->m_aes, page, 1, key, data + offset, len - offset, data + offset); - if (page == 1) - { - /* Move the encrypted header bytes 16..23 to a safe position */ - memcpy(data + 8, data + 16, 8); - /* Restore the unencrypted header bytes 16..23 */ - memcpy(data + 16, dbHeader, 8); - } - } - return rc; -} +/* The maximum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis128x2_abytes_max(void); -static int -DecryptPageAES128Cipher(void* cipher, int page, unsigned char* data, int len, int reserved, int hmacCheck) -{ - AES128Cipher* aesCipher = (AES128Cipher*) cipher; - int rc = SQLITE_OK; - if (aesCipher->m_legacy != 0) - { - /* Use the legacy encryption scheme */ - rc = sqlite3mcAES128(aesCipher->m_aes, page, 0, aesCipher->m_key, data, len, data); - } - else - { - unsigned char dbHeader[8]; - int dbPageSize; - int offset = 0; - if (page == 1) - { - /* Save (unencrypted) header bytes 16..23 */ - memcpy(dbHeader, data + 16, 8); - /* Determine page size */ - dbPageSize = (dbHeader[0] << 8) | (dbHeader[1] << 16); - /* Check whether the database header is valid */ - /* If yes, the database follows the new encryption scheme, otherwise use the previous encryption scheme */ - if ((dbPageSize >= 512) && (dbPageSize <= SQLITE_MAX_PAGE_SIZE) && (((dbPageSize - 1) & dbPageSize) == 0) && - (dbHeader[5] == 0x40) && (dbHeader[6] == 0x20) && (dbHeader[7] == 0x20)) - { - /* Restore encrypted bytes 16..23 for new encryption scheme */ - memcpy(data + 16, data + 8, 8); - offset = 16; - } - } - rc = sqlite3mcAES128(aesCipher->m_aes, page, 0, aesCipher->m_key, data + offset, len - offset, data + offset); - if (page == 1 && offset != 0) - { - /* Verify the database header */ - if (memcmp(dbHeader, data + 16, 8) == 0) - { - memcpy(data, SQLITE_FILE_HEADER, 16); - } - } - } - return rc; -} +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +AEGIS_API +size_t aegis128x2_tailbytes_max(void); -SQLITE_PRIVATE const CipherDescriptor mcAES128Descriptor = -{ - CIPHER_NAME_AES128, - AllocateAES128Cipher, - FreeAES128Cipher, - CloneAES128Cipher, - GetLegacyAES128Cipher, - GetPageSizeAES128Cipher, - GetReservedAES128Cipher, - GetSaltAES128Cipher, - GenerateKeyAES128Cipher, - EncryptPageAES128Cipher, - DecryptPageAES128Cipher -}; -#endif -/*** End of #include "cipher_wxaes128.c" ***/ +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * c: ciphertext output buffer + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +int aegis128x2_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, + size_t mlen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); -/* #include "cipher_wxaes256.c" */ -/*** Begin of #include "cipher_wxaes256.c" ***/ /* -** Name: cipher_wxaes256.c -** Purpose: Implementation of cipher wxSQLite3 AES 256-bit -** Author: Ulrich Telle -** Created: 2020-02-02 -** Copyright: (c) 2006-2024 Ulrich Telle -** License: MIT -*/ + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis128x2_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) __attribute__((warn_unused_result)); -/* #include "cipher_common.h" */ +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * c: ciphertext output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +int aegis128x2_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k); +/* + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis128x2_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) + __attribute__((warn_unused_result)); -/* --- AES 256-bit cipher (wxSQLite3) --- */ -#if HAVE_CIPHER_AES_256_CBC +#ifndef AEGIS_OMIT_INCREMENTAL -#define CIPHER_NAME_AES256 "aes256cbc" +/* + * Initialize a state for incremental encryption or decryption. + * + * st_: state to initialize + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128x2_state_init(aegis128x2_state *st_, const uint8_t *ad, size_t adlen, + const uint8_t *npub, const uint8_t *k); /* -** Configuration parameters for "aes256cbc" + * Encrypt a message chunk. + * The same function can be used regardless of whether the tag will be attached or not. + * + * st_: state to update + * c: ciphertext output buffer + * clen_max: length of the ciphertext chunk buffer (must be >= mlen) + * written: number of ciphertext bytes actually written + * m: plaintext input buffer + * mlen: length of the plaintext + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128x2_state_encrypt_update(aegis128x2_state *st_, uint8_t *c, size_t clen_max, + size_t *written, const uint8_t *m, size_t mlen); + +/* + * Finalize the incremental encryption and generate the authentication tag. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes) + * written: number of ciphertext bytes actually written + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128x2_state_encrypt_detached_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); + +/* + * Finalize the incremental encryption and attach the authentication tag + * to the final ciphertext chunk. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes+maclen) + * written: number of ciphertext bytes actually written + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128x2_state_encrypt_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, + size_t *written, size_t maclen); + +/* + * Decrypt a message chunk. + * + * The output should never be released to the caller until the tag has been verified. + * + * st_: state to update + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= clen) + * written: number of plaintext bytes actually written + * c: ciphertext chunk input buffer + * clen: length of the ciphertext chunk + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128x2_state_decrypt_detached_update(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) + __attribute__((warn_unused_result)); + +/* + * Decrypt the final message chunk and verify the authentication tag. + * + * st_: state to finalize + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= remaining bytes) + * written: number of plaintext bytes actually written + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128x2_state_decrypt_detached_final(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) + __attribute__((warn_unused_result)); + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +/* + * Return a deterministic pseudo-random byte sequence. + * + * out: output buffer + * len: number of bytes to generate + * npub: nonce input buffer (16 bytes) - Can be set to `NULL` if only one sequence has to be + * generated from a given key. + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128x2_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); + +/* + * Encrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * c: ciphertext output buffer + * m: plaintext input buffer + * mlen: length of the plaintext + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128x2_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, + const uint8_t *npub, const uint8_t *k); + +/* + * Decrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128x2_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, + const uint8_t *npub, const uint8_t *k); + +#ifndef AEGIS_OMIT_MAC_API + +/* + * Initialize a state for generating a MAC. + * + * st_: state to initialize + * k: key input buffer (16 bytes) + * + * - The same key MUST NOT be used both for MAC and encryption. + * - If the key is secret, the MAC is secure against forgery. + * - However, if the key is known, arbitrary inputs matching a tag can be efficiently computed. + * + * The recommended way to use the MAC mode is to generate a random key and keep it secret. + * + * After initialization, the state can be reused to generate multiple MACs by cloning it + * with `aegis128x2_mac_state_clone()`. It is only safe to copy a state directly without using + * the clone function if the state is guaranteed to be properly aligned. + * + * A state can also be reset for reuse without cloning with `aegis128x2_mac_reset()`. + */ +AEGIS_API +void aegis128x2_mac_init(aegis128x2_mac_state *st_, const uint8_t *k, const uint8_t *npub); + +/* + * Update the MAC state with input data. + * + * st_: state to update + * m: input data + * mlen: length of the input data + * + * This function can be called multiple times. + * + * Once the full input has been absorb, call either `_mac_final` or `_mac_verify`. + */ +AEGIS_API +int aegis128x2_mac_update(aegis128x2_mac_state *st_, const uint8_t *m, size_t mlen); + +/* + * Finalize the MAC and generate the authentication tag. + * + * st_: state to finalize + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32. 32 is recommended). + */ +AEGIS_API +int aegis128x2_mac_final(aegis128x2_mac_state *st_, uint8_t *mac, size_t maclen); + +/* + * Verify a MAC in constant time. + * + * st_: state to verify + * mac: authentication tag to verify + * maclen: length of the authentication tag (16 or 32) + * + * Returns 0 if the tag is authentic, -1 otherwise. + */ +AEGIS_API +int aegis128x2_mac_verify(aegis128x2_mac_state *st_, const uint8_t *mac, size_t maclen); + +/* + * Reset an AEGIS_MAC state. + */ +AEGIS_API +void aegis128x2_mac_reset(aegis128x2_mac_state *st_); + +/* + * Clone an AEGIS-MAC state. + * + * dst: destination state + * src: source state + * + * This function MUST be used in order to clone states. + */ +AEGIS_API +void aegis128x2_mac_state_clone(aegis128x2_mac_state *dst, const aegis128x2_mac_state *src); + +#endif /* AEGIS_OMIT_MAC_API */ + +#ifdef __cplusplus +} +#endif + +#endif /* AEGIS128X2_H */ +/*** End of #include "aegis128x2.h" ***/ + +/* #include "aegis128x4.h" */ +/*** Begin of #include "aegis128x4.h" ***/ +/* +** Name: aegis128x4.h +** Purpose: Header for AEGIS-128x4 API +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X4_H +#define AEGIS128X4_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The length of an AEGIS key, in bytes */ +#define aegis128x4_KEYBYTES 16 + +/* The length of an AEGIS nonce, in bytes */ +#define aegis128x4_NPUBBYTES 16 + +/* The minimum length of an AEGIS authentication tag, in bytes */ +#define aegis128x4_ABYTES_MIN 16 + +/* The maximum length of an AEGIS authentication tag, in bytes */ +#define aegis128x4_ABYTES_MAX 32 + +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +#define aegis128x4_TAILBYTES_MAX 127 + +/* An AEGIS state, for incremental updates */ +typedef struct aegis128x4_state { + CRYPTO_ALIGN(64) uint8_t opaque[832]; +} aegis128x4_state; + +/* An AEGIS state, only for MAC updates */ +typedef struct aegis128x4_mac_state { + CRYPTO_ALIGN(64) uint8_t opaque[1344]; +} aegis128x4_mac_state; + + +/* The length of an AEGIS key, in bytes */ +AEGIS_API +size_t aegis128x4_keybytes(void); + +/* The length of an AEGIS nonce, in bytes */ +AEGIS_API +size_t aegis128x4_npubbytes(void); + +/* The minimum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis128x4_abytes_min(void); + +/* The maximum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis128x4_abytes_max(void); + +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +AEGIS_API +size_t aegis128x4_tailbytes_max(void); + +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * c: ciphertext output buffer + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +int aegis128x4_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, + size_t mlen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + +/* + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis128x4_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) __attribute__((warn_unused_result)); + +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * c: ciphertext output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +int aegis128x4_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k); + +/* + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis128x4_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) + __attribute__((warn_unused_result)); + +#ifndef AEGIS_OMIT_INCREMENTAL + +/* + * Initialize a state for incremental encryption or decryption. + * + * st_: state to initialize + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128x4_state_init(aegis128x4_state *st_, const uint8_t *ad, size_t adlen, + const uint8_t *npub, const uint8_t *k); + +/* + * Encrypt a message chunk. + * The same function can be used regardless of whether the tag will be attached or not. + * + * st_: state to update + * c: ciphertext output buffer + * clen_max: length of the ciphertext chunk buffer (must be >= mlen) + * written: number of ciphertext bytes actually written + * m: plaintext input buffer + * mlen: length of the plaintext + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128x4_state_encrypt_update(aegis128x4_state *st_, uint8_t *c, size_t clen_max, + size_t *written, const uint8_t *m, size_t mlen); + +/* + * Finalize the incremental encryption and generate the authentication tag. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes) + * written: number of ciphertext bytes actually written + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128x4_state_encrypt_detached_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); + +/* + * Finalize the incremental encryption and attach the authentication tag + * to the final ciphertext chunk. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes+maclen) + * written: number of ciphertext bytes actually written + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128x4_state_encrypt_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, + size_t *written, size_t maclen); + +/* + * Decrypt a message chunk. + * + * The output should never be released to the caller until the tag has been verified. + * + * st_: state to update + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= clen) + * written: number of plaintext bytes actually written + * c: ciphertext chunk input buffer + * clen: length of the ciphertext chunk + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128x4_state_decrypt_detached_update(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) + __attribute__((warn_unused_result)); + +/* + * Decrypt the final message chunk and verify the authentication tag. + * + * st_: state to finalize + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= remaining bytes) + * written: number of plaintext bytes actually written + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis128x4_state_decrypt_detached_final(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) + __attribute__((warn_unused_result)); + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +/* + * Return a deterministic pseudo-random byte sequence. + * + * out: output buffer + * len: number of bytes to generate + * npub: nonce input buffer (16 bytes) - Can be set to `NULL` if only one sequence has to be + * generated from a given key. + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128x4_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); + +/* + * Encrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * c: ciphertext output buffer + * m: plaintext input buffer + * mlen: length of the plaintext + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128x4_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, + const uint8_t *npub, const uint8_t *k); + +/* + * Decrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * npub: nonce input buffer (16 bytes) + * k: key input buffer (16 bytes) + */ +AEGIS_API +void aegis128x4_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, + const uint8_t *npub, const uint8_t *k); + +#ifndef AEGIS_OMIT_MAC_API + +/* + * Initialize a state for generating a MAC. + * + * st_: state to initialize + * k: key input buffer (16 bytes) + * + * - The same key MUST NOT be used both for MAC and encryption. + * - If the key is secret, the MAC is secure against forgery. + * - However, if the key is known, arbitrary inputs matching a tag can be efficiently computed. + * + * The recommended way to use the MAC mode is to generate a random key and keep it secret. + * + * After initialization, the state can be reused to generate multiple MACs by cloning it + * with `aegis128x4_mac_state_clone()`. It is only safe to copy a state directly without using + * the clone function if the state is guaranteed to be properly aligned. + * + * A state can also be reset for reuse without cloning with `aegis128x4_mac_reset()`. + */ +AEGIS_API +void aegis128x4_mac_init(aegis128x4_mac_state *st_, const uint8_t *k, const uint8_t *npub); + +/* + * Update the MAC state with input data. + * + * st_: state to update + * m: input data + * mlen: length of the input data + * + * This function can be called multiple times. + * + * Once the full input has been absorb, call either `_mac_final` or `_mac_verify`. + */ +AEGIS_API +int aegis128x4_mac_update(aegis128x4_mac_state *st_, const uint8_t *m, size_t mlen); + +/* + * Finalize the MAC and generate the authentication tag. + * + * st_: state to finalize + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32. 32 is recommended). + */ +AEGIS_API +int aegis128x4_mac_final(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen); + +/* + * Verify a MAC in constant time. + * + * st_: state to verify + * mac: authentication tag to verify + * maclen: length of the authentication tag (16 or 32) + * + * Returns 0 if the tag is authentic, -1 otherwise. + */ +AEGIS_API +int aegis128x4_mac_verify(aegis128x4_mac_state *st_, const uint8_t *mac, size_t maclen); + +/* + * Reset an AEGIS_MAC state. + */ +AEGIS_API +void aegis128x4_mac_reset(aegis128x4_mac_state *st_); + +/* + * Clone an AEGIS-MAC state. + * + * dst: destination state + * src: source state + * + * This function MUST be used in order to clone states. + */ +AEGIS_API +void aegis128x4_mac_state_clone(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src); + +#endif /* AEGIS_OMIT_MAC_API */ + +#ifdef __cplusplus +} +#endif + +#endif /* AEGIS128X4_H */ +/*** End of #include "aegis128x4.h" ***/ + +/* #include "aegis256.h" */ +/*** Begin of #include "aegis256.h" ***/ +/* +** Name: aegis256.h +** Purpose: Header for AEGIS-256 API +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256_H +#define AEGIS256_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The length of an AEGIS key, in bytes */ +#define aegis256_KEYBYTES 32 + +/* The length of an AEGIS nonce, in bytes */ +#define aegis256_NPUBBYTES 32 + +/* The minimum length of an AEGIS authentication tag, in bytes */ +#define aegis256_ABYTES_MIN 16 + +/* The maximum length of an AEGIS authentication tag, in bytes */ +#define aegis256_ABYTES_MAX 32 + +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +#define aegis256_TAILBYTES_MAX 15 + +/* An AEGIS state, for incremental updates */ +typedef struct aegis256_state { + CRYPTO_ALIGN(16) uint8_t opaque[192]; +} aegis256_state; + +/* An AEGIS state, only for MAC updates */ +typedef struct aegis256_mac_state { + CRYPTO_ALIGN(16) uint8_t opaque[288]; +} aegis256_mac_state; + +/* The length of an AEGIS key, in bytes */ +AEGIS_API +size_t aegis256_keybytes(void); + +/* The length of an AEGIS nonce, in bytes */ +AEGIS_API +size_t aegis256_npubbytes(void); + +/* The minimum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis256_abytes_min(void); + +/* The maximum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis256_abytes_max(void); + +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +AEGIS_API +size_t aegis256_tailbytes_max(void); + +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * c: ciphertext output buffer + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +int aegis256_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, + size_t mlen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + +/* + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis256_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) __attribute__((warn_unused_result)); + +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * c: ciphertext output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +int aegis256_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k); + +/* + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis256_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) + __attribute__((warn_unused_result)); + +#ifndef AEGIS_OMIT_INCREMENTAL + +/* + * Initialize a state for incremental encryption or decryption. + * + * st_: state to initialize + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256_state_init(aegis256_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + +/* + * Encrypt a message chunk. + * The same function can be used regardless of whether the tag will be attached or not. + * + * st_: state to update + * c: ciphertext output buffer + * clen_max: length of the ciphertext chunk buffer (must be >= mlen) + * written: number of ciphertext bytes actually written + * m: plaintext input buffer + * mlen: length of the plaintext + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256_state_encrypt_update(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen); + +/* + * Finalize the incremental encryption and generate the authentication tag. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes) + * written: number of ciphertext bytes actually written + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256_state_encrypt_detached_final(aegis256_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); + +/* + * Finalize the incremental encryption and attach the authentication tag + * to the final ciphertext chunk. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes+maclen) + * written: number of ciphertext bytes actually written + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256_state_encrypt_final(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen); + +/* + * Decrypt a message chunk. + * + * The output should never be released to the caller until the tag has been verified. + * + * st_: state to update + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= clen) + * written: number of plaintext bytes actually written + * c: ciphertext chunk input buffer + * clen: length of the ciphertext chunk + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256_state_decrypt_detached_update(aegis256_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) + __attribute__((warn_unused_result)); + +/* + * Decrypt the final message chunk and verify the authentication tag. + * + * st_: state to finalize + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= remaining bytes) + * written: number of plaintext bytes actually written + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256_state_decrypt_detached_final(aegis256_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) + __attribute__((warn_unused_result)); + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +/* + * Return a deterministic pseudo-random byte sequence. + * + * out: output buffer + * len: number of bytes to generate + * npub: nonce input buffer (32 bytes) - Can be set to `NULL` if only one sequence has to be + * generated from a given key. + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); + +/* + * Encrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * c: ciphertext output buffer + * m: plaintext input buffer + * mlen: length of the plaintext + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, + const uint8_t *npub, const uint8_t *k); + +/* + * Decrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, + const uint8_t *npub, const uint8_t *k); + +#ifndef AEGIS_OMIT_MAC_API + +/* + * Initialize a state for generating a MAC. + * + * st_: state to initialize + * k: key input buffer (32 bytes) + * + * - The same key MUST NOT be used both for MAC and encryption. + * - If the key is secret, the MAC is secure against forgery. + * - However, if the key is known, arbitrary inputs matching a tag can be efficiently computed. + * + * The recommended way to use the MAC mode is to generate a random key and keep it secret. + * + * After initialization, the state can be reused to generate multiple MACs by cloning it + * with `aegis256_mac_state_clone()`. It is only safe to copy a state directly without using + * the clone function if the state is guaranteed to be properly aligned. + * + * A state can also be reset for reuse without cloning with `aegis256_mac_reset()`. + */ +AEGIS_API +void aegis256_mac_init(aegis256_mac_state *st_, const uint8_t *k, const uint8_t *npub); + +/* + * Update the MAC state with input data. + * + * st_: state to update + * m: input data + * mlen: length of the input data + * + * This function can be called multiple times. + * + * Once the full input has been absorb, call either `_mac_final` or `_mac_verify`. + */ +AEGIS_API +int aegis256_mac_update(aegis256_mac_state *st_, const uint8_t *m, size_t mlen); + +/* + * Finalize the MAC and generate the authentication tag. + * + * st_: state to finalize + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32. 32 is recommended). + */ +AEGIS_API +int aegis256_mac_final(aegis256_mac_state *st_, uint8_t *mac, size_t maclen); + +/* + * Verify a MAC in constant time. + * + * st_: state to verify + * mac: authentication tag to verify + * maclen: length of the authentication tag (16 or 32) + * + * Returns 0 if the tag is authentic, -1 otherwise. + */ +AEGIS_API +int aegis256_mac_verify(aegis256_mac_state *st_, const uint8_t *mac, size_t maclen); + +/* + * Reset an AEGIS_MAC state. + */ +AEGIS_API +void aegis256_mac_reset(aegis256_mac_state *st_); + +/* + * Clone an AEGIS-MAC state. + * + * dst: destination state + * src: source state + * + * This function MUST be used in order to clone states. + */ +AEGIS_API +void aegis256_mac_state_clone(aegis256_mac_state *dst, const aegis256_mac_state *src); + +#endif /* AEGIS_OMIT_MAC_API */ + +#ifdef __cplusplus +} +#endif + +#endif /* AEGIS256_H */ +/*** End of #include "aegis256.h" ***/ + +/* #include "aegis256x2.h" */ +/*** Begin of #include "aegis256x2.h" ***/ +/* +** Name: aegis256x2.h +** Purpose: Header for AEGIS-256x2 API +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X2_H +#define AEGIS256X2_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The length of an AEGIS key, in bytes */ +#define aegis256x2_KEYBYTES 32 + +/* The length of an AEGIS nonce, in bytes */ +#define aegis256x2_NPUBBYTES 32 + +/* The minimum length of an AEGIS authentication tag, in bytes */ +#define aegis256x2_ABYTES_MIN 16 + +/* The maximum length of an AEGIS authentication tag, in bytes */ +#define aegis256x2_ABYTES_MAX 32 + +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +#define aegis256x2_TAILBYTES_MAX 31 + +/* An AEGIS state, for incremental updates */ +typedef struct aegis256x2_state { + CRYPTO_ALIGN(32) uint8_t opaque[320]; +} aegis256x2_state; + +/* An AEGIS state, only for MAC updates */ +typedef struct aegis256x2_mac_state { + CRYPTO_ALIGN(32) uint8_t opaque[512]; +} aegis256x2_mac_state; + +/* The length of an AEGIS key, in bytes */ +AEGIS_API +size_t aegis256x2_keybytes(void); + +/* The length of an AEGIS nonce, in bytes */ +AEGIS_API +size_t aegis256x2_npubbytes(void); + +/* The minimum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis256x2_abytes_min(void); + +/* The maximum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis256x2_abytes_max(void); + +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +AEGIS_API +size_t aegis256x2_tailbytes_max(void); + +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * c: ciphertext output buffer + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +int aegis256x2_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, + size_t mlen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + +/* + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis256x2_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) __attribute__((warn_unused_result)); + +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * c: ciphertext output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +int aegis256x2_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k); + +/* + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis256x2_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) + __attribute__((warn_unused_result)); + +#ifndef AEGIS_OMIT_INCREMENTAL + +/* + * Initialize a state for incremental encryption or decryption. + * + * st_: state to initialize + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256x2_state_init(aegis256x2_state *st_, const uint8_t *ad, size_t adlen, + const uint8_t *npub, const uint8_t *k); + +/* + * Encrypt a message chunk. + * The same function can be used regardless of whether the tag will be attached or not. + * + * st_: state to update + * c: ciphertext output buffer + * clen_max: length of the ciphertext chunk buffer (must be >= mlen) + * written: number of ciphertext bytes actually written + * m: plaintext input buffer + * mlen: length of the plaintext + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256x2_state_encrypt_update(aegis256x2_state *st_, uint8_t *c, size_t clen_max, + size_t *written, const uint8_t *m, size_t mlen); + +/* + * Finalize the incremental encryption and generate the authentication tag. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes) + * written: number of ciphertext bytes actually written + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256x2_state_encrypt_detached_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); + +/* + * Finalize the incremental encryption and attach the authentication tag + * to the final ciphertext chunk. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes+maclen) + * written: number of ciphertext bytes actually written + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256x2_state_encrypt_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, + size_t *written, size_t maclen); + +/* + * Decrypt a message chunk. + * + * The output should never be released to the caller until the tag has been verified. + * + * st_: state to update + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= clen) + * written: number of plaintext bytes actually written + * c: ciphertext chunk input buffer + * clen: length of the ciphertext chunk + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256x2_state_decrypt_detached_update(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) + __attribute__((warn_unused_result)); + +/* + * Decrypt the final message chunk and verify the authentication tag. + * + * st_: state to finalize + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= remaining bytes) + * written: number of plaintext bytes actually written + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256x2_state_decrypt_detached_final(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) + __attribute__((warn_unused_result)); + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +/* + * Return a deterministic pseudo-random byte sequence. + * + * out: output buffer + * len: number of bytes to generate + * npub: nonce input buffer (32 bytes) - Can be set to `NULL` if only one sequence has to be + * generated from a given key. + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256x2_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); + +/* + * Encrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * c: ciphertext output buffer + * m: plaintext input buffer + * mlen: length of the plaintext + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256x2_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, + const uint8_t *npub, const uint8_t *k); + +/* + * Decrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256x2_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, + const uint8_t *npub, const uint8_t *k); + +#ifndef AEGIS_OMIT_MAC_API + +/* + * Initialize a state for generating a MAC. + * + * st_: state to initialize + * k: key input buffer (32 bytes) + * + * - The same key MUST NOT be used both for MAC and encryption. + * - If the key is secret, the MAC is secure against forgery. + * - However, if the key is known, arbitrary inputs matching a tag can be efficiently computed. + * + * The recommended way to use the MAC mode is to generate a random key and keep it secret. + * + * After initialization, the state can be reused to generate multiple MACs by cloning it + * with `aegis256x2_mac_state_clone()`. It is only safe to copy a state directly without using + * the clone function if the state is guaranteed to be properly aligned. + * + * A state can also be reset for reuse without cloning with `aegis256x2_mac_reset()`. + */ +AEGIS_API +void aegis256x2_mac_init(aegis256x2_mac_state *st_, const uint8_t *k, const uint8_t *npub); + +/* + * Update the MAC state with input data. + * + * st_: state to update + * m: input data + * mlen: length of the input data + * + * This function can be called multiple times. + * + * Once the full input has been absorb, call either `_mac_final` or `_mac_verify`. + */ +AEGIS_API +int aegis256x2_mac_update(aegis256x2_mac_state *st_, const uint8_t *m, size_t mlen); + +/* + * Finalize the MAC and generate the authentication tag. + * + * st_: state to finalize + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32. 32 is recommended). + */ +AEGIS_API +int aegis256x2_mac_final(aegis256x2_mac_state *st_, uint8_t *mac, size_t maclen); + +/* + * Verify a MAC in constant time. + * + * st_: state to verify + * mac: authentication tag to verify + * maclen: length of the authentication tag (16 or 32) + * + * Returns 0 if the tag is authentic, -1 otherwise. + */ +AEGIS_API +int aegis256x2_mac_verify(aegis256x2_mac_state *st_, const uint8_t *mac, size_t maclen); + +/* + * Reset an AEGIS_MAC state. + */ +AEGIS_API +void aegis256x2_mac_reset(aegis256x2_mac_state *st_); + +/* + * Clone an AEGIS-MAC state. + * + * dst: destination state + * src: source state + * + * This function MUST be used in order to clone states. + */ +AEGIS_API +void aegis256x2_mac_state_clone(aegis256x2_mac_state *dst, const aegis256x2_mac_state *src); + +#endif /* AEGIS_OMIT_MAC_API */ + +#ifdef __cplusplus +} +#endif + +#endif /* AEGIS256X2_H */ +/*** End of #include "aegis256x2.h" ***/ + +/* #include "aegis256x4.h" */ +/*** Begin of #include "aegis256x4.h" ***/ +/* +** Name: aegis256x4.h +** Purpose: Header for AEGIS-256x4 API +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X4_H +#define AEGIS256X4_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The length of an AEGIS key, in bytes */ +#define aegis256x4_KEYBYTES 32 + +/* The length of an AEGIS nonce, in bytes */ +#define aegis256x4_NPUBBYTES 32 + +/* The minimum length of an AEGIS authentication tag, in bytes */ +#define aegis256x4_ABYTES_MIN 16 + +/* The maximum length of an AEGIS authentication tag, in bytes */ +#define aegis256x4_ABYTES_MAX 32 + +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +#define aegis256x4_TAILBYTES_MAX 63 + +/* An AEGIS state, for incremental updates */ +typedef struct aegis256x4_state { + CRYPTO_ALIGN(64) uint8_t opaque[576]; +} aegis256x4_state; + +/* An AEGIS state, only for MAC updates */ +typedef struct aegis256x4_mac_state { + CRYPTO_ALIGN(64) uint8_t opaque[960]; +} aegis256x4_mac_state; + +/* The length of an AEGIS key, in bytes */ +AEGIS_API +size_t aegis256x4_keybytes(void); + +/* The length of an AEGIS nonce, in bytes */ +AEGIS_API +size_t aegis256x4_npubbytes(void); + +/* The minimum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis256x4_abytes_min(void); + +/* The maximum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis256x4_abytes_max(void); + +/* + * When using AEGIS in incremental mode, this is the maximum number + * of leftover ciphertext bytes that can be returned at finalization. + */ +AEGIS_API +size_t aegis256x4_tailbytes_max(void); + +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * c: ciphertext output buffer + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +int aegis256x4_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, + size_t mlen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + +/* + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext separately. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis256x4_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) __attribute__((warn_unused_result)); + +/* + * Encrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * c: ciphertext output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * m: plaintext input buffer + * mlen: length of the plaintext + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +int aegis256x4_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k); + +/* + * Decrypt a message with AEGIS in one shot mode, returning the tag and the ciphertext together. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * maclen: length of the authentication tag (16 or 32) + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + * + * Returns 0 if the ciphertext is authentic, -1 otherwise. + */ +AEGIS_API +int aegis256x4_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) + __attribute__((warn_unused_result)); + +#ifndef AEGIS_OMIT_INCREMENTAL + +/* + * Initialize a state for incremental encryption or decryption. + * + * st_: state to initialize + * ad: additional data input buffer + * adlen: length of the additional data + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256x4_state_init(aegis256x4_state *st_, const uint8_t *ad, size_t adlen, + const uint8_t *npub, const uint8_t *k); + +/* + * Encrypt a message chunk. + * The same function can be used regardless of whether the tag will be attached or not. + * + * st_: state to update + * c: ciphertext output buffer + * clen_max: length of the ciphertext chunk buffer (must be >= mlen) + * written: number of ciphertext bytes actually written + * m: plaintext input buffer + * mlen: length of the plaintext + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256x4_state_encrypt_update(aegis256x4_state *st_, uint8_t *c, size_t clen_max, + size_t *written, const uint8_t *m, size_t mlen); + +/* + * Finalize the incremental encryption and generate the authentication tag. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes) + * written: number of ciphertext bytes actually written + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256x4_state_encrypt_detached_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); + +/* + * Finalize the incremental encryption and attach the authentication tag + * to the final ciphertext chunk. + * + * st_: state to finalize + * c: output buffer for the final ciphertext chunk + * clen_max: length of the ciphertext chunk buffer (must be >= remaining bytes+maclen) + * written: number of ciphertext bytes actually written + * maclen: length of the authentication tag to generate (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256x4_state_encrypt_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, + size_t *written, size_t maclen); + +/* + * Decrypt a message chunk. + * + * The output should never be released to the caller until the tag has been verified. + * + * st_: state to update + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= clen) + * written: number of plaintext bytes actually written + * c: ciphertext chunk input buffer + * clen: length of the ciphertext chunk + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256x4_state_decrypt_detached_update(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) + __attribute__((warn_unused_result)); + +/* + * Decrypt the final message chunk and verify the authentication tag. + * + * st_: state to finalize + * m: plaintext output buffer + * mlen_max: length of the plaintext chunk buffer (must be >= remaining bytes) + * written: number of plaintext bytes actually written + * mac: authentication tag input buffer + * maclen: length of the authentication tag (16 or 32) + * + * Return 0 on success, -1 on failure. + */ +AEGIS_API +int aegis256x4_state_decrypt_detached_final(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) + __attribute__((warn_unused_result)); + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +/* + * Return a deterministic pseudo-random byte sequence. + * + * out: output buffer + * len: number of bytes to generate + * npub: nonce input buffer (32 bytes) - Can be set to `NULL` if only one sequence has to be + * generated from a given key. + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256x4_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); + +/* + * Encrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * c: ciphertext output buffer + * m: plaintext input buffer + * mlen: length of the plaintext + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256x4_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, + const uint8_t *npub, const uint8_t *k); + +/* + * Decrypt a message WITHOUT AUTHENTICATION, similar to AES-CTR. + * + * WARNING: this is an insecure mode of operation, provided for compatibility with specific + * protocols that bring their own authentication scheme. + * + * m: plaintext output buffer + * c: ciphertext input buffer + * clen: length of the ciphertext + * npub: nonce input buffer (32 bytes) + * k: key input buffer (32 bytes) + */ +AEGIS_API +void aegis256x4_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, + const uint8_t *npub, const uint8_t *k); + +#ifndef AEGIS_OMIT_MAC_API + +/* + * Initialize a state for generating a MAC. + * + * st_: state to initialize + * k: key input buffer (32 bytes) + * + * - The same key MUST NOT be used both for MAC and encryption. + * - If the key is secret, the MAC is secure against forgery. + * - However, if the key is known, arbitrary inputs matching a tag can be efficiently computed. + * + * The recommended way to use the MAC mode is to generate a random key and keep it secret. + * + * After initialization, the state can be reused to generate multiple MACs by cloning it + * with `aegis256x4_mac_state_clone()`. It is only safe to copy a state directly without using + * the clone function if the state is guaranteed to be properly aligned. + * + * A state can also be reset for reuse without cloning with `aegis256x4_mac_reset()`. + */ +AEGIS_API +void aegis256x4_mac_init(aegis256x4_mac_state *st_, const uint8_t *k, const uint8_t *npub); + +/* + * Update the MAC state with input data. + * + * st_: state to update + * m: input data + * mlen: length of the input data + * + * This function can be called multiple times. + * + * Once the full input has been absorb, call either `_mac_final` or `_mac_verify`. + */ +AEGIS_API +int aegis256x4_mac_update(aegis256x4_mac_state *st_, const uint8_t *m, size_t mlen); + +/* + * Finalize the MAC and generate the authentication tag. + * + * st_: state to finalize + * mac: authentication tag output buffer + * maclen: length of the authentication tag to generate (16 or 32. 32 is recommended). + */ +AEGIS_API +int aegis256x4_mac_final(aegis256x4_mac_state *st_, uint8_t *mac, size_t maclen); + +/* + * Verify a MAC in constant time. + * + * st_: state to verify + * mac: authentication tag to verify + * maclen: length of the authentication tag (16 or 32) + * + * Returns 0 if the tag is authentic, -1 otherwise. + */ +AEGIS_API +int aegis256x4_mac_verify(aegis256x4_mac_state *st_, const uint8_t *mac, size_t maclen); + +/* + * Reset an AEGIS_MAC state. + */ +AEGIS_API +void aegis256x4_mac_reset(aegis256x4_mac_state *st_); + +/* + * Clone an AEGIS-MAC state. + * + * dst: destination state + * src: source state + * + * This function MUST be used in order to clone states. + */ +AEGIS_API +void aegis256x4_mac_state_clone(aegis256x4_mac_state *dst, const aegis256x4_mac_state *src); + +#endif /* AEGIS_OMIT_MAC_API */ + +#ifdef __cplusplus +} +#endif + +#endif /* AEGIS256X4_H */ +/*** End of #include "aegis256x4.h" ***/ + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initialize the AEGIS library. + * + * This function does runtime CPU capability detection, and must be called once + * in your application before doing anything else with the library. + * + * If you don't, AEGIS will still work, but it may be much slower. + * + * The function can be called multiple times but is not thread-safe. + */ +AEGIS_API +int aegis_init(void); + +/* Compare two 16-byte blocks for equality. + * + * This function is designed to be used in constant-time code. + * + * Returns 0 if the blocks are equal, -1 otherwise. + */ +AEGIS_API +int aegis_verify_16(const uint8_t *x, const uint8_t *y) __attribute__((warn_unused_result)); + +/* Compare two 32-byte blocks for equality. + * + * This function is designed to be used in constant-time code. + * + * Returns 0 if the blocks are equal, -1 otherwise. + */ +AEGIS_API +int aegis_verify_32(const uint8_t *x, const uint8_t *y) __attribute__((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif /* AEGIS_H */ +/*** End of #include "../include/aegis.h" ***/ + +/* #include "cpu.h" */ + + +#ifdef __linux__ +# define HAVE_SYS_AUXV_H +# define HAVE_GETAUXVAL +#endif +#ifdef __ANDROID_API__ +# if __ANDROID_API__ < 18 +# undef HAVE_GETAUXVAL +# define HAVE_ANDROID_GETCPUFEATURES +# endif +#endif +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) + +# define HAVE_CPUID +# define NATIVE_LITTLE_ENDIAN +# if defined(__clang__) || defined(__GNUC__) +# define HAVE_AVX_ASM +# endif +#endif +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +# define HAVE_AVXINTRIN_H +# define HAVE_AVX2INTRIN_H +# define HAVE_AVX512FINTRIN_H +# define HAVE_TMMINTRIN_H +# define HAVE_WMMINTRIN_H +# define HAVE_VAESINTRIN_H +# ifdef __GNUC__ +# if !__has_include() +# undef HAVE_VAESINTRIN_H +# endif +# endif + +/* target pragmas don't define these flags on clang-cl (an alternative clang driver for Windows) */ +# if defined(__clang__) && defined(_MSC_BUILD) && defined(_MSC_VER) && \ + (defined(_M_IX86) || defined(_M_AMD64)) && !defined(__SSE3__) +# undef __SSE3__ +# undef __SSSE3__ +# undef __SSE4_1__ +# undef __AVX__ +# undef __AVX2__ +# undef __AVX512F__ +# undef __AES__ +# undef __VAES__ + +# define __SSE3__ 1 +# define __SSSE3__ 1 +# define __SSE4_1__ 1 +# define __AVX__ 1 +# define __AVX2__ 1 +# define __AVX512F__ 1 +# define __AES__ 1 +# define __VAES__ 1 +# endif + +#endif + +#ifdef DISABLE_AVX2 +# undef HAVE_AVXINTRIN_H +# undef HAVE_AVX2INTRIN_H +# undef HAVE_AVX512FINTRIN_H +# undef HAVE_VAESINTRIN_H +#endif +#ifdef DISABLE_AVX512 +# undef HAVE_AVX512FINTRIN_H +#endif + +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# ifndef NATIVE_LITTLE_ENDIAN +# define NATIVE_LITTLE_ENDIAN +# endif +#endif + +#if defined(__INTEL_COMPILER) || defined(_MSC_VER) +# define CRYPTO_ALIGN(x) __declspec(align(x)) +#else +# define CRYPTO_ALIGN(x) __attribute__((aligned(x))) +#endif + +#define AEGIS_LOAD32_LE(SRC) aegis_load32_le(SRC) +static inline uint32_t +aegis_load32_le(const uint8_t src[4]) +{ +#ifdef NATIVE_LITTLE_ENDIAN + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + uint32_t w = (uint32_t) src[0]; + w |= (uint32_t) src[1] << 8; + w |= (uint32_t) src[2] << 16; + w |= (uint32_t) src[3] << 24; + return w; +#endif +} + +#define AEGIS_STORE32_LE(DST, W) aegis_store32_le((DST), (W)) +static inline void +aegis_store32_le(uint8_t dst[4], uint32_t w) +{ +#ifdef NATIVE_LITTLE_ENDIAN + memcpy(dst, &w, sizeof w); +#else + dst[0] = (uint8_t) w; + w >>= 8; + dst[1] = (uint8_t) w; + w >>= 8; + dst[2] = (uint8_t) w; + w >>= 8; + dst[3] = (uint8_t) w; +#endif +} + +#define AEGIS_ROTL32(X, B) aegis_rotl32((X), (B)) +static inline uint32_t +aegis_rotl32(const uint32_t x, const int b) +{ + return (x << b) | (x >> (32 - b)); +} + +#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1]) + +#ifndef ERANGE +# define ERANGE 34 +#endif +#ifndef EINVAL +# define EINVAL 22 +#endif + +#if defined(_MSC_VER) + #define FORCEINLINE __forceinline +#elif defined(__GNUC__) || defined(__clang__) + #define FORCEINLINE static inline __attribute__((always_inline)) +#else + #define FORCEINLINE inline // Fallback +#endif + +#define AEGIS_CONCAT(A,B) AEGIS_CONCAT_(A,B) +#define AEGIS_CONCAT_(A,B) A##B +#define AEGIS_FUNC(name) AEGIS_CONCAT(AEGIS_FUNC_PREFIX,AEGIS_CONCAT(_,name)) + +#define AEGIS_API_IMPL_LIST_STD \ + .encrypt_detached = AEGIS_encrypt_detached, \ + .decrypt_detached = AEGIS_decrypt_detached, \ + .encrypt_unauthenticated = AEGIS_encrypt_unauthenticated, \ + .decrypt_unauthenticated = AEGIS_decrypt_unauthenticated, \ + .stream = AEGIS_stream, +#define AEGIS_API_IMPL_LIST_INC \ + .state_init = AEGIS_state_init, \ + .state_encrypt_update = AEGIS_state_encrypt_update, \ + .state_encrypt_detached_final = AEGIS_state_encrypt_detached_final, \ + .state_encrypt_final = AEGIS_state_encrypt_final, \ + .state_decrypt_detached_update = AEGIS_state_decrypt_detached_update, \ + .state_decrypt_detached_final = AEGIS_state_decrypt_detached_final, +#define AEGIS_API_IMPL_LIST_MAC \ + .state_mac_init = AEGIS_state_mac_init, \ + .state_mac_update = AEGIS_state_mac_update, \ + .state_mac_final = AEGIS_state_mac_final, \ + .state_mac_reset = AEGIS_state_mac_reset, \ + .state_mac_clone = AEGIS_state_mac_clone, + +#if 0 +#define AEGIS_API_IMPL_LIST \ + .encrypt_detached = AEGIS_encrypt_detached, \ + .decrypt_detached = AEGIS_decrypt_detached, \ + .encrypt_unauthenticated = AEGIS_encrypt_unauthenticated, \ + .decrypt_unauthenticated = AEGIS_decrypt_unauthenticated, \ + .stream = AEGIS_stream, \ + .state_init = AEGIS_state_init, \ + .state_encrypt_update = AEGIS_state_encrypt_update, \ + .state_encrypt_detached_final = AEGIS_state_encrypt_detached_final, \ + .state_encrypt_final = AEGIS_state_encrypt_final, \ + .state_decrypt_detached_update = AEGIS_state_decrypt_detached_update, \ + .state_decrypt_detached_final = AEGIS_state_decrypt_detached_final, \ + .state_mac_init = AEGIS_state_mac_init, \ + .state_mac_update = AEGIS_state_mac_update, \ + .state_mac_final = AEGIS_state_mac_final, \ + .state_mac_reset = AEGIS_state_mac_reset, \ + .state_mac_clone = AEGIS_state_mac_clone, +#endif + +#endif /* AEGIS_COMMON_H */ +/*** End of #include "common.h" ***/ + +/* #include "cpu.h" */ + + +static volatile uint16_t optblocker_u16; + +static inline int +aegis_verify_n(const uint8_t *x_, const uint8_t *y_, const int n) +{ + const volatile uint8_t *volatile x = (const volatile uint8_t *volatile) x_; + const volatile uint8_t *volatile y = (const volatile uint8_t *volatile) y_; + volatile uint16_t d = 0U; + int i; + + for (i = 0; i < n; i++) { + d |= x[i] ^ y[i]; + } +#if defined(__GNUC__) || defined(__clang__) + __asm__("" : "+r"(d) :); +#endif + d--; + d = ((d >> 13) ^ optblocker_u16) >> 2; + + return (int) d - 1; +} + +AEGIS_API +int +aegis_verify_16(const uint8_t *x, const uint8_t *y) +{ + return aegis_verify_n(x, y, 16); +} + +AEGIS_API +int +aegis_verify_32(const uint8_t *x, const uint8_t *y) +{ + return aegis_verify_n(x, y, 32); +} + +AEGIS_PRIVATE int aegis128l_pick_best_implementation(void); +AEGIS_PRIVATE int aegis128x2_pick_best_implementation(void); +AEGIS_PRIVATE int aegis128x4_pick_best_implementation(void); +AEGIS_PRIVATE int aegis256_pick_best_implementation(void); +AEGIS_PRIVATE int aegis256x2_pick_best_implementation(void); +AEGIS_PRIVATE int aegis256x4_pick_best_implementation(void); + +AEGIS_API +int +aegis_init(void) +{ + static int initialized = 0; + + if (initialized) { + return 0; + } + if (aegis_runtime_get_cpu_features() != 0) { + return 0; + } + if (aegis128l_pick_best_implementation() != 0 || aegis128x2_pick_best_implementation() != 0 || + aegis128x4_pick_best_implementation() != 0 || aegis256_pick_best_implementation() != 0 || + aegis256x2_pick_best_implementation() != 0 || aegis256x4_pick_best_implementation() != 0) { + return -1; + } + initialized = 1; + + return 0; +} + +#if 0 +#if defined(_MSC_VER) +# pragma section(".CRT$XCU", read) +static void __cdecl _do_aegis_init(void); +__declspec(allocate(".CRT$XCU")) void (*aegis_init_constructor)(void) = _do_aegis_init; +#else +static void _do_aegis_init(void) __attribute__((constructor)); +#endif + +static void +_do_aegis_init(void) +{ + (void) aegis_init(); +} +#endif +/*** End of #include "common/common.c" ***/ + +/* #include "common/cpu.c" */ +/*** Begin of #include "common/cpu.c" ***/ +/* +** Name: cpu.c +** Purpose: Implementation of CPU feature identification +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "cpu.h" */ + +/* #include "common.h" */ + + +#include +#include +#include + +#ifdef HAVE_ANDROID_GETCPUFEATURES +# include +#endif +#ifdef __APPLE__ +# include +# include +# include +#endif +#ifdef HAVE_SYS_AUXV_H +# include +#endif +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) +# include +#endif + +typedef struct CPUFeatures_ { + int initialized; + int has_neon; + int has_armcrypto; + int has_avx; + int has_avx2; + int has_avx512f; + int has_aesni; + int has_vaes; + int has_altivec; +} CPUFeatures; + +static CPUFeatures _cpu_features; + +#define CPUID_EBX_AVX2 0x00000020 +#define CPUID_EBX_AVX512F 0x00010000 + +#define CPUID_ECX_AESNI 0x02000000 +#define CPUID_ECX_XSAVE 0x04000000 +#define CPUID_ECX_OSXSAVE 0x08000000 +#define CPUID_ECX_AVX 0x10000000 +#define CPUID_ECX_VAES 0x00000200 + +#define XCR0_SSE 0x00000002 +#define XCR0_AVX 0x00000004 +#define XCR0_OPMASK 0x00000020 +#define XCR0_ZMM_HI256 0x00000040 +#define XCR0_HI16_ZMM 0x00000080 + +static int +_runtime_arm_cpu_features(CPUFeatures *const cpu_features) +{ +#ifndef __ARM_ARCH + return -1; /* LCOV_EXCL_LINE */ +#endif + +#if defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) + cpu_features->has_neon = 1; +#elif defined(HAVE_ANDROID_GETCPUFEATURES) && defined(ANDROID_CPU_ARM_FEATURE_NEON) + cpu_features->has_neon = (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0x0; +#elif (defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) && defined(AT_HWCAP) +# ifdef HAVE_GETAUXVAL + cpu_features->has_neon = (getauxval(AT_HWCAP) & (1L << 1)) != 0; +# elif defined(HAVE_ELF_AUX_INFO) + { + unsigned long buf; + if (elf_aux_info(AT_HWCAP, (void *) &buf, (int) sizeof buf) == 0) { + cpu_features->has_neon = (buf & (1L << 1)) != 0; + } + } +# endif +#elif defined(__arm__) && defined(AT_HWCAP) +# ifdef HAVE_GETAUXVAL + cpu_features->has_neon = (getauxval(AT_HWCAP) & (1L << 12)) != 0; +# elif defined(HAVE_ELF_AUX_INFO) + { + unsigned long buf; + if (elf_aux_info(AT_HWCAP, (void *) &buf, (int) sizeof buf) == 0) { + cpu_features->has_neon = (buf & (1L << 12)) != 0; + } + } +# endif +#endif + + if (cpu_features->has_neon == 0) { + return 0; + } + +#if __ARM_FEATURE_CRYPTO + cpu_features->has_armcrypto = 1; +#elif defined(_M_ARM64) || defined(_M_ARM64EC) + cpu_features->has_armcrypto = + 1; /* assuming all CPUs supported by ARM Windows have the crypto extensions */ +#elif defined(__APPLE__) && defined(CPU_TYPE_ARM64) && defined(CPU_SUBTYPE_ARM64E) + { + cpu_type_t cpu_type; + cpu_subtype_t cpu_subtype; + size_t cpu_type_len = sizeof cpu_type; + size_t cpu_subtype_len = sizeof cpu_subtype; + + if (sysctlbyname("hw.cputype", &cpu_type, &cpu_type_len, NULL, 0) == 0 && + cpu_type == CPU_TYPE_ARM64 && + sysctlbyname("hw.cpusubtype", &cpu_subtype, &cpu_subtype_len, NULL, 0) == 0 && + (cpu_subtype == CPU_SUBTYPE_ARM64E || cpu_subtype == CPU_SUBTYPE_ARM64_V8)) { + cpu_features->has_armcrypto = 1; + } + } +#elif defined(HAVE_ANDROID_GETCPUFEATURES) && defined(ANDROID_CPU_ARM_FEATURE_AES) + cpu_features->has_armcrypto = (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_AES) != 0x0; +#elif (defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) && defined(AT_HWCAP) +# ifdef HAVE_GETAUXVAL + cpu_features->has_armcrypto = (getauxval(AT_HWCAP) & (1L << 3)) != 0; +# elif defined(HAVE_ELF_AUX_INFO) + { + unsigned long buf; + if (elf_aux_info(AT_HWCAP, (void *) &buf, (int) sizeof buf) == 0) { + cpu_features->has_armcrypto = (buf & (1L << 3)) != 0; + } + } +# endif +#elif defined(__arm__) && defined(AT_HWCAP2) +# ifdef HAVE_GETAUXVAL + cpu_features->has_armcrypto = (getauxval(AT_HWCAP2) & (1L << 0)) != 0; +# elif defined(HAVE_ELF_AUX_INFO) + { + unsigned long buf; + if (elf_aux_info(AT_HWCAP2, (void *) &buf, (int) sizeof buf) == 0) { + cpu_features->has_armcrypto = (buf & (1L << 0)) != 0; + } + } +# endif +#endif + + return 0; +} + +static void +_cpuid(unsigned int cpu_info[4U], const unsigned int cpu_info_type) +{ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) + (__cpuid)((int *) cpu_info, cpu_info_type); +#elif defined(HAVE_CPUID) + cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; +# ifdef __i386__ + __asm__ __volatile__( + "pushfl; pushfl; " + "popl %0; " + "movl %0, %1; xorl %2, %0; " + "pushl %0; " + "popfl; pushfl; popl %0; popfl" + : "=&r"(cpu_info[0]), "=&r"(cpu_info[1]) + : "i"(0x200000)); + if (((cpu_info[0] ^ cpu_info[1]) & 0x200000) == 0x0) { + return; /* LCOV_EXCL_LINE */ + } +# endif +# ifdef __i386__ + __asm__ __volatile__("xchgl %%ebx, %k1; cpuid; xchgl %%ebx, %k1" + : "=a"(cpu_info[0]), "=&r"(cpu_info[1]), "=c"(cpu_info[2]), + "=d"(cpu_info[3]) + : "0"(cpu_info_type), "2"(0U)); +# elif defined(__x86_64__) + __asm__ __volatile__("xchgq %%rbx, %q1; cpuid; xchgq %%rbx, %q1" + : "=a"(cpu_info[0]), "=&r"(cpu_info[1]), "=c"(cpu_info[2]), + "=d"(cpu_info[3]) + : "0"(cpu_info_type), "2"(0U)); +# else + __asm__ __volatile__("cpuid" + : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), + "=d"(cpu_info[3]) + : "0"(cpu_info_type), "2"(0U)); +# endif +#else + (void) cpu_info_type; + cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; +#endif +} + +static int +_runtime_intel_cpu_features(CPUFeatures *const cpu_features) +{ + unsigned int cpu_info[4]; + uint32_t xcr0 = 0U; + + _cpuid(cpu_info, 0x0); + if (cpu_info[0] == 0U) { + return -1; /* LCOV_EXCL_LINE */ + } + _cpuid(cpu_info, 0x00000001); + + (void) xcr0; +#ifdef HAVE_AVXINTRIN_H + if ((cpu_info[2] & (CPUID_ECX_AVX | CPUID_ECX_XSAVE | CPUID_ECX_OSXSAVE)) == + (CPUID_ECX_AVX | CPUID_ECX_XSAVE | CPUID_ECX_OSXSAVE)) { + xcr0 = 0U; +# if defined(HAVE__XGETBV) || \ + (defined(_MSC_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) && _MSC_FULL_VER >= 160040219) + xcr0 = (uint32_t) _xgetbv(0); +# elif defined(_MSC_VER) && defined(_M_IX86) + /* + * Visual Studio documentation states that eax/ecx/edx don't need to + * be preserved in inline assembly code. But that doesn't seem to + * always hold true on Visual Studio 2010. + */ + __asm { + push eax + push ecx + push edx + xor ecx, ecx + _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0 + mov xcr0, eax + pop edx + pop ecx + pop eax + } +# elif defined(HAVE_AVX_ASM) + __asm__ __volatile__(".byte 0x0f, 0x01, 0xd0" /* XGETBV */ + : "=a"(xcr0) + : "c"((uint32_t) 0U) + : "%edx"); +# endif + if ((xcr0 & (XCR0_SSE | XCR0_AVX)) == (XCR0_SSE | XCR0_AVX)) { + cpu_features->has_avx = 1; + } + } +#endif + +#ifdef HAVE_WMMINTRIN_H + cpu_features->has_aesni = ((cpu_info[2] & CPUID_ECX_AESNI) != 0x0); +#endif + +#ifdef HAVE_AVX2INTRIN_H + if (cpu_features->has_avx) { + unsigned int cpu_info7[4]; + + _cpuid(cpu_info7, 0x00000007); + cpu_features->has_avx2 = ((cpu_info7[1] & CPUID_EBX_AVX2) != 0x0); + cpu_features->has_vaes = + cpu_features->has_aesni && ((cpu_info7[2] & CPUID_ECX_VAES) != 0x0); + } +#endif + + cpu_features->has_avx512f = 0; +#ifdef HAVE_AVX512FINTRIN_H + if (cpu_features->has_avx2) { + unsigned int cpu_info7[4]; + + _cpuid(cpu_info7, 0x00000007); + /* LCOV_EXCL_START */ + if ((cpu_info7[1] & CPUID_EBX_AVX512F) == CPUID_EBX_AVX512F && + (xcr0 & (XCR0_OPMASK | XCR0_ZMM_HI256 | XCR0_HI16_ZMM)) == + (XCR0_OPMASK | XCR0_ZMM_HI256 | XCR0_HI16_ZMM)) { + cpu_features->has_avx512f = 1; + } + /* LCOV_EXCL_STOP */ + } +#endif + + return 0; +} + +static int +_runtime_powerpc_cpu_features(CPUFeatures *const cpu_features) +{ + cpu_features->has_altivec = 0; +#if defined(__ALTIVEC__) && defined(__CRYPTO__) + cpu_features->has_altivec = 1; +#endif + return 0; +} + +AEGIS_PRIVATE +int +aegis_runtime_get_cpu_features(void) +{ + int ret = -1; + + memset(&_cpu_features, 0, sizeof _cpu_features); + + ret &= _runtime_arm_cpu_features(&_cpu_features); + ret &= _runtime_intel_cpu_features(&_cpu_features); + ret &= _runtime_powerpc_cpu_features(&_cpu_features); + _cpu_features.initialized = 1; + + return ret; +} + +AEGIS_PRIVATE +int +aegis_runtime_has_neon(void) +{ + return _cpu_features.has_neon; +} + +AEGIS_PRIVATE +int +aegis_runtime_has_armcrypto(void) +{ + return _cpu_features.has_armcrypto; +} + +AEGIS_PRIVATE +int +aegis_runtime_has_avx(void) +{ + return _cpu_features.has_avx; +} + +AEGIS_PRIVATE +int +aegis_runtime_has_avx2(void) +{ + return _cpu_features.has_avx2; +} + +AEGIS_PRIVATE +int +aegis_runtime_has_avx512f(void) +{ + return _cpu_features.has_avx512f; +} + +AEGIS_PRIVATE +int +aegis_runtime_has_aesni(void) +{ + return _cpu_features.has_aesni; +} + +AEGIS_PRIVATE +int +aegis_runtime_has_vaes(void) +{ + return _cpu_features.has_vaes; +} + +AEGIS_PRIVATE +int +aegis_runtime_has_altivec(void) +{ + return _cpu_features.has_altivec; +} +/*** End of #include "common/cpu.c" ***/ + +/* #include "common/softaes.c" */ +/*** Begin of #include "common/softaes.c" ***/ +/* +** Name: softaes.c +** Purpose: Implementation of AES via software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include + +/* #include "common.h" */ + +/* #include "softaes.h" */ +/*** Begin of #include "softaes.h" ***/ +/* +** Name: softaes.h +** Purpose: Header for API of AES software implementation +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS_SOFTAES_H +#define AEGIS_SOFTAES_H + +#include + +/* #include "common.h" */ + + +typedef struct SoftAesBlock { + uint32_t w0; + uint32_t w1; + uint32_t w2; + uint32_t w3; +} SoftAesBlock; + +static SoftAesBlock +softaes_block_encrypt(const SoftAesBlock block, const SoftAesBlock rk); + +static inline SoftAesBlock +softaes_block_load(const uint8_t in[16]) +{ +#ifdef NATIVE_LITTLE_ENDIAN + SoftAesBlock out; + memcpy(&out, in, 16); +#else + const SoftAesBlock out = { AEGIS_LOAD32_LE(in + 0), AEGIS_LOAD32_LE(in + 4), AEGIS_LOAD32_LE(in + 8), + AEGIS_LOAD32_LE(in + 12) }; +#endif + return out; +} + +static inline SoftAesBlock +softaes_block_load64x2(const uint64_t a, const uint64_t b) +{ + const SoftAesBlock out = { (uint32_t) b, (uint32_t) (b >> 32), (uint32_t) a, + (uint32_t) (a >> 32) }; + return out; +} + +static inline void +softaes_block_store(uint8_t out[16], const SoftAesBlock in) +{ +#ifdef NATIVE_LITTLE_ENDIAN + memcpy(out, &in, 16); +#else + AEGIS_STORE32_LE(out + 0, in.w0); + AEGIS_STORE32_LE(out + 4, in.w1); + AEGIS_STORE32_LE(out + 8, in.w2); + AEGIS_STORE32_LE(out + 12, in.w3); +#endif +} + +static inline SoftAesBlock +softaes_block_xor(const SoftAesBlock a, const SoftAesBlock b) +{ + const SoftAesBlock out = { a.w0 ^ b.w0, a.w1 ^ b.w1, a.w2 ^ b.w2, a.w3 ^ b.w3 }; + return out; +} + +static inline SoftAesBlock +softaes_block_and(const SoftAesBlock a, const SoftAesBlock b) +{ + const SoftAesBlock out = { a.w0 & b.w0, a.w1 & b.w1, a.w2 & b.w2, a.w3 & b.w3 }; + return out; +} + +#endif /* AEGIS_SOFTAES_H */ +/*** End of #include "softaes.h" ***/ + + +#if defined(__wasm__) && !defined(FAVOR_PERFORMANCE) +# define FAVOR_PERFORMANCE +#endif + +#ifndef SOFTAES_STRIDE +# define SOFTAES_STRIDE 16 +#endif + +#ifdef FAVOR_PERFORMANCE +static const uint32_t _aes_lut[1024] = { + 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, + 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, + 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, + 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, + 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, + 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, + 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, + 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, + 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, + 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, + 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, + 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, + 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, + 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, + 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, + 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, + 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, + 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, + 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, + 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, + 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, + 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, + 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, + 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, + 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, + 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, + 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, + 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, + 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, + 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, + 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, + 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c, + 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, + 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, + 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, + 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, + 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, + 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, + 0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, + 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, + 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, + 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, + 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, + 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, + 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, + 0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, + 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, + 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, + 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, + 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, + 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, + 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, + 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, + 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, + 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, + 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, + 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, + 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, + 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, + 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, + 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, + 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, + 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, + 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a, + 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, + 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, + 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, + 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, + 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, + 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, + 0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, + 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, + 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, + 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, + 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, + 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, + 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, + 0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, + 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, + 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, + 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, + 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, + 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, + 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, + 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, + 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, + 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, + 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, + 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, + 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, + 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, + 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, + 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, + 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, + 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, + 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16, + 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, + 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, + 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, + 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, + 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, + 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, + 0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, + 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, + 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, + 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, + 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, + 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, + 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, + 0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, + 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, + 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, + 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, + 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, + 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, + 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, + 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, + 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, + 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, + 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, + 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, + 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, + 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, + 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, + 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, + 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, + 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, + 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616 +}; + +static const uint32_t* const LUT0 = _aes_lut + 0 * 256; +static const uint32_t* const LUT1 = _aes_lut + 1 * 256; +static const uint32_t* const LUT2 = _aes_lut + 2 * 256; +static const uint32_t* const LUT3 = _aes_lut + 3 * 256; + +SoftAesBlock +softaes_block_encrypt(const SoftAesBlock block, const SoftAesBlock rk) +{ + SoftAesBlock out; + uint8_t ix0[4], ix1[4], ix2[4], ix3[4]; + const uint32_t s0 = block.w0; + const uint32_t s1 = block.w1; + const uint32_t s2 = block.w2; + const uint32_t s3 = block.w3; + + ix0[0] = (uint8_t) s0; + ix0[1] = (uint8_t) s1; + ix0[2] = (uint8_t) s2; + ix0[3] = (uint8_t) s3; + + ix1[0] = (uint8_t) (s1 >> 8); + ix1[1] = (uint8_t) (s2 >> 8); + ix1[2] = (uint8_t) (s3 >> 8); + ix1[3] = (uint8_t) (s0 >> 8); + + ix2[0] = (uint8_t) (s2 >> 16); + ix2[1] = (uint8_t) (s3 >> 16); + ix2[2] = (uint8_t) (s0 >> 16); + ix2[3] = (uint8_t) (s1 >> 16); + + ix3[0] = (uint8_t) (s3 >> 24); + ix3[1] = (uint8_t) (s0 >> 24); + ix3[2] = (uint8_t) (s1 >> 24); + ix3[3] = (uint8_t) (s2 >> 24); + + out.w0 = LUT0[ix0[0]]; + out.w1 = LUT0[ix0[1]]; + out.w2 = LUT0[ix0[2]]; + out.w3 = LUT0[ix0[3]]; + + out.w0 ^= LUT1[ix1[0]]; + out.w1 ^= LUT1[ix1[1]]; + out.w2 ^= LUT1[ix1[2]]; + out.w3 ^= LUT1[ix1[3]]; + + out.w0 ^= LUT2[ix2[0]]; + out.w1 ^= LUT2[ix2[1]]; + out.w2 ^= LUT2[ix2[2]]; + out.w3 ^= LUT2[ix2[3]]; + + out.w0 ^= LUT3[ix3[0]]; + out.w1 ^= LUT3[ix3[1]]; + out.w2 ^= LUT3[ix3[2]]; + out.w3 ^= LUT3[ix3[3]]; + + out.w0 ^= rk.w0; + out.w1 ^= rk.w1; + out.w2 ^= rk.w2; + out.w3 ^= rk.w3; + + return out; +} +#else + +static uint32_t _aes_lut[256] __attribute__((visibility("hidden"))) = { + 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, + 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, + 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, + 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, + 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, + 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, + 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, + 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, + 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, + 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, + 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, + 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, + 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, + 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, + 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, + 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, + 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, + 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, + 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, + 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, + 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, + 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, + 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, + 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, + 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, + 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, + 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, + 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, + 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, + 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, + 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, + 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c +}; + +static const uint32_t* const LUT = _aes_lut; + +static SoftAesBlock +_encrypt(const uint8_t ix0[4], const uint8_t ix1[4], const uint8_t ix2[4], const uint8_t ix3[4]) +{ + CRYPTO_ALIGN(64) uint32_t t[4][4][256 / SOFTAES_STRIDE]; + CRYPTO_ALIGN(64) uint8_t of[4][4]; + CRYPTO_ALIGN(64) SoftAesBlock out; + size_t i; + size_t j; + + for (j = 0; j < 4; j++) { + of[j][0] = ix0[j] % SOFTAES_STRIDE; + of[j][1] = ix1[j] % SOFTAES_STRIDE; + of[j][2] = ix2[j] % SOFTAES_STRIDE; + of[j][3] = ix3[j] % SOFTAES_STRIDE; + } + for (i = 0; i < 256 / SOFTAES_STRIDE; i++) { + for (j = 0; j < 4; j++) { + t[j][0][i] = LUT[(i * SOFTAES_STRIDE) | of[j][0]]; + t[j][1][i] = LUT[(i * SOFTAES_STRIDE) | of[j][1]]; + t[j][2][i] = LUT[(i * SOFTAES_STRIDE) | of[j][2]]; + t[j][3][i] = LUT[(i * SOFTAES_STRIDE) | of[j][3]]; + } + } + +# if defined(__GNUC__) || defined(__clang__) + __asm__ __volatile__("" : : "r"(t) : "memory"); +# endif + + out.w0 = t[0][0][ix0[0] / SOFTAES_STRIDE]; + out.w0 ^= AEGIS_ROTL32(t[0][1][ix1[0] / SOFTAES_STRIDE], 8); + out.w0 ^= AEGIS_ROTL32(t[0][2][ix2[0] / SOFTAES_STRIDE], 16); + out.w0 ^= AEGIS_ROTL32(t[0][3][ix3[0] / SOFTAES_STRIDE], 24); + + out.w1 = t[1][0][ix0[1] / SOFTAES_STRIDE]; + out.w1 ^= AEGIS_ROTL32(t[1][1][ix1[1] / SOFTAES_STRIDE], 8); + out.w1 ^= AEGIS_ROTL32(t[1][2][ix2[1] / SOFTAES_STRIDE], 16); + out.w1 ^= AEGIS_ROTL32(t[1][3][ix3[1] / SOFTAES_STRIDE], 24); + + out.w2 = t[2][0][ix0[2] / SOFTAES_STRIDE]; + out.w2 ^= AEGIS_ROTL32(t[2][1][ix1[2] / SOFTAES_STRIDE], 8); + out.w2 ^= AEGIS_ROTL32(t[2][2][ix2[2] / SOFTAES_STRIDE], 16); + out.w2 ^= AEGIS_ROTL32(t[2][3][ix3[2] / SOFTAES_STRIDE], 24); + + out.w3 = t[3][0][ix0[3] / SOFTAES_STRIDE]; + out.w3 ^= AEGIS_ROTL32(t[3][1][ix1[3] / SOFTAES_STRIDE], 8); + out.w3 ^= AEGIS_ROTL32(t[3][2][ix2[3] / SOFTAES_STRIDE], 16); + out.w3 ^= AEGIS_ROTL32(t[3][3][ix3[3] / SOFTAES_STRIDE], 24); + + return out; +} + +SoftAesBlock +softaes_block_encrypt(const SoftAesBlock block, const SoftAesBlock rk) +{ + CRYPTO_ALIGN(64) SoftAesBlock out; + CRYPTO_ALIGN(64) uint8_t ix0[4], ix1[4], ix2[4], ix3[4]; + const uint32_t s0 = block.w0; + const uint32_t s1 = block.w1; + const uint32_t s2 = block.w2; + const uint32_t s3 = block.w3; + + ix0[0] = (uint8_t) s0; + ix0[1] = (uint8_t) s1; + ix0[2] = (uint8_t) s2; + ix0[3] = (uint8_t) s3; + + ix1[0] = (uint8_t) (s1 >> 8); + ix1[1] = (uint8_t) (s2 >> 8); + ix1[2] = (uint8_t) (s3 >> 8); + ix1[3] = (uint8_t) (s0 >> 8); + + ix2[0] = (uint8_t) (s2 >> 16); + ix2[1] = (uint8_t) (s3 >> 16); + ix2[2] = (uint8_t) (s0 >> 16); + ix2[3] = (uint8_t) (s1 >> 16); + + ix3[0] = (uint8_t) (s3 >> 24); + ix3[1] = (uint8_t) (s0 >> 24); + ix3[2] = (uint8_t) (s1 >> 24); + ix3[3] = (uint8_t) (s2 >> 24); + + out = _encrypt(ix0, ix1, ix2, ix3); + + out.w0 ^= rk.w0; + out.w1 ^= rk.w1; + out.w2 ^= rk.w2; + out.w3 ^= rk.w3; + + return out; +} +#endif +/*** End of #include "common/softaes.c" ***/ + + +#if defined(__GNUC__) +# pragma GCC push_options +#endif + +/* Variants of implementation headers */ +/* #include "aegis128l/implementations.h" */ +/*** Begin of #include "aegis128l/implementations.h" ***/ +/* +** Name: implementations.h +** Purpose: Header for implementation structure of AEGIS-128L +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128L_IMPLEMENTATIONS_H +#define AEGIS128L_IMPLEMENTATIONS_H + +#include +#include + +/* #include "aegis128l.h" */ + + +typedef struct aegis128l_implementation { + int (*encrypt_detached)(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k); + int (*decrypt_detached)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + void (*stream)(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); + void (*encrypt_unauthenticated)(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k); + void (*decrypt_unauthenticated)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k); +#ifndef AEGIS_OMIT_INCREMENTAL + void (*state_init)(aegis128l_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + int (*state_encrypt_update)(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen); + int (*state_encrypt_detached_final)(aegis128l_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); + int (*state_encrypt_final)(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen); + int (*state_decrypt_detached_update)(aegis128l_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen); + int (*state_decrypt_detached_final)(aegis128l_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen); +#endif /* AEGIS_OMIT_INCREMENTAL */ +#ifndef AEGIS_OMIT_MAC_API + void (*state_mac_init)(aegis128l_mac_state *st_, const uint8_t *npub, const uint8_t *k); + int (*state_mac_update)(aegis128l_mac_state *st_, const uint8_t *ad, size_t adlen); + int (*state_mac_final)(aegis128l_mac_state *st_, uint8_t *mac, size_t maclen); + void (*state_mac_reset)(aegis128l_mac_state *st); + void (*state_mac_clone)(aegis128l_mac_state *dst, const aegis128l_mac_state *src); +#endif /* AEGIS_OMIT_MAC_API */ +} aegis128l_implementation; + +#endif /* AEGIS128L_IMPLEMENTATIONS_H */ +/*** End of #include "aegis128l/implementations.h" ***/ + +/* #include "aegis128x2/implementations.h" */ +/*** Begin of #include "aegis128x2/implementations.h" ***/ +/* +** Name: implementations.h +** Purpose: Header for implementation structure of AEGIS-128x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X2_IMPLEMENTATIONS_H +#define AEGIS128X2_IMPLEMENTATIONS_H + +#include +#include + +/* #include "aegis128x2.h" */ + + +typedef struct aegis128x2_implementation { + int (*encrypt_detached)(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k); + int (*decrypt_detached)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + void (*stream)(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); + void (*encrypt_unauthenticated)(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k); + void (*decrypt_unauthenticated)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k); +#ifndef AEGIS_OMIT_INCREMENTAL + void (*state_init)(aegis128x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + int (*state_encrypt_update)(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen); + int (*state_encrypt_detached_final)(aegis128x2_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); + int (*state_encrypt_final)(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen); + int (*state_decrypt_detached_update)(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen); + int (*state_decrypt_detached_final)(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen); +#endif /* AEGIS_OMIT_INCREMENTAL */ +#ifndef AEGIS_OMIT_MAC_API + void (*state_mac_init)(aegis128x2_mac_state *st_, const uint8_t *npub, const uint8_t *k); + int (*state_mac_update)(aegis128x2_mac_state *st_, const uint8_t *ad, size_t adlen); + int (*state_mac_final)(aegis128x2_mac_state *st_, uint8_t *mac, size_t maclen); + void (*state_mac_reset)(aegis128x2_mac_state *st); + void (*state_mac_clone)(aegis128x2_mac_state *dst, const aegis128x2_mac_state *src); +#endif /* AEGIS_OMIT_MAC_API */ +} aegis128x2_implementation; + +#endif /* AEGIS128X2_IMPLEMENTATIONS_H */ +/*** End of #include "aegis128x2/implementations.h" ***/ + +/* #include "aegis128x4/implementations.h" */ +/*** Begin of #include "aegis128x4/implementations.h" ***/ +/* +** Name: implementations.h +** Purpose: Header for implementation structure of AEGIS-128x4 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X4_IMPLEMENTATIONS_H +#define AEGIS128X4_IMPLEMENTATIONS_H + +#include +#include + +/* #include "aegis128x4.h" */ + + +typedef struct aegis128x4_implementation { + int (*encrypt_detached)(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k); + int (*decrypt_detached)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + void (*stream)(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); + void (*encrypt_unauthenticated)(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k); + void (*decrypt_unauthenticated)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k); +#ifndef AEGIS_OMIT_INCREMENTAL + void (*state_init)(aegis128x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + int (*state_encrypt_update)(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen); + int (*state_encrypt_detached_final)(aegis128x4_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); + int (*state_encrypt_final)(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen); + int (*state_decrypt_detached_update)(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen); + int (*state_decrypt_detached_final)(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen); +#endif /* AEGIS_OMIT_INCREMENTAL */ +#ifndef AEGIS_OMIT_MAC_API + void (*state_mac_init)(aegis128x4_mac_state *st_, const uint8_t *npub, const uint8_t *k); + int (*state_mac_update)(aegis128x4_mac_state *st_, const uint8_t *ad, size_t adlen); + int (*state_mac_final)(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen); + void (*state_mac_reset)(aegis128x4_mac_state *st); + void (*state_mac_clone)(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src); +#endif /* AEGIS_OMIT_MAC_API */ +} aegis128x4_implementation; + +#endif /* AEGIS128X4_IMPLEMENTATIONS_H */ +/*** End of #include "aegis128x4/implementations.h" ***/ + +/* #include "aegis256/implementations.h" */ +/*** Begin of #include "aegis256/implementations.h" ***/ +/* +** Name: implementations.h +** Purpose: Header for implementation structure of AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256_IMPLEMENTATIONS_H +#define AEGIS256_IMPLEMENTATIONS_H + +#include +#include + +/* #include "aegis256.h" */ + + +typedef struct aegis256_implementation { + int (*encrypt_detached)(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k); + int (*decrypt_detached)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + void (*stream)(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); + void (*encrypt_unauthenticated)(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k); + void (*decrypt_unauthenticated)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k); +#ifndef AEGIS_OMIT_INCREMENTAL + void (*state_init)(aegis256_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + int (*state_encrypt_update)(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen); + int (*state_encrypt_detached_final)(aegis256_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); + int (*state_encrypt_final)(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen); + int (*state_decrypt_detached_update)(aegis256_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen); + int (*state_decrypt_detached_final)(aegis256_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen); +#endif /* AEGIS_OMIT_INCREMENTAL */ +#ifndef AEGIS_OMIT_MAC_API + void (*state_mac_init)(aegis256_mac_state *st_, const uint8_t *npub, const uint8_t *k); + int (*state_mac_update)(aegis256_mac_state *st_, const uint8_t *ad, size_t adlen); + int (*state_mac_final)(aegis256_mac_state *st_, uint8_t *mac, size_t maclen); + void (*state_mac_reset)(aegis256_mac_state *st); + void (*state_mac_clone)(aegis256_mac_state *dst, const aegis256_mac_state *src); +#endif /* AEGIS_OMIT_MAC_API */ +} aegis256_implementation; + +#endif /* AEGIS256_IMPLEMENTATIONS_H */ +/*** End of #include "aegis256/implementations.h" ***/ + +/* #include "aegis256x2/implementations.h" */ +/*** Begin of #include "aegis256x2/implementations.h" ***/ +/* +** Name: implementations.h +** Purpose: Header for implementation structure of AEGIS-256x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X2_IMPLEMENTATIONS_H +#define AEGIS256X2_IMPLEMENTATIONS_H + +#include +#include + +/* #include "aegis256x2.h" */ + + +typedef struct aegis256x2_implementation { + int (*encrypt_detached)(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k); + int (*decrypt_detached)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + void (*stream)(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); + void (*encrypt_unauthenticated)(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k); + void (*decrypt_unauthenticated)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k); +#ifndef AEGIS_OMIT_INCREMENTAL + void (*state_init)(aegis256x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + int (*state_encrypt_update)(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen); + int (*state_encrypt_detached_final)(aegis256x2_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); + int (*state_encrypt_final)(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen); + int (*state_decrypt_detached_update)(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen); + int (*state_decrypt_detached_final)(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen); +#endif /* AEGIS_OMIT_INCREMENTAL */ +#ifndef AEGIS_OMIT_MAC_API + void (*state_mac_init)(aegis256x2_mac_state *st_, const uint8_t *npub, const uint8_t *k); + int (*state_mac_update)(aegis256x2_mac_state *st_, const uint8_t *ad, size_t adlen); + int (*state_mac_final)(aegis256x2_mac_state *st_, uint8_t *mac, size_t maclen); + void (*state_mac_reset)(aegis256x2_mac_state *st); + void (*state_mac_clone)(aegis256x2_mac_state *dst, const aegis256x2_mac_state *src); +#endif /* AEGIS_OMIT_MAC_API */ +} aegis256x2_implementation; + +#endif /* AEGIS256X2_IMPLEMENTATIONS_H */ +/*** End of #include "aegis256x2/implementations.h" ***/ + +/* #include "aegis256x4/implementations.h" */ +/*** Begin of #include "aegis256x4/implementations.h" ***/ +/* +** Name: implementations.h +** Purpose: Header for implementation structure of AEGIS-256x4 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X4_IMPLEMENTATIONS_H +#define AEGIS256X4_IMPLEMENTATIONS_H + +#include +#include + +/* #include "aegis256x4.h" */ + + +typedef struct aegis256x4_implementation { + int (*encrypt_detached)(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k); + int (*decrypt_detached)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + void (*stream)(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k); + void (*encrypt_unauthenticated)(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k); + void (*decrypt_unauthenticated)(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k); +#ifndef AEGIS_OMIT_INCREMENTAL + void (*state_init)(aegis256x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k); + int (*state_encrypt_update)(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen); + int (*state_encrypt_detached_final)(aegis256x4_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen); + int (*state_encrypt_final)(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen); + int (*state_decrypt_detached_update)(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen); + int (*state_decrypt_detached_final)(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen); +#endif /* AEGIS_OMIT_INCREMENTAL */ +#ifndef AEGIS_OMIT_MAC_API + void (*state_mac_init)(aegis256x4_mac_state *st_, const uint8_t *npub, const uint8_t *k); + int (*state_mac_update)(aegis256x4_mac_state *st_, const uint8_t *ad, size_t adlen); + int (*state_mac_final)(aegis256x4_mac_state *st_, uint8_t *mac, size_t maclen); + void (*state_mac_reset)(aegis256x4_mac_state *st); + void (*state_mac_clone)(aegis256x4_mac_state *dst, const aegis256x4_mac_state *src); +#endif /* AEGIS_OMIT_MAC_API */ +} aegis256x4_implementation; + +#endif /* AEGIS256X4_IMPLEMENTATIONS_H */ +/*** End of #include "aegis256x4/implementations.h" ***/ + + +/* Variants without hardware acceleration */ +/* #include "aegis128l/aegis128l_soft.c" */ +/*** Begin of #include "aegis128l/aegis128l_soft.c" ***/ +/* +** Name: aegis128l_soft.c +** Purpose: Implementation of AEGIS-128L - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + + +/* #include "../common/softaes.h" */ + +/* #include "aegis128l.h" */ + +/* #include "aegis128l_soft.h" */ +/*** Begin of #include "aegis128l_soft.h" ***/ +/* +** Name: aegis128l_soft.h +** Purpose: Header for implementation structure of AEGIS-128L - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128L_SOFT_H +#define AEGIS128L_SOFT_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128l_implementation aegis128l_soft_implementation; + +#endif /* AEGIS128L_SOFT_H */ +/*** End of #include "aegis128l_soft.h" ***/ + + +#define AES_BLOCK_LENGTH 16 + +typedef SoftAesBlock aegis128l_soft_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128l_soft_aes_block_t +#define AEGIS_BLOCKS aegis128l_soft_blocks +#define AEGIS_STATE _aegis128l_soft_state +#define AEGIS_MAC_STATE _aegis128l_soft_mac_state + +#define AEGIS_FUNC_PREFIX aegis128l_soft_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return softaes_block_xor(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return softaes_block_and(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return softaes_block_load(a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + return softaes_block_load64x2(a, b); +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + softaes_block_store(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return softaes_block_encrypt(a, b); +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_ENC(tmp, state[0]); + + state[0] = AEGIS_AES_BLOCK_XOR(state[0], d1); + state[4] = AEGIS_AES_BLOCK_XOR(state[4], d2); +} + +/* #include "aegis128l_common.h" */ +/*** Begin of #include "aegis128l_common.h" ***/ +/* +** Name: aegis128l_common.h +** Purpose: Common implementation for AEGIS-128L +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 32 +#define AEGIS_ALIGNMENT 32 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c0_[AES_BLOCK_LENGTH] = { 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, + 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c1_[AES_BLOCK_LENGTH] = { 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, + 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + k = AEGIS_AES_BLOCK_LOAD(key); + n = AEGIS_AES_BLOCK_LOAD(nonce); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac + 16, tmp); + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128l_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128l_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128l_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128l_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128l_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128l_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac(mac, maclen, st->adlen, maclen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128l_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis128l_mac_state *dst, const aegis128l_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128l_common.h" ***/ + + +AEGIS_API +struct aegis128l_implementation aegis128l_soft_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + +/*** End of #include "aegis128l/aegis128l_soft.c" ***/ + +/* #include "aegis128x2/aegis128x2_soft.c" */ +/*** Begin of #include "aegis128x2/aegis128x2_soft.c" ***/ +/* +** Name: aegis128x2_soft.c +** Purpose: Implementation of AEGIS-128x2 - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + + +/* #include "../common/softaes.h" */ + +/* #include "aegis128x2.h" */ + +/* #include "aegis128x2_soft.h" */ +/*** Begin of #include "aegis128x2_soft.h" ***/ +/* +** Name: aegis128x2_soft.h +** Purpose: Header for implementation structure of AEGIS-128x2 - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X2_SOFT_H +#define AEGIS128X2_SOFT_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128x2_implementation aegis128x2_soft_implementation; + +#endif /* AEGIS128X2_SOFT_H */ +/*** End of #include "aegis128x2_soft.h" ***/ + + +#define AES_BLOCK_LENGTH 32 + +typedef struct { + SoftAesBlock b0; + SoftAesBlock b1; +} aegis128x2_soft_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128x2_soft_aes_block_t +#define AEGIS_BLOCKS aegis128x2_soft_blocks +#define AEGIS_STATE _aegis128x2_soft_state +#define AEGIS_MAC_STATE _aegis128x2_soft_mac_state + +#define AEGIS_FUNC_PREFIX aegis128x2_soft_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_xor(a.b0, b.b0), softaes_block_xor(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_and(a.b0, b.b0), softaes_block_and(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_load(a), softaes_block_load(a + 16) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const SoftAesBlock t = softaes_block_load64x2(a, b); + return (AEGIS_AES_BLOCK_T) { t, t }; +} +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + softaes_block_store(a, b.b0); + softaes_block_store(a + 16, b.b1); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_encrypt(a.b0, b.b0), softaes_block_encrypt(a.b1, b.b1) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_ENC(tmp, state[0]); + + state[0] = AEGIS_AES_BLOCK_XOR(state[0], d1); + state[4] = AEGIS_AES_BLOCK_XOR(state[4], d2); +} + +/* #include "aegis128x2_common.h" */ +/*** Begin of #include "aegis128x2_common.h" ***/ +/* +** Name: aegis128x2_common.h +** Purpose: Common implementation for AEGIS-128x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 64 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, + 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, + 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, + 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, + 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[2 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + k = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + n = AEGIS_AES_BLOCK_LOAD(tmp); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x01; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x01; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[7] = AEGIS_AES_BLOCK_XOR(state[7], context); + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T*state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 16); + memcpy(r + AEGIS_RATE / 2, t + i * 32 + 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + AEGIS_RATE / 2, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128x2_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128x2_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128x2_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); + +} + +static void +AEGIS_state_mac_clone(aegis128x2_mac_state *dst, const aegis128x2_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE*const src_ = + (const AEGIS_MAC_STATE*) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128x2_common.h" ***/ + + +AEGIS_API +struct aegis128x2_implementation aegis128x2_soft_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + +/*** End of #include "aegis128x2/aegis128x2_soft.c" ***/ + +/* #include "aegis128x4/aegis128x4_soft.c" */ +/*** Begin of #include "aegis128x4/aegis128x4_soft.c" ***/ +/* +** Name: aegis128x4_soft.c +** Purpose: Implementation of AEGIS-128x4 - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + + +/* #include "../common/softaes.h" */ + +/* #include "aegis128x4.h" */ + +/* #include "aegis128x4_soft.h" */ +/*** Begin of #include "aegis128x4_soft.h" ***/ +/* +** Name: aegis128x4_soft.h +** Purpose: Header for implementation structure of AEGIS-128x4 - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X4_SOFT_H +#define AEGIS128X4_SOFT_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128x4_implementation aegis128x4_soft_implementation; + +#endif /* AEGIS128X4_SOFT_H */ +/*** End of #include "aegis128x4_soft.h" ***/ + + +#define AES_BLOCK_LENGTH 64 + +typedef struct { + SoftAesBlock b0; + SoftAesBlock b1; + SoftAesBlock b2; + SoftAesBlock b3; +} aegis128x4_soft_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128x4_soft_aes_block_t +#define AEGIS_BLOCKS aegis128x4_soft_blocks +#define AEGIS_STATE _aegis128x4_soft_state +#define AEGIS_MAC_STATE _aegis128x4_soft_mac_state + +#define AEGIS_FUNC_PREFIX aegis128x4_soft_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_xor(a.b0, b.b0), softaes_block_xor(a.b1, b.b1), + softaes_block_xor(a.b2, b.b2), softaes_block_xor(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_and(a.b0, b.b0), softaes_block_and(a.b1, b.b1), + softaes_block_and(a.b2, b.b2), softaes_block_and(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_load(a), softaes_block_load(a + 16), + softaes_block_load(a + 32), softaes_block_load(a + 48) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const SoftAesBlock t = softaes_block_load64x2(a, b); + return (AEGIS_AES_BLOCK_T) { t, t, t, t }; +} +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + softaes_block_store(a, b.b0); + softaes_block_store(a + 16, b.b1); + softaes_block_store(a + 32, b.b2); + softaes_block_store(a + 48, b.b3); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_encrypt(a.b0, b.b0), softaes_block_encrypt(a.b1, b.b1), + softaes_block_encrypt(a.b2, b.b2), softaes_block_encrypt(a.b3, b.b3) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_ENC(tmp, state[0]); + + state[0] = AEGIS_AES_BLOCK_XOR(state[0], d1); + state[4] = AEGIS_AES_BLOCK_XOR(state[4], d2); +} + +/* #include "aegis128x4_common.h" */ +/*** Begin of #include "aegis128x4_common.h" ***/ +/* +** Name: aegis128x4_common.h +** Purpose: Common implementation for AEGIS-128x4 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 128 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n = AEGIS_AES_BLOCK_LOAD(tmp); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[7] = AEGIS_AES_BLOCK_XOR(state[7], context); + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 16); + memcpy(r + AEGIS_RATE / 2, t + i * 32 + 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + AEGIS_RATE / 2, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128x4_common.h" ***/ + + +AEGIS_API +struct aegis128x4_implementation aegis128x4_soft_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + +/*** End of #include "aegis128x4/aegis128x4_soft.c" ***/ + +/* #include "aegis256/aegis256_soft.c" */ +/*** Begin of #include "aegis256/aegis256_soft.c" ***/ +/* +** Name: aegis256_soft.c +** Purpose: Implementation of AEGIS-256 - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + + +/* #include "../common/softaes.h" */ + +/* #include "aegis256.h" */ + +/* #include "aegis256_soft.h" */ +/*** Begin of #include "aegis256_soft.h" ***/ +/* +** Name: aegis256_soft.h +** Purpose: Header for implementation structure of AEGIS-256 - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256_SOFT_H +#define AEGIS256_SOFT_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256_implementation aegis256_soft_implementation; + +#endif /* AEGIS256_SOFT_H */ +/*** End of #include "aegis256_soft.h" ***/ + + +#define AES_BLOCK_LENGTH 16 + +typedef SoftAesBlock aegis256_soft_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256_soft_aes_block_t +#define AEGIS_BLOCKS aegis256_soft_blocks +#define AEGIS_STATE _aegis256_soft_state +#define AEGIS_MAC_STATE _aegis256_soft_mac_state + +#define AEGIS_FUNC_PREFIX aegis256_soft_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return softaes_block_xor(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return softaes_block_and(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return softaes_block_load(a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + return softaes_block_load64x2(a, b); +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + softaes_block_store(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return softaes_block_encrypt(a, b); +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256_common.h" */ +/*** Begin of #include "aegis256_common.h" ***/ +/* +** Name: aegis256_common.h +** Purpose: Common implementation for AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 16 +#define AEGIS_ALIGNMENT 16 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c0_[AES_BLOCK_LENGTH] = { 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, + 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c1_[AES_BLOCK_LENGTH] = { 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, + 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + const AEGIS_AES_BLOCK_T k0 = AEGIS_AES_BLOCK_LOAD(key); + const AEGIS_AES_BLOCK_T k1 = AEGIS_AES_BLOCK_LOAD(key + AES_BLOCK_LENGTH); + const AEGIS_AES_BLOCK_T n0 = AEGIS_AES_BLOCK_LOAD(nonce); + const AEGIS_AES_BLOCK_T n1 = AEGIS_AES_BLOCK_LOAD(nonce + AES_BLOCK_LENGTH); + const AEGIS_AES_BLOCK_T k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + const AEGIS_AES_BLOCK_T k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + int i; + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + AEGIS_update(state, k0); + AEGIS_update(state, k1); + AEGIS_update(state, k0_n0); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(AEGIS_AES_BLOCK_XOR(state[2], state[1]), state[0]); + AEGIS_AES_BLOCK_STORE(mac, tmp); + tmp = AEGIS_AES_BLOCK_XOR(AEGIS_AES_BLOCK_XOR(state[5], state[4]), state[3]); + AEGIS_AES_BLOCK_STORE(mac + 16, tmp); + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memset(st->buf, 0, sizeof st->buf); + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac(mac, maclen, st->adlen, maclen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256_mac_state *dst, const aegis256_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256_common.h" ***/ + + +AEGIS_API +struct aegis256_implementation aegis256_soft_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + +/*** End of #include "aegis256/aegis256_soft.c" ***/ + +/* #include "aegis256x2/aegis256x2_soft.c" */ +/*** Begin of #include "aegis256x2/aegis256x2_soft.c" ***/ +/* +** Name: aegis256x2_soft.c +** Purpose: Implementation of AEGIS-256x2 - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + + +/* #include "../common/softaes.h" */ + +/* #include "aegis256x2.h" */ + +/* #include "aegis256x2_soft.h" */ +/*** Begin of #include "aegis256x2_soft.h" ***/ +/* +** Name: aegis256x2_soft.h +** Purpose: Header for implementation structure of AEGIS-256x2 - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X2_SOFT_H +#define AEGIS256X2_SOFT_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256x2_implementation aegis256x2_soft_implementation; + +#endif /* AEGIS256X2_SOFT_H */ +/*** End of #include "aegis256x2_soft.h" ***/ + + +#define AES_BLOCK_LENGTH 32 + +typedef struct { + SoftAesBlock b0; + SoftAesBlock b1; +} aegis256x2_soft_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256x2_soft_aes_block_t +#define AEGIS_BLOCKS aegis256x2_soft_blocks +#define AEGIS_STATE _aegis256x2_soft_state +#define AEGIS_MAC_STATE _aegis256x2_soft_mac_state + +#define AEGIS_FUNC_PREFIX aegis256x2_soft_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_xor(a.b0, b.b0), softaes_block_xor(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_and(a.b0, b.b0), softaes_block_and(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_load(a), softaes_block_load(a + 16) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const SoftAesBlock t = softaes_block_load64x2(a, b); + return (AEGIS_AES_BLOCK_T) { t, t }; +} +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + softaes_block_store(a, b.b0); + softaes_block_store(a + 16, b.b1); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_encrypt(a.b0, b.b0), softaes_block_encrypt(a.b1, b.b1) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256x2_common.h" */ +/*** Begin of #include "aegis256x2_common.h" ***/ +/* +** Name: aegis256x2_common.h +** Purpose: Common implementation for AEGIS-256x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 32 +#define AEGIS_ALIGNMENT 32 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, + 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, + 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, + 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, + 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[2 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k0, k1; + AEGIS_AES_BLOCK_T n0, n1; + AEGIS_AES_BLOCK_T k0_n0, k1_n1; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + k0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, key + 16, 16); + memcpy(tmp + 16, key + 16, 16); + k1 = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + n0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, nonce + 16, 16); + memcpy(tmp + 16, nonce + 16, 16); + n1 = AEGIS_AES_BLOCK_LOAD(tmp); + + k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x01; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x01; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0_n0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + memcpy(r, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256x2_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256x2_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256x2_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256x2_mac_state *dst, const aegis256x2_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256x2_common.h" ***/ + + +AEGIS_API +struct aegis256x2_implementation aegis256x2_soft_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + +/*** End of #include "aegis256x2/aegis256x2_soft.c" ***/ + +/* #include "aegis256x4/aegis256x4_soft.c" */ +/*** Begin of #include "aegis256x4/aegis256x4_soft.c" ***/ +/* +** Name: aegis256x4_soft.c +** Purpose: Implementation of AEGIS-256x4 - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + + +/* #include "../common/softaes.h" */ + +/* #include "aegis256x4.h" */ + +/* #include "aegis256x4_soft.h" */ +/*** Begin of #include "aegis256x4_soft.h" ***/ +/* +** Name: aegis256x4_soft.h +** Purpose: Header for implementation structure of AEGIS-256x4 - Software +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X4_SOFT_H +#define AEGIS256X4_SOFT_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256x4_implementation aegis256x4_soft_implementation; + +#endif /* AEGIS256X4_SOFT_H */ +/*** End of #include "aegis256x4_soft.h" ***/ + + +#define AES_BLOCK_LENGTH 64 + +typedef struct { + SoftAesBlock b0; + SoftAesBlock b1; + SoftAesBlock b2; + SoftAesBlock b3; +} aegis256x4_soft_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256x4_soft_aes_block_t +#define AEGIS_BLOCKS aegis256x4_soft_blocks +#define AEGIS_STATE _aegis256x4_soft_state +#define AEGIS_MAC_STATE _aegis256x4_soft_mac_state + +#define AEGIS_FUNC_PREFIX aegis256x4_soft_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_xor(a.b0, b.b0), softaes_block_xor(a.b1, b.b1), + softaes_block_xor(a.b2, b.b2), softaes_block_xor(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_and(a.b0, b.b0), softaes_block_and(a.b1, b.b1), + softaes_block_and(a.b2, b.b2), softaes_block_and(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_load(a), softaes_block_load(a + 16), + softaes_block_load(a + 32), softaes_block_load(a + 48) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const SoftAesBlock t = softaes_block_load64x2(a, b); + return (AEGIS_AES_BLOCK_T) { t, t, t, t }; +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + softaes_block_store(a, b.b0); + softaes_block_store(a + 16, b.b1); + softaes_block_store(a + 32, b.b2); + softaes_block_store(a + 48, b.b3); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { softaes_block_encrypt(a.b0, b.b0), softaes_block_encrypt(a.b1, b.b1), + softaes_block_encrypt(a.b2, b.b2), softaes_block_encrypt(a.b3, b.b3) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256x4_common.h" */ +/*** Begin of #include "aegis256x4_common.h" ***/ +/* +** Name: aegis256x4_common.h +** Purpose: Common implementation for AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 64 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k0, k1; + AEGIS_AES_BLOCK_T n0, n1; + AEGIS_AES_BLOCK_T k0_n0, k1_n1; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, key + 16, 16); + memcpy(tmp + 16, key + 16, 16); + memcpy(tmp + 32, key + 16, 16); + memcpy(tmp + 48, key + 16, 16); + k1 = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, nonce + 16, 16); + memcpy(tmp + 16, nonce + 16, 16); + memcpy(tmp + 32, nonce + 16, 16); + memcpy(tmp + 48, nonce + 16, 16); + n1 = AEGIS_AES_BLOCK_LOAD(tmp); + + k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0_n0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + memcpy(r, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256x4_mac_state *dst, const aegis256x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256x4_common.h" ***/ + + +AEGIS_API +struct aegis256x4_implementation aegis256x4_soft_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + +/*** End of #include "aegis256x4/aegis256x4_soft.c" ***/ + + +/* Variants with support for AES and AVX instruction sets */ +/* #include "aegis128l/aegis128l_aesni.c" */ +/*** Begin of #include "aegis128l/aegis128l_aesni.c" ***/ +/* +** Name: aegis128l_aesni.c +** Purpose: Implementation of AEGIS-128L - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128l.h" */ + +/* #include "aegis128l_aesni.h" */ +/*** Begin of #include "aegis128l_aesni.h" ***/ +/* +** Name: aegis128l_aesni.h +** Purpose: Header for implementation structure of AEGIS-128L - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128L_AESNI_H +#define AEGIS128L_AESNI_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128l_implementation aegis128l_aesni_implementation; + +#endif /* AEGIS128L_AESNI_H */ +/*** End of #include "aegis128l_aesni.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("aes,avx"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("aes,avx") +#endif + +#include +#include + +#define AES_BLOCK_LENGTH 16 + +typedef __m128i aegis128l_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128l_aes_block_t +#define AEGIS_BLOCKS aegis128l_blocks +#define AEGIS_STATE _aegis128l_state +#define AEGIS_MAC_STATE _aegis128l_mac_state + +#define AEGIS_FUNC_PREFIX aegis128l_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm_xor_si128(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm_and_si128(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return _mm_loadu_si128((const AEGIS_AES_BLOCK_T *) (const void *) a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + return _mm_set_epi64x((long long) a, (long long) b); +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm_storeu_si128((AEGIS_AES_BLOCK_T *) (void *) a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm_aesenc_si128(a, b); +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_ENC(tmp, state[0]); + + state[0] = AEGIS_AES_BLOCK_XOR(state[0], d1); + state[4] = AEGIS_AES_BLOCK_XOR(state[4], d2); +} + +/* #include "aegis128l_common.h" */ +/*** Begin of #include "aegis128l_common.h" ***/ +/* +** Name: aegis128l_common.h +** Purpose: Common implementation for AEGIS-128L +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 32 +#define AEGIS_ALIGNMENT 32 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c0_[AES_BLOCK_LENGTH] = { 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, + 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c1_[AES_BLOCK_LENGTH] = { 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, + 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + k = AEGIS_AES_BLOCK_LOAD(key); + n = AEGIS_AES_BLOCK_LOAD(nonce); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac + 16, tmp); + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128l_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128l_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128l_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128l_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128l_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128l_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac(mac, maclen, st->adlen, maclen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128l_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis128l_mac_state *dst, const aegis128l_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128l_common.h" ***/ + + +AEGIS_API +struct aegis128l_implementation aegis128l_aesni_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis128l/aegis128l_aesni.c" ***/ + +/* #include "aegis128x2/aegis128x2_aesni.c" */ +/*** Begin of #include "aegis128x2/aegis128x2_aesni.c" ***/ +/* +** Name: aegis128x2_aesni.c +** Purpose: Implementation of AEGIS-128x2 - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128x2.h" */ + +/* #include "aegis128x2_aesni.h" */ +/*** Begin of #include "aegis128x2_aesni.h" ***/ +/* +** Name: aegis128x2_aesni.h +** Purpose: Header for implementation structure of AEGIS-128x2 - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X2_AESNI_H +#define AEGIS128X2_AESNI_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128x2_implementation aegis128x2_aesni_implementation; + +#endif /* AEGIS128X2_AESNI_H */ +/*** End of #include "aegis128x2_aesni.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("aes,avx"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("aes,avx") +#endif + +#include +#include + +#define AES_BLOCK_LENGTH 32 + +typedef struct { + __m128i b0; + __m128i b1; +} aegis128x2_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128x2_aes_block_t +#define AEGIS_BLOCKS aegis128x2_blocks +#define AEGIS_STATE _aegis128x2_state +#define AEGIS_MAC_STATE _aegis128x2_mac_state + +#define AEGIS_FUNC_PREFIX aegis128x2_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_xor_si128(a.b0, b.b0), _mm_xor_si128(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_and_si128(a.b0, b.b0), _mm_and_si128(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { _mm_loadu_si128((const __m128i *) (const void *) a), + _mm_loadu_si128((const __m128i *) (const void *) (a + 16)) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const __m128i t = _mm_set_epi64x((long long) a, (long long) b); + return (AEGIS_AES_BLOCK_T) { t, t }; +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm_storeu_si128((__m128i *) (void *) a, b.b0); + _mm_storeu_si128((__m128i *) (void *) (a + 16), b.b1); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_aesenc_si128(a.b0, b.b0), _mm_aesenc_si128(a.b1, b.b1) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_ENC(tmp, state[0]); + + state[0] = AEGIS_AES_BLOCK_XOR(state[0], d1); + state[4] = AEGIS_AES_BLOCK_XOR(state[4], d2); +} + +/* #include "aegis128x2_common.h" */ +/*** Begin of #include "aegis128x2_common.h" ***/ +/* +** Name: aegis128x2_common.h +** Purpose: Common implementation for AEGIS-128x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 64 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, + 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, + 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, + 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, + 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[2 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + k = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + n = AEGIS_AES_BLOCK_LOAD(tmp); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x01; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x01; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[7] = AEGIS_AES_BLOCK_XOR(state[7], context); + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T*state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 16); + memcpy(r + AEGIS_RATE / 2, t + i * 32 + 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + AEGIS_RATE / 2, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128x2_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128x2_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128x2_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); + +} + +static void +AEGIS_state_mac_clone(aegis128x2_mac_state *dst, const aegis128x2_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE*const src_ = + (const AEGIS_MAC_STATE*) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128x2_common.h" ***/ + + +AEGIS_API +struct aegis128x2_implementation aegis128x2_aesni_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis128x2/aegis128x2_aesni.c" ***/ + +/* #include "aegis128x4/aegis128x4_aesni.c" */ +/*** Begin of #include "aegis128x4/aegis128x4_aesni.c" ***/ +/* +** Name: aegis128x4_aesni.c +** Purpose: Implementation of AEGIS-128x4 - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128x4.h" */ + +/* #include "aegis128x4_aesni.h" */ +/*** Begin of #include "aegis128x4_aesni.h" ***/ +/* +** Name: aegis128x4_aesni.h +** Purpose: Header for implementation structure of AEGIS-128x4 - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X4_AESNI_H +#define AEGIS128X4_AESNI_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128x4_implementation aegis128x4_aesni_implementation; + +#endif /* AEGIS128X4_AESNI_H */ +/*** End of #include "aegis128x4_aesni.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("aes,avx"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("aes,avx") +#endif + +#include +#include + +#define AES_BLOCK_LENGTH 64 + +typedef struct { + __m128i b0; + __m128i b1; + __m128i b2; + __m128i b3; +} aegis128x4_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128x4_aes_block_t +#define AEGIS_BLOCKS aegis128x4_blocks +#define AEGIS_STATE _aegis128x4_state +#define AEGIS_MAC_STATE _aegis128x4_mac_state + +#define AEGIS_FUNC_PREFIX aegis128x4_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_xor_si128(a.b0, b.b0), _mm_xor_si128(a.b1, b.b1), + _mm_xor_si128(a.b2, b.b2), _mm_xor_si128(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_and_si128(a.b0, b.b0), _mm_and_si128(a.b1, b.b1), + _mm_and_si128(a.b2, b.b2), _mm_and_si128(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { _mm_loadu_si128((const __m128i *) (const void *) a), + _mm_loadu_si128((const __m128i *) (const void *) (a + 16)), + _mm_loadu_si128((const __m128i *) (const void *) (a + 32)), + _mm_loadu_si128((const __m128i *) (const void *) (a + 48)) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const __m128i t = _mm_set_epi64x((long long) a, (long long) b); + return (AEGIS_AES_BLOCK_T) { t, t, t, t }; +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm_storeu_si128((__m128i *) (void *) a, b.b0); + _mm_storeu_si128((__m128i *) (void *) (a + 16), b.b1); + _mm_storeu_si128((__m128i *) (void *) (a + 32), b.b2); + _mm_storeu_si128((__m128i *) (void *) (a + 48), b.b3); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_aesenc_si128(a.b0, b.b0), _mm_aesenc_si128(a.b1, b.b1), + _mm_aesenc_si128(a.b2, b.b2), _mm_aesenc_si128(a.b3, b.b3) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_ENC(tmp, state[0]); + + state[0] = AEGIS_AES_BLOCK_XOR(state[0], d1); + state[4] = AEGIS_AES_BLOCK_XOR(state[4], d2); +} + +/* #include "aegis128x4_common.h" */ +/*** Begin of #include "aegis128x4_common.h" ***/ +/* +** Name: aegis128x4_common.h +** Purpose: Common implementation for AEGIS-128x4 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 128 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n = AEGIS_AES_BLOCK_LOAD(tmp); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[7] = AEGIS_AES_BLOCK_XOR(state[7], context); + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 16); + memcpy(r + AEGIS_RATE / 2, t + i * 32 + 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + AEGIS_RATE / 2, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128x4_common.h" ***/ + + +AEGIS_API +struct aegis128x4_implementation aegis128x4_aesni_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis128x4/aegis128x4_aesni.c" ***/ + +/* #include "aegis256/aegis256_aesni.c" */ +/*** Begin of #include "aegis256/aegis256_aesni.c" ***/ +/* +** Name: aegis256_aesni.c +** Purpose: Implementation of AEGIS-256 - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256.h" */ + +/* #include "aegis256_aesni.h" */ +/*** Begin of #include "aegis256_aesni.h" ***/ +/* +** Name: aegis256_aesni.h +** Purpose: Header for implementation structure of AEGIS-256 - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256_AESNI_H +#define AEGIS256_AESNI_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256_implementation aegis256_aesni_implementation; + +#endif /* AEGIS256_AESNI_H */ +/*** End of #include "aegis256_aesni.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("aes,avx"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("aes,avx") +#endif + +#include +#include + +#define AES_BLOCK_LENGTH 16 + +typedef __m128i aegis256_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256_aes_block_t +#define AEGIS_BLOCKS aegis256_blocks +#define AEGIS_STATE _aegis256_state +#define AEGIS_MAC_STATE _aegis256_mac_state + +#define AEGIS_FUNC_PREFIX aegis256_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm_xor_si128(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm_and_si128(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return _mm_loadu_si128((const AEGIS_AES_BLOCK_T *) (const void *) a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + return _mm_set_epi64x((long long) a, (long long) b); +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm_storeu_si128((AEGIS_AES_BLOCK_T *) (void *) a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm_aesenc_si128(a, b); +} + + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256_common.h" */ +/*** Begin of #include "aegis256_common.h" ***/ +/* +** Name: aegis256_common.h +** Purpose: Common implementation for AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 16 +#define AEGIS_ALIGNMENT 16 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c0_[AES_BLOCK_LENGTH] = { 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, + 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c1_[AES_BLOCK_LENGTH] = { 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, + 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + const AEGIS_AES_BLOCK_T k0 = AEGIS_AES_BLOCK_LOAD(key); + const AEGIS_AES_BLOCK_T k1 = AEGIS_AES_BLOCK_LOAD(key + AES_BLOCK_LENGTH); + const AEGIS_AES_BLOCK_T n0 = AEGIS_AES_BLOCK_LOAD(nonce); + const AEGIS_AES_BLOCK_T n1 = AEGIS_AES_BLOCK_LOAD(nonce + AES_BLOCK_LENGTH); + const AEGIS_AES_BLOCK_T k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + const AEGIS_AES_BLOCK_T k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + int i; + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + AEGIS_update(state, k0); + AEGIS_update(state, k1); + AEGIS_update(state, k0_n0); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(AEGIS_AES_BLOCK_XOR(state[2], state[1]), state[0]); + AEGIS_AES_BLOCK_STORE(mac, tmp); + tmp = AEGIS_AES_BLOCK_XOR(AEGIS_AES_BLOCK_XOR(state[5], state[4]), state[3]); + AEGIS_AES_BLOCK_STORE(mac + 16, tmp); + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memset(st->buf, 0, sizeof st->buf); + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac(mac, maclen, st->adlen, maclen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256_mac_state *dst, const aegis256_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256_common.h" ***/ + + +AEGIS_API +struct aegis256_implementation aegis256_aesni_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis256/aegis256_aesni.c" ***/ + +/* #include "aegis256x2/aegis256x2_aesni.c" */ +/*** Begin of #include "aegis256x2/aegis256x2_aesni.c" ***/ +/* +** Name: aegis256x2_aesni.c +** Purpose: Implementation of AEGIS-256x2 - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256x2.h" */ + +/* #include "aegis256x2_aesni.h" */ +/*** Begin of #include "aegis256x2_aesni.h" ***/ +/* +** Name: aegis256x2_aesni.h +** Purpose: Header for implementation structure of AEGIS-256x2 - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X2_AESNI_H +#define AEGIS256X2_AESNI_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256x2_implementation aegis256x2_aesni_implementation; + +#endif /* AEGIS256X2_AESNI_H */ +/*** End of #include "aegis256x2_aesni.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("aes,avx"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("aes,avx") +#endif + +#include +#include + +#define AES_BLOCK_LENGTH 32 + +typedef struct { + __m128i b0; + __m128i b1; +} aegis256x2_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256x2_aes_block_t +#define AEGIS_BLOCKS aegis256x2_blocks +#define AEGIS_STATE _aegis256x2_state +#define AEGIS_MAC_STATE _aegis256x2_mac_state + +#define AEGIS_FUNC_PREFIX aegis256x2_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_xor_si128(a.b0, b.b0), _mm_xor_si128(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_and_si128(a.b0, b.b0), _mm_and_si128(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { _mm_loadu_si128((const __m128i *) (const void *) a), + _mm_loadu_si128((const __m128i *) (const void *) (a + 16)) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const __m128i t = _mm_set_epi64x((long long) a, (long long) b); + return (AEGIS_AES_BLOCK_T) { t, t }; +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm_storeu_si128((__m128i *) (void *) a, b.b0); + _mm_storeu_si128((__m128i *) (void *) (a + 16), b.b1); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_aesenc_si128(a.b0, b.b0), _mm_aesenc_si128(a.b1, b.b1) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256x2_common.h" */ +/*** Begin of #include "aegis256x2_common.h" ***/ +/* +** Name: aegis256x2_common.h +** Purpose: Common implementation for AEGIS-256x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 32 +#define AEGIS_ALIGNMENT 32 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, + 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, + 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, + 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, + 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[2 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k0, k1; + AEGIS_AES_BLOCK_T n0, n1; + AEGIS_AES_BLOCK_T k0_n0, k1_n1; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + k0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, key + 16, 16); + memcpy(tmp + 16, key + 16, 16); + k1 = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + n0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, nonce + 16, 16); + memcpy(tmp + 16, nonce + 16, 16); + n1 = AEGIS_AES_BLOCK_LOAD(tmp); + + k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x01; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x01; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0_n0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + memcpy(r, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256x2_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256x2_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256x2_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256x2_mac_state *dst, const aegis256x2_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256x2_common.h" ***/ + + +AEGIS_API +struct aegis256x2_implementation aegis256x2_aesni_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis256x2/aegis256x2_aesni.c" ***/ + +/* #include "aegis256x4/aegis256x4_aesni.c" */ +/*** Begin of #include "aegis256x4/aegis256x4_aesni.c" ***/ +/* +** Name: aegis256x4_aesni.c +** Purpose: Implementation of AEGIS-256x4 - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256x4.h" */ + +/* #include "aegis256x4_aesni.h" */ +/*** Begin of #include "aegis256x4_aesni.h" ***/ +/* +** Name: aegis256x4_aesni.h +** Purpose: Header for implementation structure of AEGIS-256x4 - AES-NI +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X4_AESNI_H +#define AEGIS256X4_AESNI_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256x4_implementation aegis256x4_aesni_implementation; + +#endif /* AEGIS256X4_AESNI_H */ +/*** End of #include "aegis256x4_aesni.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("aes,avx"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("aes,avx") +#endif + +#include +#include + +#define AES_BLOCK_LENGTH 64 + +typedef struct { + __m128i b0; + __m128i b1; + __m128i b2; + __m128i b3; +} aegis256x4_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256x4_aes_block_t +#define AEGIS_BLOCKS aegis256x4_blocks +#define AEGIS_STATE _aegis256x4_state +#define AEGIS_MAC_STATE _aegis256x4_mac_state + +#define AEGIS_FUNC_PREFIX aegis256x4_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_xor_si128(a.b0, b.b0), _mm_xor_si128(a.b1, b.b1), + _mm_xor_si128(a.b2, b.b2), _mm_xor_si128(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_and_si128(a.b0, b.b0), _mm_and_si128(a.b1, b.b1), + _mm_and_si128(a.b2, b.b2), _mm_and_si128(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { _mm_loadu_si128((const __m128i *) (const void *) a), + _mm_loadu_si128((const __m128i *) (const void *) (a + 16)), + _mm_loadu_si128((const __m128i *) (const void *) (a + 32)), + _mm_loadu_si128((const __m128i *) (const void *) (a + 48)) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const __m128i t = _mm_set_epi64x((long long) a, (long long) b); + return (AEGIS_AES_BLOCK_T) { t, t, t, t }; +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm_storeu_si128((__m128i *) (void *) a, b.b0); + _mm_storeu_si128((__m128i *) (void *) (a + 16), b.b1); + _mm_storeu_si128((__m128i *) (void *) (a + 32), b.b2); + _mm_storeu_si128((__m128i *) (void *) (a + 48), b.b3); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm_aesenc_si128(a.b0, b.b0), _mm_aesenc_si128(a.b1, b.b1), + _mm_aesenc_si128(a.b2, b.b2), _mm_aesenc_si128(a.b3, b.b3) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256x4_common.h" */ +/*** Begin of #include "aegis256x4_common.h" ***/ +/* +** Name: aegis256x4_common.h +** Purpose: Common implementation for AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 64 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k0, k1; + AEGIS_AES_BLOCK_T n0, n1; + AEGIS_AES_BLOCK_T k0_n0, k1_n1; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, key + 16, 16); + memcpy(tmp + 16, key + 16, 16); + memcpy(tmp + 32, key + 16, 16); + memcpy(tmp + 48, key + 16, 16); + k1 = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, nonce + 16, 16); + memcpy(tmp + 16, nonce + 16, 16); + memcpy(tmp + 32, nonce + 16, 16); + memcpy(tmp + 48, nonce + 16, 16); + n1 = AEGIS_AES_BLOCK_LOAD(tmp); + + k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0_n0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + memcpy(r, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256x4_mac_state *dst, const aegis256x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256x4_common.h" ***/ + + +AEGIS_API +struct aegis256x4_implementation aegis256x4_aesni_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis256x4/aegis256x4_aesni.c" ***/ + + +/* Variants with support for VAES and AVX2 instruction sets */ +/* #include "aegis128x2/aegis128x2_avx2.c" */ +/*** Begin of #include "aegis128x2/aegis128x2_avx2.c" ***/ +/* +** Name: aegis128x2_avx2.c +** Purpose: Implementation of AEGIS-128x2 - AES-NI AVX2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128x2.h" */ + +/* #include "aegis128x2_avx2.h" */ +/*** Begin of #include "aegis128x2_avx2.h" ***/ +/* +** Name: aegis128x2_avx2.h +** Purpose: Header for implementation structure of AEGIS-128x2 - AES-NI AVX2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X2_AVX2_H +#define AEGIS128X2_AVX2_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +#ifdef HAVE_VAESINTRIN_H +AEGIS_EXTERN struct aegis128x2_implementation aegis128x2_avx2_implementation; +#endif + +#endif /* AEGIS128X2_AVX2_H */ +/*** End of #include "aegis128x2_avx2.h" ***/ + + +#ifdef HAVE_VAESINTRIN_H + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("vaes,avx2"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("vaes,avx2") +#endif + +#include + +#define AES_BLOCK_LENGTH 32 + +typedef __m256i aegis128x2_avx2_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128x2_avx2_aes_block_t +#define AEGIS_BLOCKS aegis128x2_avx2_blocks +#define AEGIS_STATE _aegis128x2_avx2_state +#define AEGIS_MAC_STATE _aegis128x2_avx2_mac_state + +#define AEGIS_FUNC_PREFIX aegis128x2_avx2_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm256_xor_si256(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm256_and_si256(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return _mm256_loadu_si256((const AEGIS_AES_BLOCK_T *) (const void *) a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + return _mm256_broadcastsi128_si256(_mm_set_epi64x(a, b)); +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm256_storeu_si256((AEGIS_AES_BLOCK_T *) (void *) a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm256_aesenc_epi128(a, b); +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_ENC(tmp, state[0]); + + state[0] = AEGIS_AES_BLOCK_XOR(state[0], d1); + state[4] = AEGIS_AES_BLOCK_XOR(state[4], d2); +} + +/* #include "aegis128x2_common.h" */ +/*** Begin of #include "aegis128x2_common.h" ***/ +/* +** Name: aegis128x2_common.h +** Purpose: Common implementation for AEGIS-128x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 64 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, + 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, + 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, + 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, + 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[2 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + k = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + n = AEGIS_AES_BLOCK_LOAD(tmp); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x01; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x01; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[7] = AEGIS_AES_BLOCK_XOR(state[7], context); + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T*state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 16); + memcpy(r + AEGIS_RATE / 2, t + i * 32 + 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + AEGIS_RATE / 2, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128x2_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128x2_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128x2_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); + +} + +static void +AEGIS_state_mac_clone(aegis128x2_mac_state *dst, const aegis128x2_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE*const src_ = + (const AEGIS_MAC_STATE*) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128x2_common.h" ***/ + + +AEGIS_API +struct aegis128x2_implementation aegis128x2_avx2_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif /* HAVE_VAESINTRIN_H */ + +#endif +#endif +/*** End of #include "aegis128x2/aegis128x2_avx2.c" ***/ + +/* #include "aegis128x4/aegis128x4_avx2.c" */ +/*** Begin of #include "aegis128x4/aegis128x4_avx2.c" ***/ +/* +** Name: aegis128x4_avx2.c +** Purpose: Implementation of AEGIS-128x4 - AES-NI AVX2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128x4.h" */ + +/* #include "aegis128x4_avx2.h" */ +/*** Begin of #include "aegis128x4_avx2.h" ***/ +/* +** Name: aegis128x4_avx2.h +** Purpose: Header for implementation structure of AEGIS-128x4 - AES-NI AVX2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X4_AVX2_H +#define AEGIS128X4_AVX2_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +#ifdef HAVE_VAESINTRIN_H +AEGIS_EXTERN struct aegis128x4_implementation aegis128x4_avx2_implementation; +#endif + +#endif /* AEGIS128X4_AVX2_H */ +/*** End of #include "aegis128x4_avx2.h" ***/ + + +#ifdef HAVE_VAESINTRIN_H + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("vaes,avx2"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("vaes,avx2") +#endif + +#include + +#define AES_BLOCK_LENGTH 64 + +typedef struct { + __m256i b0; + __m256i b1; +} aegis128x4_avx2_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128x4_avx2_aes_block_t +#define AEGIS_BLOCKS aegis128x4_avx2_blocks +#define AEGIS_STATE _aegis128x4_avx2_state +#define AEGIS_MAC_STATE _aegis128x4_avx2_mac_state + +#define AEGIS_FUNC_PREFIX aegis128x4_avx2_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm256_xor_si256(a.b0, b.b0), _mm256_xor_si256(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm256_and_si256(a.b0, b.b0), _mm256_and_si256(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { _mm256_loadu_si256((const __m256i *) (const void *) a), + _mm256_loadu_si256((const __m256i *) (const void *) (a + 32)) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const __m256i t = _mm256_broadcastsi128_si256(_mm_set_epi64x((long long) a, (long long) b)); + return (AEGIS_AES_BLOCK_T) { t, t }; +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm256_storeu_si256((__m256i *) (void *) a, b.b0); + _mm256_storeu_si256((__m256i *) (void *) (a + 32), b.b1); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm256_aesenc_epi128(a.b0, b.b0), _mm256_aesenc_epi128(a.b1, b.b1) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_ENC(tmp, state[0]); + + state[0] = AEGIS_AES_BLOCK_XOR(state[0], d1); + state[4] = AEGIS_AES_BLOCK_XOR(state[4], d2); +} + +/* #include "aegis128x4_common.h" */ +/*** Begin of #include "aegis128x4_common.h" ***/ +/* +** Name: aegis128x4_common.h +** Purpose: Common implementation for AEGIS-128x4 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 128 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n = AEGIS_AES_BLOCK_LOAD(tmp); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[7] = AEGIS_AES_BLOCK_XOR(state[7], context); + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 16); + memcpy(r + AEGIS_RATE / 2, t + i * 32 + 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + AEGIS_RATE / 2, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128x4_common.h" ***/ + + +AEGIS_API +struct aegis128x4_implementation aegis128x4_avx2_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif /* HAVE_VAESINTRIN_H */ + +#endif +#endif +/*** End of #include "aegis128x4/aegis128x4_avx2.c" ***/ + +/* #include "aegis256x2/aegis256x2_avx2.c" */ +/*** Begin of #include "aegis256x2/aegis256x2_avx2.c" ***/ +/* +** Name: aegis256x2_avx2.c +** Purpose: Implementation of AEGIS-256x2 - AES-NI AVX2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256x2.h" */ + +/* #include "aegis256x2_avx2.h" */ +/*** Begin of #include "aegis256x2_avx2.h" ***/ +/* +** Name: aegis256x2_avx2.h +** Purpose: Header for implementation structure of AEGIS-256x2 - AES-NI AVX2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X2_AVX2_H +#define AEGIS256X2_AVX2_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +#ifdef HAVE_VAESINTRIN_H +AEGIS_EXTERN struct aegis256x2_implementation aegis256x2_avx2_implementation; +#endif + +#endif /* AEGIS256X2_AVX2_H */ +/*** End of #include "aegis256x2_avx2.h" ***/ + + +#ifdef HAVE_VAESINTRIN_H + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("vaes,avx2"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("vaes,avx2") +#endif + +#include + +#define AES_BLOCK_LENGTH 32 + +typedef __m256i aegis256x2_avx2_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256x2_avx2_aes_block_t +#define AEGIS_BLOCKS aegis256x2_avx2_blocks +#define AEGIS_STATE _aegis256x2_avx2_state +#define AEGIS_MAC_STATE _aegis256x2_avx2_mac_state + +#define AEGIS_FUNC_PREFIX aegis256x2_avx2_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm256_xor_si256(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm256_and_si256(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return _mm256_loadu_si256((const AEGIS_AES_BLOCK_T *) (const void *) a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + return _mm256_broadcastsi128_si256(_mm_set_epi64x(a, b)); +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm256_storeu_si256((AEGIS_AES_BLOCK_T *) (void *) a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm256_aesenc_epi128(a, b); +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256x2_common.h" */ +/*** Begin of #include "aegis256x2_common.h" ***/ +/* +** Name: aegis256x2_common.h +** Purpose: Common implementation for AEGIS-256x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 32 +#define AEGIS_ALIGNMENT 32 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, + 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, + 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, + 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, + 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[2 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k0, k1; + AEGIS_AES_BLOCK_T n0, n1; + AEGIS_AES_BLOCK_T k0_n0, k1_n1; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + k0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, key + 16, 16); + memcpy(tmp + 16, key + 16, 16); + k1 = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + n0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, nonce + 16, 16); + memcpy(tmp + 16, nonce + 16, 16); + n1 = AEGIS_AES_BLOCK_LOAD(tmp); + + k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x01; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x01; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0_n0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + memcpy(r, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256x2_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256x2_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256x2_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256x2_mac_state *dst, const aegis256x2_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256x2_common.h" ***/ + + +AEGIS_API +struct aegis256x2_implementation aegis256x2_avx2_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif /* HAVE_VAESINTRIN_H */ + +#endif +#endif +/*** End of #include "aegis256x2/aegis256x2_avx2.c" ***/ + +/* #include "aegis256x4/aegis256x4_avx2.c" */ +/*** Begin of #include "aegis256x4/aegis256x4_avx2.c" ***/ +/* +** Name: aegis256x4_avx2.c +** Purpose: Implementation of AEGIS-256x4 - AES-NI AVX2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256x4.h" */ + +/* #include "aegis256x4_avx2.h" */ +/*** Begin of #include "aegis256x4_avx2.h" ***/ +/* +** Name: aegis256x4_avx2.h +** Purpose: Header for implementation structure of AEGIS-256x4 - AES-NI AVX2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X4_AVX2_H +#define AEGIS256X4_AVX2_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +#ifdef HAVE_VAESINTRIN_H +AEGIS_EXTERN struct aegis256x4_implementation aegis256x4_avx2_implementation; +#endif + +#endif /* AEGIS256X4_AVX2_H */ +/*** End of #include "aegis256x4_avx2.h" ***/ + + +#ifdef HAVE_VAESINTRIN_H + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("vaes,avx2"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("vaes,avx2") +#endif + +#include + +#define AES_BLOCK_LENGTH 64 + +typedef struct { + __m256i b0; + __m256i b1; +} aegis256_avx2_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256_avx2_aes_block_t +#define AEGIS_BLOCKS aegis256x4_avx2_blocks +#define AEGIS_STATE _aegis256x4_avx2_state +#define AEGIS_MAC_STATE _aegis256x4_avx2_mac_state + +#define AEGIS_FUNC_PREFIX aegis256x4_avx2_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm256_xor_si256(a.b0, b.b0), _mm256_xor_si256(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm256_and_si256(a.b0, b.b0), _mm256_and_si256(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { _mm256_loadu_si256((const __m256i *) (const void *) a), + _mm256_loadu_si256((const __m256i *) (const void *) (a + 32)) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const __m256i t = _mm256_broadcastsi128_si256(_mm_set_epi64x((long long) a, (long long) b)); + return (AEGIS_AES_BLOCK_T) { t, t }; +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm256_storeu_si256((__m256i *) (void *) a, b.b0); + _mm256_storeu_si256((__m256i *) (void *) (a + 32), b.b1); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { _mm256_aesenc_epi128(a.b0, b.b0), _mm256_aesenc_epi128(a.b1, b.b1) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256x4_common.h" */ +/*** Begin of #include "aegis256x4_common.h" ***/ +/* +** Name: aegis256x4_common.h +** Purpose: Common implementation for AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 64 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k0, k1; + AEGIS_AES_BLOCK_T n0, n1; + AEGIS_AES_BLOCK_T k0_n0, k1_n1; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, key + 16, 16); + memcpy(tmp + 16, key + 16, 16); + memcpy(tmp + 32, key + 16, 16); + memcpy(tmp + 48, key + 16, 16); + k1 = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, nonce + 16, 16); + memcpy(tmp + 16, nonce + 16, 16); + memcpy(tmp + 32, nonce + 16, 16); + memcpy(tmp + 48, nonce + 16, 16); + n1 = AEGIS_AES_BLOCK_LOAD(tmp); + + k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0_n0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + memcpy(r, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256x4_mac_state *dst, const aegis256x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256x4_common.h" ***/ + + +AEGIS_API +struct aegis256x4_implementation aegis256x4_avx2_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif /* HAVE_VAESINTRIN_H */ + +#endif +#endif +/*** End of #include "aegis256x4/aegis256x4_avx2.c" ***/ + + +/* Variants with support for AVX512F instruction sets */ +/* #include "aegis128x4/aegis128x4_avx512.c" */ +/*** Begin of #include "aegis128x4/aegis128x4_avx512.c" ***/ +/* +** Name: aegis128x4_avx512.c +** Purpose: Implementation of AEGIS-128x4 - AES-NI AVX512 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128x4.h" */ + +/* #include "aegis128x4_avx512.h" */ +/*** Begin of #include "aegis128x4_avx512.h" ***/ +/* +** Name: aegis128x4_avx512.h +** Purpose: Header for implementation structure of AEGIS-128x4 - AES-NI AVX512 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X4_AVX512_H +#define AEGIS128X4_AVX512_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +#ifdef HAVE_VAESINTRIN_H +AEGIS_EXTERN struct aegis128x4_implementation aegis128x4_avx512_implementation; +#endif + +#endif /* AEGIS128X4_AVX512_H */ +/*** End of #include "aegis128x4_avx512.h" ***/ + + +#ifdef HAVE_VAESINTRIN_H + +#ifdef __clang__ +# if __clang_major__ >= 18 && __clang_major__ < 22 +# pragma clang attribute push(__attribute__((target("aes,vaes,avx512f,evex512"))), apply_to=function) +# else +# pragma clang attribute push(__attribute__((target("aes,vaes,avx512f"))), apply_to=function) +# endif +#elif defined(__GNUC__) +# pragma GCC target("vaes,avx512f") +#endif + +#include + +#define AES_BLOCK_LENGTH 64 + +typedef __m512i aegis128x4_avx512_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128x4_avx512_aes_block_t +#define AEGIS_BLOCKS aegis128x4_avx512_blocks +#define AEGIS_STATE _aegis128x4_avx512_state +#define AEGIS_MAC_STATE _aegis128x4_avx512_mac_state + +#define AEGIS_FUNC_PREFIX aegis128x4_avx512_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm512_xor_si512(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm512_and_si512(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return _mm512_loadu_si512((const AEGIS_AES_BLOCK_T *) (const void *) a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ +#if defined(_MSC_VER) && (_MSC_VER >= 1910 && _MSC_VER < 1920) + /* + ** Visual Studio 2017 produces an internal compiler error in release mode + ** for the function call _mm512_broadcast_i32x4(_mm_set_epi64x(a, b)). + ** Therefore perform the operation "manually". + */ + __m128i x128 = _mm_set_epi64x(a, b); + __m256i x256 = _mm256_broadcastsi128_si256(x128); + __m512i x512 = _mm512_castsi256_si512(x256); + x512 = _mm512_inserti64x4(x512, x256, 1); + return x512; +#else + return _mm512_broadcast_i32x4(_mm_set_epi64x(a, b)); +#endif +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm512_storeu_si512((AEGIS_AES_BLOCK_T *) (void *) a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm512_aesenc_epi128(a, b); +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_ENC(tmp, state[0]); + + state[0] = AEGIS_AES_BLOCK_XOR(state[0], d1); + state[4] = AEGIS_AES_BLOCK_XOR(state[4], d2); +} + +/* #include "aegis128x4_common.h" */ +/*** Begin of #include "aegis128x4_common.h" ***/ +/* +** Name: aegis128x4_common.h +** Purpose: Common implementation for AEGIS-128x4 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 128 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n = AEGIS_AES_BLOCK_LOAD(tmp); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[7] = AEGIS_AES_BLOCK_XOR(state[7], context); + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 16); + memcpy(r + AEGIS_RATE / 2, t + i * 32 + 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + AEGIS_RATE / 2, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128x4_common.h" ***/ + + +AEGIS_API +struct aegis128x4_implementation aegis128x4_avx512_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif /* HAVE_VAESINTRIN_H */ + +#endif +#endif +/*** End of #include "aegis128x4/aegis128x4_avx512.c" ***/ + +/* #include "aegis256x4/aegis256x4_avx512.c" */ +/*** Begin of #include "aegis256x4/aegis256x4_avx512.c" ***/ +/* +** Name: aegis256x4_avx512.c +** Purpose: Implementation of AEGIS-256x4 - AES-NI AVX512 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_AMD64) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256x4.h" */ + +/* #include "aegis256x4_avx512.h" */ +/*** Begin of #include "aegis256x4_avx512.h" ***/ +/* +** Name: aegis256x4_avx512.h +** Purpose: Header for implementation structure of AEGIS-256x4 - AES-NI AVX512 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X4_AVX512_H +#define AEGIS256X4_AVX512_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +#ifdef HAVE_VAESINTRIN_H +AEGIS_EXTERN struct aegis256x4_implementation aegis256x4_avx512_implementation; +#endif + +#endif /* AEGIS256X4_AVX512_H */ +/*** End of #include "aegis256x4_avx512.h" ***/ + + +#ifdef HAVE_VAESINTRIN_H + +#ifdef __clang__ +# if __clang_major__ >= 18 && __clang_major__ < 22 +# pragma clang attribute push(__attribute__((target("vaes,avx512f,evex512"))), apply_to=function) +# else +# pragma clang attribute push(__attribute__((target("vaes,avx512f"))), apply_to=function) +# endif +#elif defined(__GNUC__) +# pragma GCC target("vaes,avx512f") +#endif + +#include + +#define AES_BLOCK_LENGTH 64 + +typedef __m512i aegis256_avx512_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256_avx512_aes_block_t +#define AEGIS_BLOCKS aegis256x4_avx512_blocks +#define AEGIS_STATE _aegis256x4_avx512_state +#define AEGIS_MAC_STATE _aegis256x4_avx512_mac_state + +#define AEGIS_FUNC_PREFIX aegis256_avx512_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm512_xor_si512(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm512_and_si512(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return _mm512_loadu_si512((const AEGIS_AES_BLOCK_T *) (const void *) a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ +#if defined(_MSC_VER) && (_MSC_VER >= 1910 && _MSC_VER < 1920) + /* + ** Visual Studio 2017 produces an internal compiler error in release mode + ** for the function call _mm512_broadcast_i32x4(_mm_set_epi64x(a, b)). + ** Therefore perform the operation "manually". + */ + __m128i x128 = _mm_set_epi64x(a, b); + __m256i x256 = _mm256_broadcastsi128_si256(x128); + __m512i x512 = _mm512_castsi256_si512(x256); + x512 = _mm512_inserti64x4(x512, x256, 1); + return x512; +#else + return _mm512_broadcast_i32x4(_mm_set_epi64x(a, b)); +#endif +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + _mm512_storeu_si512((AEGIS_AES_BLOCK_T *) (void *) a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return _mm512_aesenc_epi128(a, b); +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256x4_common.h" */ +/*** Begin of #include "aegis256x4_common.h" ***/ +/* +** Name: aegis256x4_common.h +** Purpose: Common implementation for AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 64 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k0, k1; + AEGIS_AES_BLOCK_T n0, n1; + AEGIS_AES_BLOCK_T k0_n0, k1_n1; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, key + 16, 16); + memcpy(tmp + 16, key + 16, 16); + memcpy(tmp + 32, key + 16, 16); + memcpy(tmp + 48, key + 16, 16); + k1 = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, nonce + 16, 16); + memcpy(tmp + 16, nonce + 16, 16); + memcpy(tmp + 32, nonce + 16, 16); + memcpy(tmp + 48, nonce + 16, 16); + n1 = AEGIS_AES_BLOCK_LOAD(tmp); + + k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0_n0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + memcpy(r, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256x4_mac_state *dst, const aegis256x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256x4_common.h" ***/ + + +AEGIS_API +struct aegis256x4_implementation aegis256x4_avx512_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif /* HAVE_VAESINTRIN_H */ + +#endif +#endif +/*** End of #include "aegis256x4/aegis256x4_avx512.c" ***/ + + +/* Variants with support for AltiVec instruction sets */ +/* #include "aegis128l/aegis128l_altivec.c" */ +/*** Begin of #include "aegis128l/aegis128l_altivec.c" ***/ +/* +** Name: aegis128l_altivec.c +** Purpose: Implementation of AEGIS-128L - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +#if defined(__ALTIVEC__) && defined(__CRYPTO__) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128l.h" */ + +/* #include "aegis128l_altivec.h" */ +/*** Begin of #include "aegis128l_altivec.h" ***/ +/* +** Name: aegis128l_altivec.h +** Purpose: Header for implementation structure of AEGIS-128L - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128L_ALTIVEC_H +#define AEGIS128L_ALTIVEC_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128l_implementation aegis128l_altivec_implementation; + +#endif /* AEGIS128L_ALTIVEC_H */ +/*** End of #include "aegis128l_altivec.h" ***/ + + +#include + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("altivec,crypto"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("altivec,crypto") +#endif + +#define AES_BLOCK_LENGTH 16 + +typedef vector unsigned char aegis128l_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128l_aes_block_t +#define AEGIS_BLOCKS aegis128l_blocks +#define AEGIS_STATE _aegis128l_state +#define AEGIS_MAC_STATE _aegis128l_mac_state + +#define AEGIS_FUNC_PREFIX aegis128l_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return vec_xor(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return vec_and(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return vec_xl_be(0, (const unsigned char *) a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + return (AEGIS_AES_BLOCK_T) vec_revb(vec_insert(a, vec_promote((unsigned long long) b, 1), 0)); +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vec_xst_be(b, 0, (unsigned char *) a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) vec_cipher_be(a, b); +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(state[3], state[4]), d2); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d1); +} + +/* #include "aegis128l_common.h" */ +/*** Begin of #include "aegis128l_common.h" ***/ +/* +** Name: aegis128l_common.h +** Purpose: Common implementation for AEGIS-128L +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 32 +#define AEGIS_ALIGNMENT 32 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c0_[AES_BLOCK_LENGTH] = { 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, + 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c1_[AES_BLOCK_LENGTH] = { 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, + 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + k = AEGIS_AES_BLOCK_LOAD(key); + n = AEGIS_AES_BLOCK_LOAD(nonce); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac + 16, tmp); + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128l_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128l_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128l_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128l_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128l_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128l_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac(mac, maclen, st->adlen, maclen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128l_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis128l_mac_state *dst, const aegis128l_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128l_common.h" ***/ + + +AEGIS_API +struct aegis128l_implementation aegis128l_altivec_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis128l/aegis128l_altivec.c" ***/ + +/* #include "aegis128x2/aegis128x2_altivec.c" */ +/*** Begin of #include "aegis128x2/aegis128x2_altivec.c" ***/ +/* +** Name: aegis128x2_altivec.c +** Purpose: Implementation of AEGIS-128x2 - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +#if defined(__ALTIVEC__) && defined(__CRYPTO__) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128x2.h" */ + +/* #include "aegis128x2_altivec.h" */ +/*** Begin of #include "aegis128x2_altivec.h" ***/ +/* +** Name: aegis128x2_altivec.h +** Purpose: Header for implementation structure of AEGIS-128x2 - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X2_ALTIVEC_H +#define AEGIS128X2_ALTIVEC_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128x2_implementation aegis128x2_altivec_implementation; + +#endif /* AEGIS128X2_ALTIVEC_H */ +/*** End of #include "aegis128x2_altivec.h" ***/ + + +#include + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("altivec,crypto"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("altivec,crypto") +#endif + +#define AES_BLOCK_LENGTH 32 + +typedef struct { + vector unsigned char b0; + vector unsigned char b1; +} aegis128x2_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128x2_aes_block_t +#define AEGIS_BLOCKS aegis128x2_blocks +#define AEGIS_STATE _aegis128x2_state +#define AEGIS_MAC_STATE _aegis128x2_mac_state + +#define AEGIS_FUNC_PREFIX aegis128x2_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_xor(a.b0, b.b0), vec_xor(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_and(a.b0, b.b0), vec_and(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { vec_xl_be(0, a), vec_xl_be(0, a + 16) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const vector unsigned char t = + (vector unsigned char) vec_revb(vec_insert(a, vec_promote((unsigned long long) (b), 1), 0)); + return (AEGIS_AES_BLOCK_T) { t, t }; +} +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vec_xst_be(b.b0, 0, a); + vec_xst_be(b.b1, 0, a + 16); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_cipher_be(a.b0, b.b0), vec_cipher_be(a.b1, b.b1) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(state[3], state[4]), d2); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d1); +} + +/* #include "aegis128x2_common.h" */ +/*** Begin of #include "aegis128x2_common.h" ***/ +/* +** Name: aegis128x2_common.h +** Purpose: Common implementation for AEGIS-128x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 64 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, + 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, + 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, + 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, + 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[2 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + k = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + n = AEGIS_AES_BLOCK_LOAD(tmp); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x01; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x01; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[7] = AEGIS_AES_BLOCK_XOR(state[7], context); + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T*state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 16); + memcpy(r + AEGIS_RATE / 2, t + i * 32 + 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + AEGIS_RATE / 2, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128x2_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128x2_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128x2_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); + +} + +static void +AEGIS_state_mac_clone(aegis128x2_mac_state *dst, const aegis128x2_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE*const src_ = + (const AEGIS_MAC_STATE*) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128x2_common.h" ***/ + + +AEGIS_API +struct aegis128x2_implementation aegis128x2_altivec_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis128x2/aegis128x2_altivec.c" ***/ + +/* #include "aegis128x4/aegis128x4_altivec.c" */ +/*** Begin of #include "aegis128x4/aegis128x4_altivec.c" ***/ +/* +** Name: aegis128x4_altivec.c +** Purpose: Implementation of AEGIS-128x4 - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +#if defined(__ALTIVEC__) && defined(__CRYPTO__) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128x4.h" */ + +/* #include "aegis128x4_altivec.h" */ +/*** Begin of #include "aegis128x4_altivec.h" ***/ +/* +** Name: aegis128x4_altivec.h +** Purpose: Header for implementation structure of AEGIS-128x4 - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X4_ALTIVEC_H +#define AEGIS128X4_ALTIVEC_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128x4_implementation aegis128x4_altivec_implementation; + +#endif /* AEGIS128X4_ALTIVEC_H */ +/*** End of #include "aegis128x4_altivec.h" ***/ + + +#include + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("altivec,crypto"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("altivec,crypto") +#endif + +#define AES_BLOCK_LENGTH 64 + +typedef struct { + vector unsigned char b0; + vector unsigned char b1; + vector unsigned char b2; + vector unsigned char b3; +} aegis128x4_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128x4_aes_block_t +#define AEGIS_BLOCKS aegis128x4_blocks +#define AEGIS_STATE _aegis128x4_state +#define AEGIS_MAC_STATE _aegis128x4_mac_state + +#define AEGIS_FUNC_PREFIX aegis128x4_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_xor(a.b0, b.b0), vec_xor(a.b1, b.b1), + vec_xor(a.b2, b.b2), vec_xor(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_and(a.b0, b.b0), vec_and(a.b1, b.b1), + vec_and(a.b2, b.b2), vec_and(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { vec_xl_be(0, a), vec_xl_be(0, a + 16), + vec_xl_be(0, a + 32), vec_xl_be(0, a + 48) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const vector unsigned char t = + (vector unsigned char) vec_revb(vec_insert(a, vec_promote((unsigned long long) (b), 1), 0)); + return (AEGIS_AES_BLOCK_T) { t, t, t, t }; +} +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vec_xst_be(b.b0, 0, a); + vec_xst_be(b.b1, 0, a + 16); + vec_xst_be(b.b2, 0, a + 32); + vec_xst_be(b.b3, 0, a + 48); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_cipher_be(a.b0, b.b0), vec_cipher_be(a.b1, b.b1), + vec_cipher_be(a.b2, b.b2), vec_cipher_be(a.b3, b.b3) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(state[3], state[4]), d2); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d1); +} + +/* #include "aegis128x4_common.h" */ +/*** Begin of #include "aegis128x4_common.h" ***/ +/* +** Name: aegis128x4_common.h +** Purpose: Common implementation for AEGIS-128x4 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 128 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n = AEGIS_AES_BLOCK_LOAD(tmp); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[7] = AEGIS_AES_BLOCK_XOR(state[7], context); + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 16); + memcpy(r + AEGIS_RATE / 2, t + i * 32 + 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + AEGIS_RATE / 2, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128x4_common.h" ***/ + + +AEGIS_API +struct aegis128x4_implementation aegis128x4_altivec_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis128x4/aegis128x4_altivec.c" ***/ + +/* #include "aegis256/aegis256_altivec.c" */ +/*** Begin of #include "aegis256/aegis256_altivec.c" ***/ +/* +** Name: aegis256_altivec.c +** Purpose: Implementation of AEGIS-256 - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +#if defined(__ALTIVEC__) && defined(__CRYPTO__) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256.h" */ + +/* #include "aegis256_altivec.h" */ +/*** Begin of #include "aegis256_altivec.h" ***/ +/* +** Name: aegis256_altivec.h +** Purpose: Header for implementation structure of AEGIS-256 - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256_ALTIVEC_H +#define AEGIS256_ALTIVEC_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256_implementation aegis256_altivec_implementation; + +#endif /* AEGIS256_ALTIVEC_H */ +/*** End of #include "aegis256_altivec.h" ***/ + + +#include + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("altivec,crypto"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("altivec,crypto") +#endif + +#define AES_BLOCK_LENGTH 16 + +typedef vector unsigned char aegis256_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256_aes_block_t +#define AEGIS_BLOCKS aegis256_blocks +#define AEGIS_STATE _aegis256_state +#define AEGIS_MAC_STATE _aegis256_mac_state + +#define AEGIS_FUNC_PREFIX aegis256_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return vec_xor(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return vec_and(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return vec_xl_be(0, (const unsigned char *) a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + return (AEGIS_AES_BLOCK_T) vec_revb(vec_insert(a, vec_promote((unsigned long long) b, 1), 0)); +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vec_xst_be(b, 0, (unsigned char *) a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) vec_cipher_be(a, b); +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256_common.h" */ +/*** Begin of #include "aegis256_common.h" ***/ +/* +** Name: aegis256_common.h +** Purpose: Common implementation for AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 16 +#define AEGIS_ALIGNMENT 16 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c0_[AES_BLOCK_LENGTH] = { 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, + 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c1_[AES_BLOCK_LENGTH] = { 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, + 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + const AEGIS_AES_BLOCK_T k0 = AEGIS_AES_BLOCK_LOAD(key); + const AEGIS_AES_BLOCK_T k1 = AEGIS_AES_BLOCK_LOAD(key + AES_BLOCK_LENGTH); + const AEGIS_AES_BLOCK_T n0 = AEGIS_AES_BLOCK_LOAD(nonce); + const AEGIS_AES_BLOCK_T n1 = AEGIS_AES_BLOCK_LOAD(nonce + AES_BLOCK_LENGTH); + const AEGIS_AES_BLOCK_T k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + const AEGIS_AES_BLOCK_T k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + int i; + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + AEGIS_update(state, k0); + AEGIS_update(state, k1); + AEGIS_update(state, k0_n0); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(AEGIS_AES_BLOCK_XOR(state[2], state[1]), state[0]); + AEGIS_AES_BLOCK_STORE(mac, tmp); + tmp = AEGIS_AES_BLOCK_XOR(AEGIS_AES_BLOCK_XOR(state[5], state[4]), state[3]); + AEGIS_AES_BLOCK_STORE(mac + 16, tmp); + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memset(st->buf, 0, sizeof st->buf); + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac(mac, maclen, st->adlen, maclen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256_mac_state *dst, const aegis256_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256_common.h" ***/ + + +AEGIS_API +struct aegis256_implementation aegis256_altivec_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis256/aegis256_altivec.c" ***/ + +/* #include "aegis256x2/aegis256x2_altivec.c" */ +/*** Begin of #include "aegis256x2/aegis256x2_altivec.c" ***/ +/* +** Name: aegis256x2_altivec.c +** Purpose: Implementation of AEGIS-256x2 - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +#if defined(__ALTIVEC__) && defined(__CRYPTO__) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256x2.h" */ + +/* #include "aegis256x2_altivec.h" */ +/*** Begin of #include "aegis256x2_altivec.h" ***/ +/* +** Name: aegis256x2_altivec.h +** Purpose: Header for implementation structure of AEGIS-256x2 - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X2_ALTIVEC_H +#define AEGIS256X2_ALTIVEC_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256x2_implementation aegis256x2_altivec_implementation; + +#endif /* AEGIS256X2_ALTIVEC_H */ +/*** End of #include "aegis256x2_altivec.h" ***/ + + +#include + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("altivec,crypto"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("altivec,crypto") +#endif + +#define AES_BLOCK_LENGTH 32 + +typedef struct { + vector unsigned char b0; + vector unsigned char b1; +} aegis256x2_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256x2_aes_block_t +#define AEGIS_BLOCKS aegis256x2_blocks +#define AEGIS_STATE _aegis256x2_state +#define AEGIS_MAC_STATE _aegis256x2_mac_state + +#define AEGIS_FUNC_PREFIX aegis256x2_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_xor(a.b0, b.b0), vec_xor(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_and(a.b0, b.b0), vec_and(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { vec_xl_be(0, a), vec_xl_be(0, a + 16) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const vector unsigned char t = + (vector unsigned char) vec_revb(vec_insert(a, vec_promote((unsigned long long) (b), 1), 0)); + return (AEGIS_AES_BLOCK_T) { t, t }; +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vec_xst_be(b.b0, 0, a); + vec_xst_be(b.b1, 0, a + 16); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_cipher_be(a.b0, b.b0), vec_cipher_be(a.b1, b.b1) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256x2_common.h" */ +/*** Begin of #include "aegis256x2_common.h" ***/ +/* +** Name: aegis256x2_common.h +** Purpose: Common implementation for AEGIS-256x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 32 +#define AEGIS_ALIGNMENT 32 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, + 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, + 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, + 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, + 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[2 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k0, k1; + AEGIS_AES_BLOCK_T n0, n1; + AEGIS_AES_BLOCK_T k0_n0, k1_n1; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + k0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, key + 16, 16); + memcpy(tmp + 16, key + 16, 16); + k1 = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + n0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, nonce + 16, 16); + memcpy(tmp + 16, nonce + 16, 16); + n1 = AEGIS_AES_BLOCK_LOAD(tmp); + + k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x01; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x01; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0_n0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + memcpy(r, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256x2_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256x2_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256x2_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256x2_mac_state *dst, const aegis256x2_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256x2_common.h" ***/ + + +AEGIS_API +struct aegis256x2_implementation aegis256x2_altivec_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis256x2/aegis256x2_altivec.c" ***/ + +/* #include "aegis256x4/aegis256x4_altivec.c" */ +/*** Begin of #include "aegis256x4/aegis256x4_altivec.c" ***/ +/* +** Name: aegis256x4_altivec.c +** Purpose: Implementation of AEGIS-256x4 - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +#if defined(__ALTIVEC__) && defined(__CRYPTO__) + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256x4.h" */ + +/* #include "aegis256x4_altivec.h" */ +/*** Begin of #include "aegis256x4_altivec.h" ***/ +/* +** Name: aegis256x4_altivec.h +** Purpose: Header for implementation structure of AEGIS-256x4 - AltiVec +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X4_ALTIVEC_H +#define AEGIS256X4_ALTIVEC_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256x4_implementation aegis256x4_altivec_implementation; + +#endif /* AEGIS256X4_ALTIVEC_H */ +/*** End of #include "aegis256x4_altivec.h" ***/ + + +#include + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("altivec,crypto"))), apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("altivec,crypto") +#endif + +#define AES_BLOCK_LENGTH 64 + +typedef struct { + vector unsigned char b0; + vector unsigned char b1; + vector unsigned char b2; + vector unsigned char b3; +} aegis256x4_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256x4_aes_block_t +#define AEGIS_BLOCKS aegis256x4_blocks +#define AEGIS_STATE _aegis256x4_state +#define AEGIS_MAC_STATE _aegis256x4_mac_state + +#define AEGIS_FUNC_PREFIX aegis256x4_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_xor(a.b0, b.b0), vec_xor(a.b1, b.b1), vec_xor(a.b2, b.b2), + vec_xor(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_and(a.b0, b.b0), vec_and(a.b1, b.b1), vec_and(a.b2, b.b2), + vec_and(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { vec_xl_be(0, a), vec_xl_be(0, a + 16), vec_xl_be(0, a + 32), + vec_xl_be(0, a + 48) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const vector unsigned char t = + (vector unsigned char) vec_revb(vec_insert(a, vec_promote((unsigned long long) (b), 1), 0)); + return (AEGIS_AES_BLOCK_T) { t, t, t, t }; +} +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vec_xst_be(b.b0, 0, a); + vec_xst_be(b.b1, 0, a + 16); + vec_xst_be(b.b2, 0, a + 32); + vec_xst_be(b.b3, 0, a + 48); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vec_cipher_be(a.b0, b.b0), vec_cipher_be(a.b1, b.b1), + vec_cipher_be(a.b2, b.b2), vec_cipher_be(a.b3, b.b3) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256x4_common.h" */ +/*** Begin of #include "aegis256x4_common.h" ***/ +/* +** Name: aegis256x4_common.h +** Purpose: Common implementation for AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 64 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k0, k1; + AEGIS_AES_BLOCK_T n0, n1; + AEGIS_AES_BLOCK_T k0_n0, k1_n1; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, key + 16, 16); + memcpy(tmp + 16, key + 16, 16); + memcpy(tmp + 32, key + 16, 16); + memcpy(tmp + 48, key + 16, 16); + k1 = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, nonce + 16, 16); + memcpy(tmp + 16, nonce + 16, 16); + memcpy(tmp + 32, nonce + 16, 16); + memcpy(tmp + 48, nonce + 16, 16); + n1 = AEGIS_AES_BLOCK_LOAD(tmp); + + k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0_n0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + memcpy(r, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256x4_mac_state *dst, const aegis256x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256x4_common.h" ***/ + + +AEGIS_API +struct aegis256x4_implementation aegis256x4_altivec_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +#endif +/*** End of #include "aegis256x4/aegis256x4_altivec.c" ***/ + + +/* Variants with support for ARM Neon instruction sets */ +/* #include "aegis128l/aegis128l_armcrypto.c" */ +/*** Begin of #include "aegis128l/aegis128l_armcrypto.c" ***/ +/* +** Name: aegis128l_armcrypto.c +** Purpose: Implementation of AEGIS-128L - ARM-Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128l.h" */ + +/* #include "aegis128l_armcrypto.h" */ +/*** Begin of #include "aegis128l_armcrypto.h" ***/ +/* +** Name: aegis128l_armcrypto.h +** Purpose: Header for implementation structure of AEGIS-128L - ARM Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128L_ARMCRYPTO_H +#define AEGIS128L_ARMCRYPTO_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128l_implementation aegis128l_armcrypto_implementation; + +#endif /* AEGIS128L_ARMCRYPTO_H */ +/*** End of #include "aegis128l_armcrypto.h" ***/ + + +#ifndef __ARM_FEATURE_CRYPTO +# define __ARM_FEATURE_CRYPTO 1 +#endif +#ifndef __ARM_FEATURE_AES +# define __ARM_FEATURE_AES 1 +#endif + +#ifdef USE_ARM64_NEON_H +#include +#else +#include +#endif + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), \ + apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("+simd+crypto") +#endif + +#define AES_BLOCK_LENGTH 16 + +typedef uint8x16_t aegis128l_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128l_aes_block_t +#define AEGIS_BLOCKS aegis128l_blocks +#define AEGIS_STATE _aegis128l_state +#define AEGIS_MAC_STATE _aegis128l_mac_state + +#define AEGIS_FUNC_PREFIX aegis128l_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return veorq_u8(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return vandq_u8(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return vld1q_u8(a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + return vreinterpretq_u8_u64(vsetq_lane_u64(a, vmovq_n_u64(b), 1)); +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vst1q_u8(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return veorq_u8(vaesmcq_u8(vaeseq_u8(a, vmovq_n_u8(0))), b); +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(state[3], state[4]), d2); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d1); +} + +/* #include "aegis128l_common.h" */ +/*** Begin of #include "aegis128l_common.h" ***/ +/* +** Name: aegis128l_common.h +** Purpose: Common implementation for AEGIS-128L +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 32 +#define AEGIS_ALIGNMENT 32 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c0_[AES_BLOCK_LENGTH] = { 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, + 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c1_[AES_BLOCK_LENGTH] = { 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, + 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + k = AEGIS_AES_BLOCK_LOAD(key); + n = AEGIS_AES_BLOCK_LOAD(nonce); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac + 16, tmp); + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128l_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128l_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128l_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128l_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128l_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128l_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac(mac, maclen, st->adlen, maclen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128l_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis128l_mac_state *dst, const aegis128l_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128l_common.h" ***/ + + +AEGIS_API +struct aegis128l_implementation aegis128l_armcrypto_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +/*** End of #include "aegis128l/aegis128l_armcrypto.c" ***/ + +/* #include "aegis128x2/aegis128x2_armcrypto.c" */ +/*** Begin of #include "aegis128x2/aegis128x2_armcrypto.c" ***/ +/* +** Name: aegis128x2_armcrypto.c +** Purpose: Implementation of AEGIS-128x2 - ARM-Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128x2.h" */ + +/* #include "aegis128x2_armcrypto.h" */ +/*** Begin of #include "aegis128x2_armcrypto.h" ***/ +/* +** Name: aegis128x2_armcrypto.h +** Purpose: Header for implementation structure of AEGIS-128x2 - ARM Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X2_ARMCRYPTO_H +#define AEGIS128X2_ARMCRYPTO_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128x2_implementation aegis128x2_armcrypto_implementation; + +#endif /* AEGIS128X2_ARMCRYPTO_H */ +/*** End of #include "aegis128x2_armcrypto.h" ***/ + + +#ifndef __ARM_FEATURE_CRYPTO +# define __ARM_FEATURE_CRYPTO 1 +#endif +#ifndef __ARM_FEATURE_AES +# define __ARM_FEATURE_AES 1 +#endif + +#ifdef USE_ARM64_NEON_H +#include +#else +#include +#endif + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), \ + apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("+simd+crypto") +#endif + +#define AES_BLOCK_LENGTH 32 + +typedef struct { + uint8x16_t b0; + uint8x16_t b1; +} aegis128x2_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128x2_aes_block_t +#define AEGIS_BLOCKS aegis128x2_blocks +#define AEGIS_STATE _aegis128x2_state +#define AEGIS_MAC_STATE _aegis128x2_mac_state + +#define AEGIS_FUNC_PREFIX aegis128x2_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { veorq_u8(a.b0, b.b0), veorq_u8(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vandq_u8(a.b0, b.b0), vandq_u8(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { vld1q_u8(a), vld1q_u8(a + 16) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const uint8x16_t t = vreinterpretq_u8_u64(vsetq_lane_u64((a), vmovq_n_u64(b), 1)); + return (AEGIS_AES_BLOCK_T) { t, t }; +} +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vst1q_u8(a, b.b0); + vst1q_u8(a + 16, b.b1); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { veorq_u8(vaesmcq_u8(vaeseq_u8((a.b0), vmovq_n_u8(0))), (b.b0)), + veorq_u8(vaesmcq_u8(vaeseq_u8((a.b1), vmovq_n_u8(0))), (b.b1)) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(state[3], state[4]), d2); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d1); +} + +/* #include "aegis128x2_common.h" */ +/*** Begin of #include "aegis128x2_common.h" ***/ +/* +** Name: aegis128x2_common.h +** Purpose: Common implementation for AEGIS-128x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 64 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, + 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, + 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, + 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, + 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[2 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + k = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + n = AEGIS_AES_BLOCK_LOAD(tmp); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x01; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x01; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[7] = AEGIS_AES_BLOCK_XOR(state[7], context); + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T*state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 16); + memcpy(r + AEGIS_RATE / 2, t + i * 32 + 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + AEGIS_RATE / 2, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128x2_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128x2_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128x2_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); + +} + +static void +AEGIS_state_mac_clone(aegis128x2_mac_state *dst, const aegis128x2_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE*const src_ = + (const AEGIS_MAC_STATE*) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128x2_common.h" ***/ + + +AEGIS_API +struct aegis128x2_implementation aegis128x2_armcrypto_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +/*** End of #include "aegis128x2/aegis128x2_armcrypto.c" ***/ + +/* #include "aegis128x4/aegis128x4_armcrypto.c" */ +/*** Begin of #include "aegis128x4/aegis128x4_armcrypto.c" ***/ +/* +** Name: aegis128x4_armcrypto.c +** Purpose: Implementation of AEGIS-128x4 - ARM-Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis128x4.h" */ + +/* #include "aegis128x4_armcrypto.h" */ +/*** Begin of #include "aegis128x4_armcrypto.h" ***/ +/* +** Name: aegis128x4_armcrypto.h +** Purpose: Header for implementation structure of AEGIS-128x4 - ARM Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128X4_ARMCRYPTO_H +#define AEGIS128X4_ARMCRYPTO_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis128x4_implementation aegis128x4_armcrypto_implementation; + +#endif /* AEGIS128X4_ARMCRYPTO_H */ +/*** End of #include "aegis128x4_armcrypto.h" ***/ + + +#ifndef __ARM_FEATURE_CRYPTO +# define __ARM_FEATURE_CRYPTO 1 +#endif +#ifndef __ARM_FEATURE_AES +# define __ARM_FEATURE_AES 1 +#endif + +#ifdef USE_ARM64_NEON_H +#include +#else +#include +#endif + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), \ + apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("+simd+crypto") +#endif + +#define AES_BLOCK_LENGTH 64 + +typedef struct { + uint8x16_t b0; + uint8x16_t b1; + uint8x16_t b2; + uint8x16_t b3; +} aegis128x4_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis128x4_aes_block_t +#define AEGIS_BLOCKS aegis128x4_blocks +#define AEGIS_STATE _aegis128x4_state +#define AEGIS_MAC_STATE _aegis128x4_mac_state + +#define AEGIS_FUNC_PREFIX aegis128x4_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { veorq_u8(a.b0, b.b0), veorq_u8(a.b1, b.b1), veorq_u8(a.b2, b.b2), + veorq_u8(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vandq_u8(a.b0, b.b0), vandq_u8(a.b1, b.b1), vandq_u8(a.b2, b.b2), + vandq_u8(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { vld1q_u8(a), vld1q_u8(a + 16), vld1q_u8(a + 32), vld1q_u8(a + 48) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const uint8x16_t t = vreinterpretq_u8_u64(vsetq_lane_u64((a), vmovq_n_u64(b), 1)); + return (AEGIS_AES_BLOCK_T) { t, t, t, t }; +} +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vst1q_u8(a, b.b0); + vst1q_u8(a + 16, b.b1); + vst1q_u8(a + 32, b.b2); + vst1q_u8(a + 48, b.b3); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { veorq_u8(vaesmcq_u8(vaeseq_u8((a.b0), vmovq_n_u8(0))), (b.b0)), + veorq_u8(vaesmcq_u8(vaeseq_u8((a.b1), vmovq_n_u8(0))), (b.b1)), + veorq_u8(vaesmcq_u8(vaeseq_u8((a.b2), vmovq_n_u8(0))), (b.b2)), + veorq_u8(vaesmcq_u8(vaeseq_u8((a.b3), vmovq_n_u8(0))), (b.b3)) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d1, const AEGIS_AES_BLOCK_T d2) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[7]; + state[7] = AEGIS_AES_ENC(state[6], state[7]); + state[6] = AEGIS_AES_ENC(state[5], state[6]); + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(state[3], state[4]), d2); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d1); +} + +/* #include "aegis128x4_common.h" */ +/*** Begin of #include "aegis128x4_common.h" ***/ +/* +** Name: aegis128x4_common.h +** Purpose: Common implementation for AEGIS-128x4 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 128 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[8]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k; + AEGIS_AES_BLOCK_T n; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n = AEGIS_AES_BLOCK_LOAD(tmp); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = AEGIS_AES_BLOCK_XOR(k, n); + state[1] = c1; + state[2] = c0; + state[3] = c1; + state[4] = AEGIS_AES_BLOCK_XOR(k, n); + state[5] = AEGIS_AES_BLOCK_XOR(k, c0); + state[6] = AEGIS_AES_BLOCK_XOR(k, c1); + state[7] = AEGIS_AES_BLOCK_XOR(k, c0); + for (i = 0; i < 10; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[7] = AEGIS_AES_BLOCK_XOR(state[7], context); + AEGIS_update(state, n, k); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + AEGIS_AES_BLOCK_T tmp0, tmp1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + tmp0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, state[1]); + tmp1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, state[2]); + tmp0 = AEGIS_AES_BLOCK_XOR(tmp0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + tmp1 = AEGIS_AES_BLOCK_XOR(tmp1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, tmp0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(src); + msg1 = AEGIS_AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(dst, msg0); + AEGIS_AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, msg1); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg0, msg1; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[6]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, state[1]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[5]); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, state[2]); + msg0 = AEGIS_AES_BLOCK_XOR(msg0, AEGIS_AES_BLOCK_AND(state[2], state[3])); + msg1 = AEGIS_AES_BLOCK_XOR(msg1, AEGIS_AES_BLOCK_AND(state[6], state[7])); + AEGIS_AES_BLOCK_STORE(pad, msg0); + AEGIS_AES_BLOCK_STORE(pad + AES_BLOCK_LENGTH, msg1); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg0 = AEGIS_AES_BLOCK_LOAD(pad); + msg1 = AEGIS_AES_BLOCK_LOAD(pad + AES_BLOCK_LENGTH); + + AEGIS_update(state, msg0, msg1); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 16); + memcpy(r + AEGIS_RATE / 2, t + i * 32 + 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[6], AEGIS_AES_BLOCK_XOR(state[5], state[4])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + AEGIS_RATE / 2, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[3], state[2]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[7], state[6]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[5], state[4])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis128x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis128x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis128x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1, msg2, msg3; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + msg2 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 2); + msg3 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 3); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 4 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0, msg1); + AEGIS_update(blocks, msg2, msg3); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis128x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis128x4_common.h" ***/ + + +AEGIS_API +struct aegis128x4_implementation aegis128x4_armcrypto_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +/*** End of #include "aegis128x4/aegis128x4_armcrypto.c" ***/ + +/* #include "aegis256/aegis256_armcrypto.c" */ +/*** Begin of #include "aegis256/aegis256_armcrypto.c" ***/ +/* +** Name: aegis256_armcrypto.c +** Purpose: Implementation of AEGIS-256 - ARM-Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256.h" */ + +/* #include "aegis256_armcrypto.h" */ +/*** Begin of #include "aegis256_armcrypto.h" ***/ +/* +** Name: aegis256_armcrypto.h +** Purpose: Header for implementation structure of AEGIS-256 - ARM Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256_ARMCRYPTO_H +#define AEGIS256_ARMCRYPTO_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256_implementation aegis256_armcrypto_implementation; + +#endif /* AEGIS256_ARMCRYPTO_H */ +/*** End of #include "aegis256_armcrypto.h" ***/ + + +#ifndef __ARM_FEATURE_CRYPTO +# define __ARM_FEATURE_CRYPTO 1 +#endif +#ifndef __ARM_FEATURE_AES +# define __ARM_FEATURE_AES 1 +#endif + +#ifdef USE_ARM64_NEON_H +#include +#else +#include +#endif + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), \ + apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("+simd+crypto") +#endif + +#define AES_BLOCK_LENGTH 16 + +typedef uint8x16_t aegis256_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256_aes_block_t +#define AEGIS_BLOCKS aegis256_blocks +#define AEGIS_STATE _aegis256_state +#define AEGIS_MAC_STATE _aegis256_mac_state + +#define AEGIS_FUNC_PREFIX aegis256_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return veorq_u8(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return vandq_u8(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return vld1q_u8(a); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + return vreinterpretq_u8_u64(vsetq_lane_u64(a, vmovq_n_u64(b), 1)); +} + +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vst1q_u8(a, b); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return veorq_u8(vaesmcq_u8(vaeseq_u8(a, vmovq_n_u8(0))), b); +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256_common.h" */ +/*** Begin of #include "aegis256_common.h" ***/ +/* +** Name: aegis256_common.h +** Purpose: Common implementation for AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 16 +#define AEGIS_ALIGNMENT 16 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c0_[AES_BLOCK_LENGTH] = { 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, + 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) + const uint8_t c1_[AES_BLOCK_LENGTH] = { 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, + 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + const AEGIS_AES_BLOCK_T k0 = AEGIS_AES_BLOCK_LOAD(key); + const AEGIS_AES_BLOCK_T k1 = AEGIS_AES_BLOCK_LOAD(key + AES_BLOCK_LENGTH); + const AEGIS_AES_BLOCK_T n0 = AEGIS_AES_BLOCK_LOAD(nonce); + const AEGIS_AES_BLOCK_T n1 = AEGIS_AES_BLOCK_LOAD(nonce + AES_BLOCK_LENGTH); + const AEGIS_AES_BLOCK_T k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + const AEGIS_AES_BLOCK_T k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + int i; + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + AEGIS_update(state, k0); + AEGIS_update(state, k1); + AEGIS_update(state, k0_n0); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac, tmp); + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(AEGIS_AES_BLOCK_XOR(state[2], state[1]), state[0]); + AEGIS_AES_BLOCK_STORE(mac, tmp); + tmp = AEGIS_AES_BLOCK_XOR(AEGIS_AES_BLOCK_XOR(state[5], state[4]), state[3]); + AEGIS_AES_BLOCK_STORE(mac + 16, tmp); + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memset(st->buf, 0, sizeof st->buf); + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac(mac, maclen, st->adlen, maclen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256_mac_state *dst, const aegis256_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256_common.h" ***/ + + +AEGIS_API +struct aegis256_implementation aegis256_armcrypto_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +/*** End of #include "aegis256/aegis256_armcrypto.c" ***/ + +/* #include "aegis256x2/aegis256x2_armcrypto.c" */ +/*** Begin of #include "aegis256x2/aegis256x2_armcrypto.c" ***/ +/* +** Name: aegis256x2_armcrypto.c +** Purpose: Implementation of AEGIS-256x2 - ARM-Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256x2.h" */ + +/* #include "aegis256x2_armcrypto.h" */ +/*** Begin of #include "aegis256x2_armcrypto.h" ***/ +/* +** Name: aegis256x2_armcrypto.h +** Purpose: Header for implementation structure of AEGIS-256x2 - ARM Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X2_ARMCRYPTO_H +#define AEGIS256X2_ARMCRYPTO_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256x2_implementation aegis256x2_armcrypto_implementation; + +#endif /* AEGIS256X2_ARMCRYPTO_H */ +/*** End of #include "aegis256x2_armcrypto.h" ***/ + + +#ifndef __ARM_FEATURE_CRYPTO +# define __ARM_FEATURE_CRYPTO 1 +#endif +#ifndef __ARM_FEATURE_AES +# define __ARM_FEATURE_AES 1 +#endif + +#ifdef USE_ARM64_NEON_H +#include +#else +#include +#endif + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), \ + apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("+simd+crypto") +#endif + +#define AES_BLOCK_LENGTH 32 + +typedef struct { + uint8x16_t b0; + uint8x16_t b1; +} aegis256x2_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256x2_aes_block_t +#define AEGIS_BLOCKS aegis256x2_blocks +#define AEGIS_STATE _aegis256x2_state +#define AEGIS_MAC_STATE _aegis256x2_mac_state + +#define AEGIS_FUNC_PREFIX aegis256x2_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { veorq_u8(a.b0, b.b0), veorq_u8(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vandq_u8(a.b0, b.b0), vandq_u8(a.b1, b.b1) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { vld1q_u8(a), vld1q_u8(a + 16) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const uint8x16_t t = vreinterpretq_u8_u64(vsetq_lane_u64((a), vmovq_n_u64(b), 1)); + return (AEGIS_AES_BLOCK_T) { t, t }; +} +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vst1q_u8(a, b.b0); + vst1q_u8(a + 16, b.b1); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { veorq_u8(vaesmcq_u8(vaeseq_u8((a.b0), vmovq_n_u8(0))), (b.b0)), + veorq_u8(vaesmcq_u8(vaeseq_u8((a.b1), vmovq_n_u8(0))), (b.b1)) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256x2_common.h" */ +/*** Begin of #include "aegis256x2_common.h" ***/ +/* +** Name: aegis256x2_common.h +** Purpose: Common implementation for AEGIS-256x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 32 +#define AEGIS_ALIGNMENT 32 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, + 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, + 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, + 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, + 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[2 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k0, k1; + AEGIS_AES_BLOCK_T n0, n1; + AEGIS_AES_BLOCK_T k0_n0, k1_n1; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + k0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, key + 16, 16); + memcpy(tmp + 16, key + 16, 16); + k1 = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + n0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, nonce + 16, 16); + memcpy(tmp + 16, nonce + 16, 16); + n1 = AEGIS_AES_BLOCK_LOAD(tmp); + + k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x01; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x01; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0_n0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + memcpy(r, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256x2_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256x2_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256x2_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256x2_mac_state *dst, const aegis256x2_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256x2_common.h" ***/ + + +AEGIS_API +struct aegis256x2_implementation aegis256x2_armcrypto_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +/*** End of #include "aegis256x2/aegis256x2_armcrypto.c" ***/ + +/* #include "aegis256x4/aegis256x4_armcrypto.c" */ +/*** Begin of #include "aegis256x4/aegis256x4_armcrypto.c" ***/ +/* +** Name: aegis256x4_armcrypto.c +** Purpose: Implementation of AEGIS-256x4 - ARM-Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* #include "../common/aeshardware.h" */ + + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "aegis256x4.h" */ + +/* #include "aegis256x4_armcrypto.h" */ +/*** Begin of #include "aegis256x4_armcrypto.h" ***/ +/* +** Name: aegis256x4_armcrypto.h +** Purpose: Header for implementation structure of AEGIS-256x4 - ARM Crypto +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS256X4_ARMCRYPTO_H +#define AEGIS256X4_ARMCRYPTO_H + +/* #include "../common/common.h" */ + +/* #include "implementations.h" */ + + +AEGIS_EXTERN struct aegis256x4_implementation aegis256x4_armcrypto_implementation; + +#endif /* AEGIS256X4_ARMCRYPTO_H */ +/*** End of #include "aegis256x4_armcrypto.h" ***/ + + +#ifndef __ARM_FEATURE_CRYPTO +# define __ARM_FEATURE_CRYPTO 1 +#endif +#ifndef __ARM_FEATURE_AES +# define __ARM_FEATURE_AES 1 +#endif + +#ifdef USE_ARM64_NEON_H +#include +#else +#include +#endif + +#ifdef __clang__ +# pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), \ + apply_to = function) +#elif defined(__GNUC__) +# pragma GCC target("+simd+crypto") +#endif + +#define AES_BLOCK_LENGTH 64 + +typedef struct { + uint8x16_t b0; + uint8x16_t b1; + uint8x16_t b2; + uint8x16_t b3; +} aegis256x4_aes_block_t; + +#define AEGIS_AES_BLOCK_T aegis256x4_aes_block_t +#define AEGIS_BLOCKS aegis256x4_blocks +#define AEGIS_STATE _aegis256x4_state +#define AEGIS_MAC_STATE _aegis256x4_mac_state + +#define AEGIS_FUNC_PREFIX aegis256x4_impl + +/* #include "../common/func_names_define.h" */ +/*** Begin of #include "../common/func_names_define.h" ***/ +/* +** Name: func_names_define.h +** Purpose: Defines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +#define AEGIS_AES_BLOCK_XOR AEGIS_FUNC(aes_block_xor) +#define AEGIS_AES_BLOCK_AND AEGIS_FUNC(aes_block_and) +#define AEGIS_AES_BLOCK_LOAD AEGIS_FUNC(aes_block_load) +#define AEGIS_AES_BLOCK_LOAD_64x2 AEGIS_FUNC(aes_block_load_64x2) +#define AEGIS_AES_BLOCK_STORE AEGIS_FUNC(aes_block_store) +#define AEGIS_AES_ENC AEGIS_FUNC(aes_enc) +#define AEGIS_update AEGIS_FUNC(update) +#define AEGIS_encrypt_detached AEGIS_FUNC(encrypt_detached) +#define AEGIS_decrypt_detached AEGIS_FUNC(decrypt_detached) +#define AEGIS_encrypt_unauthenticated AEGIS_FUNC(encrypt_unauthenticated) +#define AEGIS_decrypt_unauthenticated AEGIS_FUNC(decrypt_unauthenticated) +#define AEGIS_stream AEGIS_FUNC(stream) +#define AEGIS_state_init AEGIS_FUNC(state_init) +#define AEGIS_state_encrypt_update AEGIS_FUNC(state_encrypt_update) +#define AEGIS_state_encrypt_detached_final AEGIS_FUNC(state_encrypt_detached_final) +#define AEGIS_state_encrypt_final AEGIS_FUNC(state_encrypt_final) +#define AEGIS_state_decrypt_detached_update AEGIS_FUNC(state_decrypt_detached_update) +#define AEGIS_state_decrypt_detached_final AEGIS_FUNC(state_decrypt_detached_final) +#define AEGIS_state_mac_init AEGIS_FUNC(state_mac_init) +#define AEGIS_state_mac_update AEGIS_FUNC(state_mac_update) +#define AEGIS_state_mac_final AEGIS_FUNC(state_mac_final) +#define AEGIS_state_mac_reset AEGIS_FUNC(state_mac_reset) +#define AEGIS_state_mac_clone AEGIS_FUNC(state_mac_clone) +/*** End of #include "../common/func_names_define.h" ***/ + + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_XOR(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { veorq_u8(a.b0, b.b0), veorq_u8(a.b1, b.b1), veorq_u8(a.b2, b.b2), + veorq_u8(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_AND(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { vandq_u8(a.b0, b.b0), vandq_u8(a.b1, b.b1), vandq_u8(a.b2, b.b2), + vandq_u8(a.b3, b.b3) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD(const uint8_t *a) +{ + return (AEGIS_AES_BLOCK_T) { vld1q_u8(a), vld1q_u8(a + 16), vld1q_u8(a + 32), vld1q_u8(a + 48) }; +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_BLOCK_LOAD_64x2(uint64_t a, uint64_t b) +{ + const uint8x16_t t = vreinterpretq_u8_u64(vsetq_lane_u64((a), vmovq_n_u64(b), 1)); + return (AEGIS_AES_BLOCK_T) { t, t, t, t }; +} +static inline void +AEGIS_AES_BLOCK_STORE(uint8_t *a, const AEGIS_AES_BLOCK_T b) +{ + vst1q_u8(a, b.b0); + vst1q_u8(a + 16, b.b1); + vst1q_u8(a + 32, b.b2); + vst1q_u8(a + 48, b.b3); +} + +static inline AEGIS_AES_BLOCK_T +AEGIS_AES_ENC(const AEGIS_AES_BLOCK_T a, const AEGIS_AES_BLOCK_T b) +{ + return (AEGIS_AES_BLOCK_T) { veorq_u8(vaesmcq_u8(vaeseq_u8((a.b0), vmovq_n_u8(0))), (b.b0)), + veorq_u8(vaesmcq_u8(vaeseq_u8((a.b1), vmovq_n_u8(0))), (b.b1)), + veorq_u8(vaesmcq_u8(vaeseq_u8((a.b2), vmovq_n_u8(0))), (b.b2)), + veorq_u8(vaesmcq_u8(vaeseq_u8((a.b3), vmovq_n_u8(0))), (b.b3)) }; +} + +static inline void +AEGIS_update(AEGIS_AES_BLOCK_T *const state, const AEGIS_AES_BLOCK_T d) +{ + AEGIS_AES_BLOCK_T tmp; + + tmp = state[5]; + state[5] = AEGIS_AES_ENC(state[4], state[5]); + state[4] = AEGIS_AES_ENC(state[3], state[4]); + state[3] = AEGIS_AES_ENC(state[2], state[3]); + state[2] = AEGIS_AES_ENC(state[1], state[2]); + state[1] = AEGIS_AES_ENC(state[0], state[1]); + state[0] = AEGIS_AES_BLOCK_XOR(AEGIS_AES_ENC(tmp, state[0]), d); +} + +/* #include "aegis256x4_common.h" */ +/*** Begin of #include "aegis256x4_common.h" ***/ +/* +** Name: aegis256x4_common.h +** Purpose: Common implementation for AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#define AEGIS_RATE 64 +#define AEGIS_ALIGNMENT 64 + +typedef AEGIS_AES_BLOCK_T AEGIS_BLOCKS[6]; + +#define AEGIS_init AEGIS_FUNC(init) +#define AEGIS_mac AEGIS_FUNC(mac) +#define AEGIS_mac_nr AEGIS_FUNC(mac_nr) +#define AEGIS_absorb AEGIS_FUNC(absorb) +#define AEGIS_enc AEGIS_FUNC(enc) +#define AEGIS_dec AEGIS_FUNC(dec) +#define AEGIS_declast AEGIS_FUNC(declast) + +static void +AEGIS_init(const uint8_t *key, const uint8_t *nonce, AEGIS_AES_BLOCK_T *const state) +{ + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c0_[AES_BLOCK_LENGTH] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, + 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, + 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0x00, 0x01, 0x01, 0x02, + 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, + }; + static CRYPTO_ALIGN(AES_BLOCK_LENGTH) const uint8_t c1_[AES_BLOCK_LENGTH] = { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, + 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, + 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, + 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, 0xdb, 0x3d, 0x18, 0x55, + 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, + }; + + const AEGIS_AES_BLOCK_T c0 = AEGIS_AES_BLOCK_LOAD(c0_); + const AEGIS_AES_BLOCK_T c1 = AEGIS_AES_BLOCK_LOAD(c1_); + uint8_t tmp[4 * 16]; + uint8_t context_bytes[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T context; + AEGIS_AES_BLOCK_T k0, k1; + AEGIS_AES_BLOCK_T n0, n1; + AEGIS_AES_BLOCK_T k0_n0, k1_n1; + int i; + + memcpy(tmp, key, 16); + memcpy(tmp + 16, key, 16); + memcpy(tmp + 32, key, 16); + memcpy(tmp + 48, key, 16); + k0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, key + 16, 16); + memcpy(tmp + 16, key + 16, 16); + memcpy(tmp + 32, key + 16, 16); + memcpy(tmp + 48, key + 16, 16); + k1 = AEGIS_AES_BLOCK_LOAD(tmp); + + memcpy(tmp, nonce, 16); + memcpy(tmp + 16, nonce, 16); + memcpy(tmp + 32, nonce, 16); + memcpy(tmp + 48, nonce, 16); + n0 = AEGIS_AES_BLOCK_LOAD(tmp); + memcpy(tmp, nonce + 16, 16); + memcpy(tmp + 16, nonce + 16, 16); + memcpy(tmp + 32, nonce + 16, 16); + memcpy(tmp + 48, nonce + 16, 16); + n1 = AEGIS_AES_BLOCK_LOAD(tmp); + + k0_n0 = AEGIS_AES_BLOCK_XOR(k0, n0); + k1_n1 = AEGIS_AES_BLOCK_XOR(k1, n1); + + memset(context_bytes, 0, sizeof context_bytes); + context_bytes[0 * 16] = 0x00; + context_bytes[0 * 16 + 1] = 0x03; + context_bytes[1 * 16] = 0x01; + context_bytes[1 * 16 + 1] = 0x03; + context_bytes[2 * 16] = 0x02; + context_bytes[2 * 16 + 1] = 0x03; + context_bytes[3 * 16] = 0x03; + context_bytes[3 * 16 + 1] = 0x03; + context = AEGIS_AES_BLOCK_LOAD(context_bytes); + + state[0] = k0_n0; + state[1] = k1_n1; + state[2] = c1; + state[3] = c0; + state[4] = AEGIS_AES_BLOCK_XOR(k0, c0); + state[5] = AEGIS_AES_BLOCK_XOR(k1, c1); + for (i = 0; i < 4; i++) { + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k0_n0); + state[3] = AEGIS_AES_BLOCK_XOR(state[3], context); + state[5] = AEGIS_AES_BLOCK_XOR(state[5], context); + AEGIS_update(state, k1_n1); + } +} + +static void +AEGIS_mac(uint8_t *mac, size_t maclen, uint64_t adlen, uint64_t mlen, AEGIS_AES_BLOCK_T *const state) +{ + uint8_t mac_multi_0[AES_BLOCK_LENGTH]; + uint8_t mac_multi_1[AES_BLOCK_LENGTH]; + AEGIS_AES_BLOCK_T tmp; + int i; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(mlen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + if (maclen == 16) { + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + } else if (maclen == 32) { + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(mac_multi_0, tmp); + for (i = 0; i < 16; i++) { + mac[i] = mac_multi_0[i] ^ mac_multi_0[1 * 16 + i] ^ mac_multi_0[2 * 16 + i] ^ + mac_multi_0[3 * 16 + i]; + } + + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(mac_multi_1, tmp); + for (i = 0; i < 16; i++) { + mac[i + 16] = mac_multi_1[i] ^ mac_multi_1[1 * 16 + i] ^ mac_multi_1[2 * 16 + i] ^ + mac_multi_1[3 * 16 + i]; + } + } else { + memset(mac, 0, maclen); + } +} + +static inline void +AEGIS_absorb(const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + AEGIS_update(state, msg); +} + +static void +AEGIS_enc(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + AEGIS_AES_BLOCK_T tmp; + + msg = AEGIS_AES_BLOCK_LOAD(src); + tmp = AEGIS_AES_BLOCK_XOR(msg, state[5]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[1]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, tmp); + + AEGIS_update(state, msg); +} + +static void +AEGIS_dec(uint8_t *const dst, const uint8_t *const src, AEGIS_AES_BLOCK_T *const state) +{ + AEGIS_AES_BLOCK_T msg; + + msg = AEGIS_AES_BLOCK_LOAD(src); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(dst, msg); + + AEGIS_update(state, msg); +} + +static void +AEGIS_declast(uint8_t *const dst, const uint8_t *const src, size_t len, + AEGIS_AES_BLOCK_T *const state) +{ + uint8_t pad[AEGIS_RATE]; + AEGIS_AES_BLOCK_T msg; + + memset(pad, 0, sizeof pad); + memcpy(pad, src, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + msg = AEGIS_AES_BLOCK_XOR(msg, state[5]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[4]); + msg = AEGIS_AES_BLOCK_XOR(msg, state[1]); + msg = AEGIS_AES_BLOCK_XOR(msg, AEGIS_AES_BLOCK_AND(state[2], state[3])); + AEGIS_AES_BLOCK_STORE(pad, msg); + + memset(pad + len, 0, sizeof pad - len); + memcpy(dst, pad, len); + + msg = AEGIS_AES_BLOCK_LOAD(pad); + + AEGIS_update(state, msg); +} + +static void +AEGIS_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, AEGIS_AES_BLOCK_T *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[AEGIS_RATE]; + AEGIS_AES_BLOCK_T tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, adlen << 3); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[5], state[4]); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[3], state[2])); + tmp = AEGIS_AES_BLOCK_XOR(tmp, AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + AEGIS_absorb(r, state); + memcpy(r, t + AES_BLOCK_LENGTH + i * 16, 16); + AEGIS_absorb(r, state); + } + tmp = AEGIS_AES_BLOCK_LOAD_64x2(maclen << 3, d); + tmp = AEGIS_AES_BLOCK_XOR(tmp, state[3]); + for (i = 0; i < 7; i++) { + AEGIS_update(state, tmp); + } +#endif + tmp = AEGIS_AES_BLOCK_XOR(state[2], AEGIS_AES_BLOCK_XOR(state[1], state[0])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AEGIS_AES_BLOCK_XOR(state[5], AEGIS_AES_BLOCK_XOR(state[4], state[3])); + AEGIS_AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + +static int +AEGIS_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } + + AEGIS_mac(mac, maclen, adlen, mlen, state); + + return 0; +} + +static int +AEGIS_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, size_t maclen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + const size_t mlen = clen; + size_t i; + int ret; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, state); + } + if (adlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(src, state); + } + if (m != NULL) { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + } else { + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, state); + } + } + if (mlen % AEGIS_RATE) { + if (m != NULL) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } else { + AEGIS_declast(dst, c + i, mlen % AEGIS_RATE, state); + } + } + + COMPILER_ASSERT(sizeof computed_mac >= 32); + AEGIS_mac(computed_mac, maclen, adlen, mlen, state); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret != 0 && m != NULL) { + memset(m, 0, mlen); + } + return ret; +} + +static void +AEGIS_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + memset(src, 0, sizeof src); + if (npub == NULL) { + npub = src; + } + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= len; i += AEGIS_RATE) { + AEGIS_enc(out + i, src, state); + } + if (len % AEGIS_RATE) { + AEGIS_enc(dst, src, state); + memcpy(out + i, dst, len % AEGIS_RATE); + } +} + +static void +AEGIS_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, state); + } + if (mlen % AEGIS_RATE) { + memset(src, 0, AEGIS_RATE); + memcpy(src, m + i, mlen % AEGIS_RATE); + AEGIS_enc(dst, src, state); + memcpy(c + i, dst, mlen % AEGIS_RATE); + } +} + +static void +AEGIS_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS state; + const size_t mlen = clen; + size_t i; + + AEGIS_init(k, npub, state); + + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, state); + } + if (mlen % AEGIS_RATE) { + AEGIS_declast(m + i, c + i, mlen % AEGIS_RATE, state); + } +} + +typedef struct AEGIS_STATE { + AEGIS_BLOCKS blocks; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + uint64_t mlen; + size_t pos; +} AEGIS_STATE; + +typedef struct AEGIS_MAC_STATE { + AEGIS_BLOCKS blocks; + AEGIS_BLOCKS blocks0; + uint8_t buf[AEGIS_RATE]; + uint64_t adlen; + size_t pos; +} AEGIS_MAC_STATE; + +#ifndef AEGIS_OMIT_INCREMENTAL + +static void +AEGIS_state_init(aegis256x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + + memcpy(blocks, st->blocks, sizeof blocks); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->mlen = 0; + st->pos = 0; + + AEGIS_init(k, npub, blocks); + for (i = 0; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (adlen % AEGIS_RATE) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen % AEGIS_RATE); + AEGIS_absorb(st->buf, blocks); + } + st->adlen = adlen; + + memcpy(st->blocks, blocks, sizeof blocks); +} + +static int +AEGIS_state_encrypt_update(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += mlen; + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = mlen < available ? mlen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, m + i, n); + m += n; + mlen -= n; + st->pos += n; + } + if (st->pos == sizeof st->buf) { + if (clen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + clen_max -= AEGIS_RATE; + AEGIS_enc(c, st->buf, blocks); + *written += AEGIS_RATE; + c += AEGIS_RATE; + st->pos = 0; + } else { + return 0; + } + } + if (clen_max < (mlen & ~(size_t) (AEGIS_RATE - 1))) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= mlen; i += AEGIS_RATE) { + AEGIS_enc(c + i, m + i, blocks); + } + *written += i; + left = mlen % AEGIS_RATE; + if (left != 0) { + memcpy(st->buf, m + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_detached_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(mac, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_encrypt_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t src[AEGIS_RATE]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (clen_max < st->pos + maclen) { + errno = ERANGE; + return -1; + } + if (st->pos != 0) { + memset(src, 0, sizeof src); + memcpy(src, st->buf, st->pos); + AEGIS_enc(dst, src, blocks); + memcpy(c, dst, st->pos); + } + AEGIS_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks); + + *written = st->pos + maclen; + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_update(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *c, size_t clen) +{ + AEGIS_BLOCKS blocks; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + size_t i = 0; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + st->mlen += clen; + + if (st->pos != 0) { + const size_t available = (sizeof st->buf) - st->pos; + const size_t n = clen < available ? clen : available; + + if (n != 0) { + memcpy(st->buf + st->pos, c, n); + c += n; + clen -= n; + st->pos += n; + } + if (st->pos < (sizeof st->buf)) { + return 0; + } + st->pos = 0; + if (m != NULL) { + if (mlen_max < AEGIS_RATE) { + errno = ERANGE; + return -1; + } + mlen_max -= AEGIS_RATE; + AEGIS_dec(m, st->buf, blocks); + m += AEGIS_RATE; + } else { + AEGIS_dec(dst, st->buf, blocks); + } + *written += AEGIS_RATE; + } + + if (m != NULL) { + if (mlen_max < (clen % AEGIS_RATE)) { + errno = ERANGE; + return -1; + } + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(m + i, c + i, blocks); + } + } else { + for (i = 0; i + AEGIS_RATE <= clen; i += AEGIS_RATE) { + AEGIS_dec(dst, c + i, blocks); + } + } + *written += i; + left = clen % AEGIS_RATE; + if (left) { + memcpy(st->buf, c + i, left); + st->pos = left; + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_decrypt_detached_final(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, + const uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + CRYPTO_ALIGN(16) uint8_t computed_mac[32]; + CRYPTO_ALIGN(AEGIS_ALIGNMENT) uint8_t dst[AEGIS_RATE]; + AEGIS_STATE *const st = + (AEGIS_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + int ret; + + memcpy(blocks, st->blocks, sizeof blocks); + + *written = 0; + if (st->pos != 0) { + if (m != NULL) { + if (mlen_max < st->pos) { + errno = ERANGE; + return -1; + } + AEGIS_declast(m, st->buf, st->pos, blocks); + } else { + AEGIS_declast(dst, st->buf, st->pos, blocks); + } + } + AEGIS_mac(computed_mac, maclen, st->adlen, st->mlen, blocks); + ret = -1; + if (maclen == 16) { + ret = aegis_verify_16(computed_mac, mac); + } else if (maclen == 32) { + ret = aegis_verify_32(computed_mac, mac); + } + if (ret == 0) { + *written = st->pos; + } else { + memset(m, 0, st->pos); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return ret; +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +#ifndef AEGIS_OMIT_MAC_API + +static void +AEGIS_state_mac_init(aegis256x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + AEGIS_ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + AEGIS_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + +static int +AEGIS_state_mac_update(aegis256x4_mac_state *st_, const uint8_t *ad, size_t adlen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t i; + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + st->adlen += adlen; + if (left != 0) { + if (left + adlen < AEGIS_RATE) { + memcpy(st->buf + left, ad, adlen); + return 0; + } + memcpy(st->buf + left, ad, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + ad += AEGIS_RATE - left; + adlen -= AEGIS_RATE - left; + } + for (i = 0; i + AEGIS_RATE * 2 <= adlen; i += AEGIS_RATE * 2) { + AEGIS_AES_BLOCK_T msg0, msg1; + + msg0 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 0); + msg1 = AEGIS_AES_BLOCK_LOAD(ad + i + AES_BLOCK_LENGTH * 1); + COMPILER_ASSERT(AES_BLOCK_LENGTH * 2 == AEGIS_RATE * 2); + + AEGIS_update(blocks, msg0); + AEGIS_update(blocks, msg1); + } + for (; i + AEGIS_RATE <= adlen; i += AEGIS_RATE) { + AEGIS_absorb(ad + i, blocks); + } + if (i < adlen) { + memset(st->buf, 0, AEGIS_RATE); + memcpy(st->buf, ad + i, adlen - i); + } + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static int +AEGIS_state_mac_final(aegis256x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + AEGIS_BLOCKS blocks; + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + size_t left; + + memcpy(blocks, st->blocks, sizeof blocks); + + left = st->adlen % AEGIS_RATE; + if (left != 0) { + memset(st->buf + left, 0, AEGIS_RATE - left); + AEGIS_absorb(st->buf, blocks); + } + AEGIS_mac_nr(mac, maclen, st->adlen, blocks); + + memcpy(st->blocks, blocks, sizeof blocks); + + return 0; +} + +static void +AEGIS_state_mac_reset(aegis256x4_mac_state *st_) +{ + AEGIS_MAC_STATE *const st = + (AEGIS_MAC_STATE *) ((((uintptr_t) &st_->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(AEGIS_BLOCKS)); +} + +static void +AEGIS_state_mac_clone(aegis256x4_mac_state *dst, const aegis256x4_mac_state *src) +{ + AEGIS_MAC_STATE *const dst_ = + (AEGIS_MAC_STATE *) ((((uintptr_t) &dst->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + const AEGIS_MAC_STATE *const src_ = + (const AEGIS_MAC_STATE *) ((((uintptr_t) &src->opaque) + (AEGIS_ALIGNMENT - 1)) & + ~(uintptr_t) (AEGIS_ALIGNMENT - 1)); + *dst_ = *src_; +} + +#endif /* AEGIS_OMIT_MAC_API */ + +#undef AEGIS_RATE +#undef AEGIS_ALIGNMENT + +#undef AEGIS_init +#undef AEGIS_mac +#undef AEGIS_mac_nr +#undef AEGIS_absorb +#undef AEGIS_enc +#undef AEGIS_dec +#undef AEGIS_declast +/*** End of #include "aegis256x4_common.h" ***/ + + +AEGIS_API +struct aegis256x4_implementation aegis256x4_armcrypto_implementation = { +/* #include "../common/func_table.h" */ +/*** Begin of #include "../common/func_table.h" ***/ +/* +** Name: func_table.h +** Purpose: Table of AEGIS API function implementations +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +AEGIS_API_IMPL_LIST_STD +#ifndef AEGIS_OMIT_INCREMENTAL +AEGIS_API_IMPL_LIST_INC +#endif +#ifndef AEGIS_OMIT_MAC_API +AEGIS_API_IMPL_LIST_MAC +#endif + +/*** End of #include "../common/func_table.h" ***/ + +}; + +/* #include "../common/type_names_undefine.h" */ +/*** Begin of #include "../common/type_names_undefine.h" ***/ +/* +** Name: type_names_undefine.h +** Purpose: Undefines for AEGIS type names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine AES block length */ +#undef AES_BLOCK_LENGTH + +/* Undefine type names */ +#undef AEGIS_AES_BLOCK_T +#undef AEGIS_BLOCKS +#undef AEGIS_STATE +#undef AEGIS_MAC_STATE +/*** End of #include "../common/type_names_undefine.h" ***/ + +/* #include "../common/func_names_undefine.h" */ +/*** Begin of #include "../common/func_names_undefine.h" ***/ +/* +** Name: func_names_undefine.h +** Purpose: Undefines for AEGIS function names +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +/* +** NOTE: +** Do NOT use include guards, because including this header +** multiple times is intended behaviour. +*/ + +/* Undefine function name prefix */ +#undef AEGIS_FUNC_PREFIX + +/* Undefine all function names */ +#undef AEGIS_AES_BLOCK_XOR +#undef AEGIS_AES_BLOCK_AND +#undef AEGIS_AES_BLOCK_LOAD +#undef AEGIS_AES_BLOCK_LOAD_64x2 +#undef AEGIS_AES_BLOCK_STORE +#undef AEGIS_AES_ENC +#undef AEGIS_update +#undef AEGIS_encrypt_detached +#undef AEGIS_decrypt_detached +#undef AEGIS_encrypt_unauthenticated +#undef AEGIS_decrypt_unauthenticated +#undef AEGIS_stream +#undef AEGIS_state_init +#undef AEGIS_state_encrypt_update +#undef AEGIS_state_encrypt_detached_final +#undef AEGIS_state_encrypt_final +#undef AEGIS_state_decrypt_detached_update +#undef AEGIS_state_decrypt_detached_final +#undef AEGIS_state_mac_init +#undef AEGIS_state_mac_update +#undef AEGIS_state_mac_final +#undef AEGIS_state_mac_reset +#undef AEGIS_state_mac_clone +/*** End of #include "../common/func_names_undefine.h" ***/ + + +#ifdef __clang__ +# pragma clang attribute pop +#endif + +#endif +/*** End of #include "aegis256x4/aegis256x4_armcrypto.c" ***/ + + +/* Control functions for the AEGIS variants */ +/* #include "aegis128l/aegis128l.c" */ +/*** Begin of #include "aegis128l/aegis128l.c" ***/ +/* +** Name: aegis128l.c +** Purpose: Implementation of AEGIS-128L +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + +/* #include "../include/aegis128l.h" */ + +#if 0 +/* #include "aegis128l_aesni.h" */ + +/* #include "aegis128l_altivec.h" */ + +/* #include "aegis128l_armcrypto.h" */ + +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NONE +/* #include "aegis128l_soft.h" */ + +static const aegis128l_implementation *implementation_128l = &aegis128l_soft_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON +static const aegis128l_implementation *implementation_128l = &aegis128l_armcrypto_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +static const aegis128l_implementation *implementation_128l = &aegis128l_aesni_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +static const aegis128l_implementation *implementation_128l = &aegis128l_altivec_implementation; +#else +#error "Unsupported architecture" +#endif + +AEGIS_API +size_t +aegis128l_keybytes(void) +{ + return aegis128l_KEYBYTES; +} + +AEGIS_API +size_t +aegis128l_npubbytes(void) +{ + return aegis128l_NPUBBYTES; +} + +AEGIS_API +size_t +aegis128l_abytes_min(void) +{ + return aegis128l_ABYTES_MIN; +} + +AEGIS_API +size_t +aegis128l_abytes_max(void) +{ + return aegis128l_ABYTES_MAX; +} + +AEGIS_API +size_t +aegis128l_tailbytes_max(void) +{ + return aegis128l_TAILBYTES_MAX; +} + +AEGIS_API +int +aegis128l_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128l->encrypt_detached(c, mac, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128l_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128l->decrypt_detached(m, c, clen, mac, maclen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128l_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + return aegis128l_encrypt_detached(c, c + mlen, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128l_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + int ret = -1; + + if (clen >= maclen) { + ret = aegis128l_decrypt_detached(m, c, clen - maclen, c + clen - maclen, maclen, ad, adlen, + npub, k); + } + return ret; +} + +#ifndef AEGIS_OMIT_INCREMENTAL + +AEGIS_API +void +aegis128l_state_init(aegis128l_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + memset(st_, 0, sizeof *st_); + implementation_128l->state_init(st_, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128l_state_encrypt_update(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + return implementation_128l->state_encrypt_update(st_, c, clen_max, written, m, mlen); +} + +AEGIS_API +int +aegis128l_state_encrypt_detached_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128l->state_encrypt_detached_final(st_, c, clen_max, written, mac, maclen); +} + +AEGIS_API +int +aegis128l_state_encrypt_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128l->state_encrypt_final(st_, c, clen_max, written, maclen); +} + +AEGIS_API +int +aegis128l_state_decrypt_detached_update(aegis128l_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) +{ + return implementation_128l->state_decrypt_detached_update(st_, m, mlen_max, written, c, clen); +} + +AEGIS_API +int +aegis128l_state_decrypt_detached_final(aegis128l_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128l->state_decrypt_detached_final(st_, m, mlen_max, written, mac, maclen); +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +AEGIS_API +void +aegis128l_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + implementation_128l->stream(out, len, npub, k); +} + +AEGIS_API +void +aegis128l_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_128l->encrypt_unauthenticated(c, m, mlen, npub, k); +} + +AEGIS_API +void +aegis128l_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_128l->decrypt_unauthenticated(m, c, clen, npub, k); +} + +#ifndef AEGIS_OMIT_MAC_API + +AEGIS_API +void +aegis128l_mac_init(aegis128l_mac_state *st_, const uint8_t *k, const uint8_t *npub) +{ +#if 0 + memset(st_, 0, sizeof *st_); +#endif + implementation_128l->state_mac_init(st_, npub, k); +} + +AEGIS_API +int +aegis128l_mac_update(aegis128l_mac_state *st_, const uint8_t *m, size_t mlen) +{ + return implementation_128l->state_mac_update(st_, m, mlen); +} + +AEGIS_API +int +aegis128l_mac_final(aegis128l_mac_state *st_, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128l->state_mac_final(st_, mac, maclen); +} + +AEGIS_API +int +aegis128l_mac_verify(aegis128l_mac_state *st_, const uint8_t *mac, size_t maclen) +{ + uint8_t expected_mac[32]; + + switch (maclen) { + case 16: + implementation_128l->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_16(expected_mac, mac); + case 32: + implementation_128l->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_32(expected_mac, mac); + default: + errno = EINVAL; + return -1; + } +} + +AEGIS_API +void +aegis128l_mac_reset(aegis128l_mac_state *st_) +{ + implementation_128l->state_mac_reset(st_); +} + +AEGIS_API +void +aegis128l_mac_state_clone(aegis128l_mac_state *dst, const aegis128l_mac_state *src) +{ + implementation_128l->state_mac_clone(dst, src); +} + +#endif /* AEGIS_OMIT_MAC_API */ + +AEGIS_PRIVATE +int +aegis128l_pick_best_implementation(void) +{ + implementation_128l = &aegis128l_soft_implementation; + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + if (aegis_runtime_has_armcrypto()) { + implementation_128l = &aegis128l_armcrypto_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI + if (aegis_runtime_has_aesni() && aegis_runtime_has_avx()) { + implementation_128l = &aegis128l_aesni_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC + if (aegis_runtime_has_altivec()) { + implementation_128l = &aegis128l_altivec_implementation; + return 0; + } +#endif + + return 0; /* LCOV_EXCL_LINE */ +} +/*** End of #include "aegis128l/aegis128l.c" ***/ + +/* #include "aegis128x2/aegis128x2.c" */ +/*** Begin of #include "aegis128x2/aegis128x2.c" ***/ +/* +** Name: aegis128x2.c +** Purpose: Implementation of AEGIS-128x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + +/* #include "../include/aegis128x2.h" */ + +#if 0 +/* #include "aegis128x2_aesni.h" */ + +/* #include "aegis128x2_altivec.h" */ + +/* #include "aegis128x2_armcrypto.h" */ + +/* #include "aegis128x2_avx2.h" */ + +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NONE +/* #include "aegis128x2_soft.h" */ + +static const aegis128x2_implementation* implementation_128x2 = &aegis128x2_soft_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON +static const aegis128x2_implementation* implementation_128x2 = &aegis128x2_armcrypto_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +static const aegis128x2_implementation* implementation_128x2 = &aegis128x2_aesni_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +static const aegis128x2_implementation* implementation_128x2 = &aegis128x2_altivec_implementation; +#else +#error "Unsupported architecture" +#endif + +AEGIS_API +size_t +aegis128x2_keybytes(void) +{ + return aegis128x2_KEYBYTES; +} + +AEGIS_API +size_t +aegis128x2_npubbytes(void) +{ + return aegis128x2_NPUBBYTES; +} + +AEGIS_API +size_t +aegis128x2_abytes_min(void) +{ + return aegis128x2_ABYTES_MIN; +} + +AEGIS_API +size_t +aegis128x2_abytes_max(void) +{ + return aegis128x2_ABYTES_MAX; +} + +AEGIS_API +size_t +aegis128x2_tailbytes_max(void) +{ + return aegis128x2_TAILBYTES_MAX; +} + +AEGIS_API +int +aegis128x2_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x2->encrypt_detached(c, mac, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128x2_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x2->decrypt_detached(m, c, clen, mac, maclen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128x2_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + return aegis128x2_encrypt_detached(c, c + mlen, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128x2_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + int ret = -1; + + if (clen >= maclen) { + ret = aegis128x2_decrypt_detached(m, c, clen - maclen, c + clen - maclen, maclen, ad, adlen, + npub, k); + } + return ret; +} + +#ifndef AEGIS_OMIT_INCREMENTAL + +AEGIS_API +void +aegis128x2_state_init(aegis128x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + memset(st_, 0, sizeof *st_); + implementation_128x2->state_init(st_, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128x2_state_encrypt_update(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + return implementation_128x2->state_encrypt_update(st_, c, clen_max, written, m, mlen); +} + +AEGIS_API +int +aegis128x2_state_encrypt_detached_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x2->state_encrypt_detached_final(st_, c, clen_max, written, mac, maclen); +} + +AEGIS_API +int +aegis128x2_state_encrypt_final(aegis128x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x2->state_encrypt_final(st_, c, clen_max, written, maclen); +} + +AEGIS_API +int +aegis128x2_state_decrypt_detached_update(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) +{ + return implementation_128x2->state_decrypt_detached_update(st_, m, mlen_max, written, c, clen); +} + +AEGIS_API +int +aegis128x2_state_decrypt_detached_final(aegis128x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x2->state_decrypt_detached_final(st_, m, mlen_max, written, mac, maclen); +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +AEGIS_API +void +aegis128x2_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + implementation_128x2->stream(out, len, npub, k); +} + +AEGIS_API +void +aegis128x2_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_128x2->encrypt_unauthenticated(c, m, mlen, npub, k); +} + +AEGIS_API +void +aegis128x2_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_128x2->decrypt_unauthenticated(m, c, clen, npub, k); +} + +#ifndef AEGIS_OMIT_MAC_API + +AEGIS_API +void +aegis128x2_mac_init(aegis128x2_mac_state *st_, const uint8_t *k, const uint8_t *npub) +{ + implementation_128x2->state_mac_init(st_, npub, k); +} + +AEGIS_API +int +aegis128x2_mac_update(aegis128x2_mac_state *st_, const uint8_t *m, size_t mlen) +{ + return implementation_128x2->state_mac_update(st_, m, mlen); +} + +AEGIS_API +int +aegis128x2_mac_final(aegis128x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x2->state_mac_final(st_, mac, maclen); +} + +AEGIS_API +int +aegis128x2_mac_verify(aegis128x2_mac_state *st_, const uint8_t *mac, size_t maclen) +{ + uint8_t expected_mac[32]; + + switch (maclen) { + case 16: + implementation_128x2->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_16(expected_mac, mac); + case 32: + implementation_128x2->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_32(expected_mac, mac); + default: + errno = EINVAL; + return -1; + } +} + +AEGIS_API +void +aegis128x2_mac_reset(aegis128x2_mac_state *st_) +{ + implementation_128x2->state_mac_reset(st_); +} + +AEGIS_API +void +aegis128x2_mac_state_clone(aegis128x2_mac_state *dst, const aegis128x2_mac_state *src) +{ + implementation_128x2->state_mac_clone(dst, src); +} + +#endif /* AEGIS_OMIT_MAC_API */ + +AEGIS_PRIVATE +int +aegis128x2_pick_best_implementation(void) +{ + implementation_128x2 = &aegis128x2_soft_implementation; + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + if (aegis_runtime_has_armcrypto()) { + implementation_128x2 = &aegis128x2_armcrypto_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +# ifdef HAVE_VAESINTRIN_H + if (aegis_runtime_has_vaes() && aegis_runtime_has_avx2()) { + implementation_128x2 = &aegis128x2_avx2_implementation; + return 0; + } +# endif + if (aegis_runtime_has_aesni() && aegis_runtime_has_avx()) { + implementation_128x2 = &aegis128x2_aesni_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC + if (aegis_runtime_has_altivec()) { + implementation_128x2 = &aegis128x2_altivec_implementation; + return 0; + } +#endif + + return 0; /* LCOV_EXCL_LINE */ +} +/*** End of #include "aegis128x2/aegis128x2.c" ***/ + +/* #include "aegis128x4/aegis128x4.c" */ +/*** Begin of #include "aegis128x4/aegis128x4.c" ***/ +/* +** Name: aegis128x4.c +** Purpose: Implementation of AEGIS-128x4 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + +/* #include "../include/aegis128x4.h" */ + + +#if 0 +/* #include "aegis128x4_aesni.h" */ + +/* #include "aegis128x4_altivec.h" */ + +/* #include "aegis128x4_armcrypto.h" */ + +/* #include "aegis128x4_avx2.h" */ + +/* #include "aegis128x4_avx512.h" */ + +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NONE +/* #include "aegis128x4_soft.h" */ + +static const aegis128x4_implementation* implementation_128x4 = &aegis128x4_soft_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON +static const aegis128x4_implementation* implementation_128x4 = &aegis128x4_armcrypto_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +static const aegis128x4_implementation* implementation_128x4 = &aegis128x4_aesni_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +static const aegis128x4_implementation* implementation_128x4 = &aegis128x4_altivec_implementation; +#else +#error "Unsupported architecture" +#endif + +AEGIS_API +size_t +aegis128x4_keybytes(void) +{ + return aegis128x4_KEYBYTES; +} + +AEGIS_API +size_t +aegis128x4_npubbytes(void) +{ + return aegis128x4_NPUBBYTES; +} + +AEGIS_API +size_t +aegis128x4_abytes_min(void) +{ + return aegis128x4_ABYTES_MIN; +} + +AEGIS_API +size_t +aegis128x4_abytes_max(void) +{ + return aegis128x4_ABYTES_MAX; +} + +AEGIS_API +size_t +aegis128x4_tailbytes_max(void) +{ + return aegis128x4_TAILBYTES_MAX; +} + +AEGIS_API +int +aegis128x4_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x4->encrypt_detached(c, mac, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128x4_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x4->decrypt_detached(m, c, clen, mac, maclen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128x4_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + return aegis128x4_encrypt_detached(c, c + mlen, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128x4_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + int ret = -1; + + if (clen >= maclen) { + ret = aegis128x4_decrypt_detached(m, c, clen - maclen, c + clen - maclen, maclen, ad, adlen, + npub, k); + } + return ret; +} + +#ifndef AEGIS_OMIT_INCREMENTAL + +AEGIS_API +void +aegis128x4_state_init(aegis128x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + memset(st_, 0, sizeof *st_); + implementation_128x4->state_init(st_, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis128x4_state_encrypt_update(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + return implementation_128x4->state_encrypt_update(st_, c, clen_max, written, m, mlen); +} + +AEGIS_API +int +aegis128x4_state_encrypt_detached_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x4->state_encrypt_detached_final(st_, c, clen_max, written, mac, maclen); +} + +AEGIS_API +int +aegis128x4_state_encrypt_final(aegis128x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x4->state_encrypt_final(st_, c, clen_max, written, maclen); +} + +AEGIS_API +int +aegis128x4_state_decrypt_detached_update(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) +{ + return implementation_128x4->state_decrypt_detached_update(st_, m, mlen_max, written, c, clen); +} + +AEGIS_API +int +aegis128x4_state_decrypt_detached_final(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x4->state_decrypt_detached_final(st_, m, mlen_max, written, mac, maclen); +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +AEGIS_API +void +aegis128x4_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + implementation_128x4->stream(out, len, npub, k); +} + +AEGIS_API +void +aegis128x4_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_128x4->encrypt_unauthenticated(c, m, mlen, npub, k); +} + +AEGIS_API +void +aegis128x4_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_128x4->decrypt_unauthenticated(m, c, clen, npub, k); +} + +#ifndef AEGIS_OMIT_MAC_API + +AEGIS_API +void +aegis128x4_mac_init(aegis128x4_mac_state *st_, const uint8_t *k, const uint8_t *npub) +{ + implementation_128x4->state_mac_init(st_, npub, k); +} + +AEGIS_API +int +aegis128x4_mac_update(aegis128x4_mac_state *st_, const uint8_t *m, size_t mlen) +{ + return implementation_128x4->state_mac_update(st_, m, mlen); +} + +AEGIS_API +int +aegis128x4_mac_final(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_128x4->state_mac_final(st_, mac, maclen); +} + +AEGIS_API +int +aegis128x4_mac_verify(aegis128x4_mac_state *st_, const uint8_t *mac, size_t maclen) +{ + uint8_t expected_mac[32]; + + switch (maclen) { + case 16: + implementation_128x4->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_16(expected_mac, mac); + case 32: + implementation_128x4->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_32(expected_mac, mac); + default: + errno = EINVAL; + return -1; + } +} + +AEGIS_API +void +aegis128x4_mac_reset(aegis128x4_mac_state *st_) +{ + implementation_128x4->state_mac_reset(st_); +} + +AEGIS_API +void +aegis128x4_mac_state_clone(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src) +{ + implementation_128x4->state_mac_clone(dst, src); +} + +#endif /* AEGIS_OMIT_MAC_API */ + +AEGIS_PRIVATE +int +aegis128x4_pick_best_implementation(void) +{ + implementation_128x4 = &aegis128x4_soft_implementation; + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + if (aegis_runtime_has_armcrypto()) { + implementation_128x4 = &aegis128x4_armcrypto_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +# ifdef HAVE_VAESINTRIN_H + if (aegis_runtime_has_vaes() && aegis_runtime_has_avx512f()) { + implementation_128x4 = &aegis128x4_avx512_implementation; + return 0; + } + if (aegis_runtime_has_vaes() && aegis_runtime_has_avx2()) { + implementation_128x4 = &aegis128x4_avx2_implementation; + return 0; + } +# endif + if (aegis_runtime_has_aesni() && aegis_runtime_has_avx()) { + implementation_128x4 = &aegis128x4_aesni_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC + if (aegis_runtime_has_altivec()) { + implementation_128x4 = &aegis128x4_altivec_implementation; + return 0; + } +#endif + + return 0; /* LCOV_EXCL_LINE */ +} +/*** End of #include "aegis128x4/aegis128x4.c" ***/ + +/* #include "aegis256/aegis256.c" */ +/*** Begin of #include "aegis256/aegis256.c" ***/ +/* +** Name: aegis256.c +** Purpose: Implementation of AEGIS-256 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + +/* #include "aegis256.h" */ + +#if 0 +/* #include "aegis256_aesni.h" */ + +/* #include "aegis256_altivec.h" */ + +/* #include "aegis256_armcrypto.h" */ + +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NONE +/* #include "aegis256_soft.h" */ + +static const aegis256_implementation *implementation_256 = &aegis256_soft_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON +static const aegis256_implementation *implementation_256 = &aegis256_armcrypto_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +static const aegis256_implementation *implementation_256 = &aegis256_aesni_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +static const aegis256_implementation *implementation_256 = &aegis256_altivec_implementation; +#else +#error "Unsupported architecture" +#endif + +AEGIS_API +size_t +aegis256_keybytes(void) +{ + return aegis256_KEYBYTES; +} + +AEGIS_API +size_t +aegis256_npubbytes(void) +{ + return aegis256_NPUBBYTES; +} + +AEGIS_API +size_t +aegis256_abytes_min(void) +{ + return aegis256_ABYTES_MIN; +} + +AEGIS_API +size_t +aegis256_abytes_max(void) +{ + return aegis256_ABYTES_MAX; +} + +AEGIS_API +size_t +aegis256_tailbytes_max(void) +{ + return aegis256_TAILBYTES_MAX; +} + +AEGIS_API +int +aegis256_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256->encrypt_detached(c, mac, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256->decrypt_detached(m, c, clen, mac, maclen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + return aegis256_encrypt_detached(c, c + mlen, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + int ret = -1; + + if (clen >= maclen) { + ret = aegis256_decrypt_detached(m, c, clen - maclen, c + clen - maclen, maclen, ad, adlen, + npub, k); + } + return ret; +} + +#ifndef AEGIS_OMIT_INCREMENTAL + +AEGIS_API +void +aegis256_state_init(aegis256_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + memset(st_, 0, sizeof *st_); + implementation_256->state_init(st_, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256_state_encrypt_update(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + return implementation_256->state_encrypt_update(st_, c, clen_max, written, m, mlen); +} + +AEGIS_API +int +aegis256_state_encrypt_detached_final(aegis256_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256->state_encrypt_detached_final(st_, c, clen_max, written, mac, maclen); +} + +AEGIS_API +int +aegis256_state_encrypt_final(aegis256_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256->state_encrypt_final(st_, c, clen_max, written, maclen); +} + +AEGIS_API +int +aegis256_state_decrypt_detached_update(aegis256_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) +{ + return implementation_256->state_decrypt_detached_update(st_, m, mlen_max, written, c, clen); +} + +AEGIS_API +int +aegis256_state_decrypt_detached_final(aegis256_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256->state_decrypt_detached_final(st_, m, mlen_max, written, mac, maclen); +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +AEGIS_API +void +aegis256_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + implementation_256->stream(out, len, npub, k); +} + +AEGIS_API +void +aegis256_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_256->encrypt_unauthenticated(c, m, mlen, npub, k); +} + +AEGIS_API +void +aegis256_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_256->decrypt_unauthenticated(m, c, clen, npub, k); +} + +#ifndef AEGIS_OMIT_MAC_API + +AEGIS_API +void +aegis256_mac_init(aegis256_mac_state *st_, const uint8_t *k, const uint8_t *npub) +{ + implementation_256->state_mac_init(st_, npub, k); +} + +AEGIS_API +int +aegis256_mac_update(aegis256_mac_state *st_, const uint8_t *m, size_t mlen) +{ + return implementation_256->state_mac_update(st_, m, mlen); +} + +AEGIS_API +int +aegis256_mac_final(aegis256_mac_state *st_, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256->state_mac_final(st_, mac, maclen); +} + +AEGIS_API +int +aegis256_mac_verify(aegis256_mac_state *st_, const uint8_t *mac, size_t maclen) +{ + uint8_t expected_mac[32]; + + switch (maclen) { + case 16: + implementation_256->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_16(expected_mac, mac); + case 32: + implementation_256->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_32(expected_mac, mac); + default: + errno = EINVAL; + return -1; + } +} + +AEGIS_API +void +aegis256_mac_reset(aegis256_mac_state *st_) +{ + implementation_256->state_mac_reset(st_); +} + +AEGIS_API +void +aegis256_mac_state_clone(aegis256_mac_state *dst, const aegis256_mac_state *src) +{ + implementation_256->state_mac_clone(dst, src); +} + +#endif /* AEGIS_OMIT_MAC_API */ + +AEGIS_PRIVATE +int +aegis256_pick_best_implementation(void) +{ + implementation_256 = &aegis256_soft_implementation; + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + if (aegis_runtime_has_armcrypto()) { + implementation_256 = &aegis256_armcrypto_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI + if (aegis_runtime_has_aesni() && aegis_runtime_has_avx()) { + implementation_256 = &aegis256_aesni_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC + if (aegis_runtime_has_altivec()) { + implementation_256 = &aegis256_altivec_implementation; + return 0; + } +#endif + + return 0; /* LCOV_EXCL_LINE */ +} +/*** End of #include "aegis256/aegis256.c" ***/ + +/* #include "aegis256x2/aegis256x2.c" */ +/*** Begin of #include "aegis256x2/aegis256x2.c" ***/ +/* +** Name: aegis256x2.c +** Purpose: Implementation of AEGIS-256x2 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + +/* #include "aegis256x2.h" */ + +#if 0 +/* #include "aegis256x2_aesni.h" */ + +/* #include "aegis256x2_altivec.h" */ + +/* #include "aegis256x2_armcrypto.h" */ + +/* #include "aegis256x2_avx2.h" */ + +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NONE +/* #include "aegis256x2_soft.h" */ + +static const aegis256x2_implementation *implementation_256x2 = &aegis256x2_soft_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON +static const aegis256x2_implementation *implementation_256x2 = &aegis256x2_armcrypto_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +static const aegis256x2_implementation *implementation_256x2 = &aegis256x2_aesni_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +static const aegis256x2_implementation *implementation_256x2 = &aegis256x2_altivec_implementation; +#else +#error "Unsupported architecture" +#endif + +AEGIS_API +size_t +aegis256x2_keybytes(void) +{ + return aegis256x2_KEYBYTES; +} + +AEGIS_API +size_t +aegis256x2_npubbytes(void) +{ + return aegis256x2_NPUBBYTES; +} + +AEGIS_API +size_t +aegis256x2_abytes_min(void) +{ + return aegis256x2_ABYTES_MIN; +} + +AEGIS_API +size_t +aegis256x2_abytes_max(void) +{ + return aegis256x2_ABYTES_MAX; +} + +AEGIS_API +size_t +aegis256x2_tailbytes_max(void) +{ + return aegis256x2_TAILBYTES_MAX; +} + +AEGIS_API +int +aegis256x2_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x2->encrypt_detached(c, mac, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256x2_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x2->decrypt_detached(m, c, clen, mac, maclen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256x2_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + return aegis256x2_encrypt_detached(c, c + mlen, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256x2_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + int ret = -1; + + if (clen >= maclen) { + ret = aegis256x2_decrypt_detached(m, c, clen - maclen, c + clen - maclen, maclen, ad, adlen, + npub, k); + } + return ret; +} + +#ifndef AEGIS_OMIT_INCREMENTAL + +AEGIS_API +void +aegis256x2_state_init(aegis256x2_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + memset(st_, 0, sizeof *st_); + implementation_256x2->state_init(st_, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256x2_state_encrypt_update(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + return implementation_256x2->state_encrypt_update(st_, c, clen_max, written, m, mlen); +} + +AEGIS_API +int +aegis256x2_state_encrypt_detached_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x2->state_encrypt_detached_final(st_, c, clen_max, written, mac, maclen); +} + +AEGIS_API +int +aegis256x2_state_encrypt_final(aegis256x2_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x2->state_encrypt_final(st_, c, clen_max, written, maclen); +} + +AEGIS_API +int +aegis256x2_state_decrypt_detached_update(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) +{ + return implementation_256x2->state_decrypt_detached_update(st_, m, mlen_max, written, c, clen); +} + +AEGIS_API +int +aegis256x2_state_decrypt_detached_final(aegis256x2_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x2->state_decrypt_detached_final(st_, m, mlen_max, written, mac, maclen); +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +AEGIS_API +void +aegis256x2_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + implementation_256x2->stream(out, len, npub, k); +} + +AEGIS_API +void +aegis256x2_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_256x2->encrypt_unauthenticated(c, m, mlen, npub, k); +} + +AEGIS_API +void +aegis256x2_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_256x2->decrypt_unauthenticated(m, c, clen, npub, k); +} + +#ifndef AEGIS_OMIT_MAC_API + +AEGIS_API +void +aegis256x2_mac_init(aegis256x2_mac_state *st_, const uint8_t *k, const uint8_t *npub) +{ + implementation_256x2->state_mac_init(st_, npub, k); +} + +AEGIS_API +int +aegis256x2_mac_update(aegis256x2_mac_state *st_, const uint8_t *m, size_t mlen) +{ + return implementation_256x2->state_mac_update(st_, m, mlen); +} + +AEGIS_API +int +aegis256x2_mac_final(aegis256x2_mac_state *st_, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x2->state_mac_final(st_, mac, maclen); +} + +AEGIS_API +int +aegis256x2_mac_verify(aegis256x2_mac_state *st_, const uint8_t *mac, size_t maclen) +{ + uint8_t expected_mac[32]; + + switch (maclen) { + case 16: + implementation_256x2->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_16(expected_mac, mac); + case 32: + implementation_256x2->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_32(expected_mac, mac); + default: + errno = EINVAL; + return -1; + } +} + +AEGIS_API +void +aegis256x2_mac_reset(aegis256x2_mac_state *st_) +{ + implementation_256x2->state_mac_reset(st_); +} + +AEGIS_API +void +aegis256x2_mac_state_clone(aegis256x2_mac_state *dst, const aegis256x2_mac_state *src) +{ + implementation_256x2->state_mac_clone(dst, src); +} + +#endif /* AEGIS_OMIT_MAC_API */ + +AEGIS_PRIVATE +int +aegis256x2_pick_best_implementation(void) +{ + implementation_256x2 = &aegis256x2_soft_implementation; + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + if (aegis_runtime_has_armcrypto()) { + implementation_256x2 = &aegis256x2_armcrypto_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +# ifdef HAVE_VAESINTRIN_H + if (aegis_runtime_has_vaes() && aegis_runtime_has_avx2()) { + implementation_256x2 = &aegis256x2_avx2_implementation; + return 0; + } +# endif + if (aegis_runtime_has_aesni() && aegis_runtime_has_avx()) { + implementation_256x2 = &aegis256x2_aesni_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC + if (aegis_runtime_has_altivec()) { + implementation_256x2 = &aegis256x2_altivec_implementation; + return 0; + } +#endif + + return 0; /* LCOV_EXCL_LINE */ +} +/*** End of #include "aegis256x2/aegis256x2.c" ***/ + +/* #include "aegis256x4/aegis256x4.c" */ +/*** Begin of #include "aegis256x4/aegis256x4.c" ***/ +/* +** Name: aegis256x4.c +** Purpose: Implementation of AEGIS-256x4 +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +/* #include "../common/common.h" */ + +/* #include "../common/cpu.h" */ + +/* #include "aegis256x4.h" */ + +#if 0 +/* #include "aegis256x4_aesni.h" */ + +/* #include "aegis256x4_altivec.h" */ + +/* #include "aegis256x4_armcrypto.h" */ + +/* #include "aegis256x4_avx2.h" */ + +/* #include "aegis256x4_avx512.h" */ + +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NONE +/* #include "aegis256x4_soft.h" */ + +static const aegis256x4_implementation *implementation_256x4 = &aegis256x4_soft_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON +static const aegis256x4_implementation *implementation_256x4 = &aegis256x4_armcrypto_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +static const aegis256x4_implementation *implementation_256x4 = &aegis256x4_aesni_implementation; +#elif HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC +static const aegis256x4_implementation *implementation_256x4 = &aegis256x4_altivec_implementation; +#else +#error "Unsupported architecture" +#endif + +AEGIS_API +size_t +aegis256x4_keybytes(void) +{ + return aegis256x4_KEYBYTES; +} + +AEGIS_API +size_t +aegis256x4_npubbytes(void) +{ + return aegis256x4_NPUBBYTES; +} + +AEGIS_API +size_t +aegis256x4_abytes_min(void) +{ + return aegis256x4_ABYTES_MIN; +} + +AEGIS_API +size_t +aegis256x4_abytes_max(void) +{ + return aegis256x4_ABYTES_MAX; +} + +AEGIS_API +size_t +aegis256x4_tailbytes_max(void) +{ + return aegis256x4_TAILBYTES_MAX; +} + +AEGIS_API +int +aegis256x4_encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, + const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x4->encrypt_detached(c, mac, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256x4_decrypt_detached(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *mac, + size_t maclen, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x4->decrypt_detached(m, c, clen, mac, maclen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256x4_encrypt(uint8_t *c, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + return aegis256x4_encrypt_detached(c, c + mlen, maclen, m, mlen, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256x4_decrypt(uint8_t *m, const uint8_t *c, size_t clen, size_t maclen, const uint8_t *ad, + size_t adlen, const uint8_t *npub, const uint8_t *k) +{ + int ret = -1; + + if (clen >= maclen) { + ret = aegis256x4_decrypt_detached(m, c, clen - maclen, c + clen - maclen, maclen, ad, adlen, + npub, k); + } + return ret; +} + +#ifndef AEGIS_OMIT_INCREMENTAL + +AEGIS_API +void +aegis256x4_state_init(aegis256x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, + const uint8_t *k) +{ + memset(st_, 0, sizeof *st_); + implementation_256x4->state_init(st_, ad, adlen, npub, k); +} + +AEGIS_API +int +aegis256x4_state_encrypt_update(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + const uint8_t *m, size_t mlen) +{ + return implementation_256x4->state_encrypt_update(st_, c, clen_max, written, m, mlen); +} + +AEGIS_API +int +aegis256x4_state_encrypt_detached_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, + size_t *written, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x4->state_encrypt_detached_final(st_, c, clen_max, written, mac, maclen); +} + +AEGIS_API +int +aegis256x4_state_encrypt_final(aegis256x4_state *st_, uint8_t *c, size_t clen_max, size_t *written, + size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x4->state_encrypt_final(st_, c, clen_max, written, maclen); +} + +AEGIS_API +int +aegis256x4_state_decrypt_detached_update(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *c, size_t clen) +{ + return implementation_256x4->state_decrypt_detached_update(st_, m, mlen_max, written, c, clen); +} + +AEGIS_API +int +aegis256x4_state_decrypt_detached_final(aegis256x4_state *st_, uint8_t *m, size_t mlen_max, + size_t *written, const uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x4->state_decrypt_detached_final(st_, m, mlen_max, written, mac, maclen); +} + +#endif /* AEGIS_OMIT_INCREMENTAL */ + +AEGIS_API +void +aegis256x4_stream(uint8_t *out, size_t len, const uint8_t *npub, const uint8_t *k) +{ + implementation_256x4->stream(out, len, npub, k); +} + +AEGIS_API +void +aegis256x4_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_256x4->encrypt_unauthenticated(c, m, mlen, npub, k); +} + +AEGIS_API +void +aegis256x4_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, const uint8_t *npub, + const uint8_t *k) +{ + implementation_256x4->decrypt_unauthenticated(m, c, clen, npub, k); +} + +#ifndef AEGIS_OMIT_MAC_API + +AEGIS_API +void +aegis256x4_mac_init(aegis256x4_mac_state *st_, const uint8_t *k, const uint8_t *npub) +{ + implementation_256x4->state_mac_init(st_, npub, k); +} + +AEGIS_API +int +aegis256x4_mac_update(aegis256x4_mac_state *st_, const uint8_t *m, size_t mlen) +{ + return implementation_256x4->state_mac_update(st_, m, mlen); +} + +AEGIS_API +int +aegis256x4_mac_final(aegis256x4_mac_state *st_, uint8_t *mac, size_t maclen) +{ + if (maclen != 16 && maclen != 32) { + errno = EINVAL; + return -1; + } + return implementation_256x4->state_mac_final(st_, mac, maclen); +} + +AEGIS_API +int +aegis256x4_mac_verify(aegis256x4_mac_state *st_, const uint8_t *mac, size_t maclen) +{ + uint8_t expected_mac[32]; + + switch (maclen) { + case 16: + implementation_256x4->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_16(expected_mac, mac); + case 32: + implementation_256x4->state_mac_final(st_, expected_mac, maclen); + return aegis_verify_32(expected_mac, mac); + default: + errno = EINVAL; + return -1; + } +} + +AEGIS_API +void +aegis256x4_mac_reset(aegis256x4_mac_state *st_) +{ + implementation_256x4->state_mac_reset(st_); +} + +AEGIS_API +void +aegis256x4_mac_state_clone(aegis256x4_mac_state *dst, const aegis256x4_mac_state *src) +{ + implementation_256x4->state_mac_clone(dst, src); +} + +#endif /* AEGIS_OMIT_MAC_API */ + +AEGIS_PRIVATE +int +aegis256x4_pick_best_implementation(void) +{ + implementation_256x4 = &aegis256x4_soft_implementation; + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NEON + if (aegis_runtime_has_armcrypto()) { + implementation_256x4 = &aegis256x4_armcrypto_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NI +# ifdef HAVE_VAESINTRIN_H + if (aegis_runtime_has_vaes() && aegis_runtime_has_avx512f()) { + implementation_256x4 = &aegis256x4_avx512_implementation; + return 0; + } + if (aegis_runtime_has_vaes() && aegis_runtime_has_avx2()) { + implementation_256x4 = &aegis256x4_avx2_implementation; + return 0; + } +# endif + if (aegis_runtime_has_aesni() && aegis_runtime_has_avx()) { + implementation_256x4 = &aegis256x4_aesni_implementation; + return 0; + } +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_ALTIVEC + if (aegis_runtime_has_altivec()) { + implementation_256x4 = &aegis256x4_altivec_implementation; + return 0; + } +#endif + + return 0; /* LCOV_EXCL_LINE */ +} +/*** End of #include "aegis256x4/aegis256x4.c" ***/ + + +#if defined(__GNUC__) +# pragma GCC pop_options +#endif +/*** End of #include "aegis/libaegis.c" ***/ + +/* #include "argon2/libargon2.c" */ +/*** Begin of #include "argon2/libargon2.c" ***/ +#ifndef ARGON2_API +#define ARGON2_API static +#endif + +#ifndef ARGON2_EXTERN +#define ARGON2_EXTERN static +#endif + +#ifndef ARGON2_PRIVATE +#define ARGON2_PRIVATE static +#endif + +#ifndef ARGON2_PUBLIC +#define ARGON2_PUBLIC static +#endif + +#ifndef ARGON2_LOCAL +#define ARGON2_LOCAL static +#endif + +#ifndef BLAKE2B_API +#define BLAKE2B_API static +#endif + +/* #include "src/blake2/blake2b.c" */ +/*** Begin of #include "src/blake2/blake2b.c" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#include +#include +#include + +/* #include "blake2.h" */ +/*** Begin of #include "blake2.h" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef PORTABLE_BLAKE2_H +#define PORTABLE_BLAKE2_H + +/* #include "argon2.h" */ +/*** Begin of #include "argon2.h" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef ARGON2_H +#define ARGON2_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Symbols visibility control */ +#ifdef A2_VISCTL +#define ARGON2_PUBLIC __attribute__((visibility("default"))) +#define ARGON2_LOCAL __attribute__ ((visibility ("hidden"))) +#elif defined(_MSC_VER) +#ifndef ARGON2_PUBLIC +#define ARGON2_PUBLIC __declspec(dllexport) +#endif +#ifndef ARGON2_LOCAL +#define ARGON2_LOCAL +#endif +#else +#ifndef ARGON2_PUBLIC +#define ARGON2_PUBLIC +#endif +#ifndef ARGON2_LOCAL +#define ARGON2_LOCAL +#endif +#endif +#ifndef ARGON2_EXTERN +#define ARGON2_EXTERN extern +#endif + +/* + * Argon2 input parameter restrictions + */ + +/* Minimum and maximum number of lanes (degree of parallelism) */ +#define ARGON2_MIN_LANES UINT32_C(1) +#define ARGON2_MAX_LANES UINT32_C(0xFFFFFF) + +/* Minimum and maximum number of threads */ +#define ARGON2_MIN_THREADS UINT32_C(1) +#define ARGON2_MAX_THREADS UINT32_C(0xFFFFFF) + +/* Number of synchronization points between lanes per pass */ +#define ARGON2_SYNC_POINTS UINT32_C(4) + +/* Minimum and maximum digest size in bytes */ +#define ARGON2_MIN_OUTLEN UINT32_C(4) +#define ARGON2_MAX_OUTLEN UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */ +#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */ + +#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b)) +/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */ +#define ARGON2_MAX_MEMORY_BITS \ + ARGON2_MIN(UINT32_C(32), (sizeof(void *) * CHAR_BIT - 10 - 1)) +#define ARGON2_MAX_MEMORY \ + ARGON2_MIN(UINT32_C(0xFFFFFFFF), UINT64_C(1) << ARGON2_MAX_MEMORY_BITS) + +/* Minimum and maximum number of passes */ +#define ARGON2_MIN_TIME UINT32_C(1) +#define ARGON2_MAX_TIME UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum password length in bytes */ +#define ARGON2_MIN_PWD_LENGTH UINT32_C(0) +#define ARGON2_MAX_PWD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum associated data length in bytes */ +#define ARGON2_MIN_AD_LENGTH UINT32_C(0) +#define ARGON2_MAX_AD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum salt length in bytes */ +#define ARGON2_MIN_SALT_LENGTH UINT32_C(8) +#define ARGON2_MAX_SALT_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum key length in bytes */ +#define ARGON2_MIN_SECRET UINT32_C(0) +#define ARGON2_MAX_SECRET UINT32_C(0xFFFFFFFF) + +/* Flags to determine which fields are securely wiped (default = no wipe). */ +#define ARGON2_DEFAULT_FLAGS UINT32_C(0) +#define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0) +#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1) + +/* Global flag to determine if we are wiping internal memory buffers. This flag + * is defined in core.c and defaults to 1 (wipe internal memory). */ +ARGON2_EXTERN int FLAG_clear_internal_memory; + +/* Error codes */ +typedef enum Argon2_ErrorCodes { + ARGON2_OK = 0, + + ARGON2_OUTPUT_PTR_NULL = -1, + + ARGON2_OUTPUT_TOO_SHORT = -2, + ARGON2_OUTPUT_TOO_LONG = -3, + + ARGON2_PWD_TOO_SHORT = -4, + ARGON2_PWD_TOO_LONG = -5, + + ARGON2_SALT_TOO_SHORT = -6, + ARGON2_SALT_TOO_LONG = -7, + + ARGON2_AD_TOO_SHORT = -8, + ARGON2_AD_TOO_LONG = -9, + + ARGON2_SECRET_TOO_SHORT = -10, + ARGON2_SECRET_TOO_LONG = -11, + + ARGON2_TIME_TOO_SMALL = -12, + ARGON2_TIME_TOO_LARGE = -13, + + ARGON2_MEMORY_TOO_LITTLE = -14, + ARGON2_MEMORY_TOO_MUCH = -15, + + ARGON2_LANES_TOO_FEW = -16, + ARGON2_LANES_TOO_MANY = -17, + + ARGON2_PWD_PTR_MISMATCH = -18, /* NULL ptr with non-zero length */ + ARGON2_SALT_PTR_MISMATCH = -19, /* NULL ptr with non-zero length */ + ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */ + ARGON2_AD_PTR_MISMATCH = -21, /* NULL ptr with non-zero length */ + + ARGON2_MEMORY_ALLOCATION_ERROR = -22, + + ARGON2_FREE_MEMORY_CBK_NULL = -23, + ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24, + + ARGON2_INCORRECT_PARAMETER = -25, + ARGON2_INCORRECT_TYPE = -26, + + ARGON2_OUT_PTR_MISMATCH = -27, + + ARGON2_THREADS_TOO_FEW = -28, + ARGON2_THREADS_TOO_MANY = -29, + + ARGON2_MISSING_ARGS = -30, + + ARGON2_ENCODING_FAIL = -31, + + ARGON2_DECODING_FAIL = -32, + + ARGON2_THREAD_FAIL = -33, + + ARGON2_DECODING_LENGTH_FAIL = -34, + + ARGON2_VERIFY_MISMATCH = -35 +} argon2_error_codes; + +/* Memory allocator types --- for external allocation */ +typedef int (*allocate_fptr)(uint8_t **memory, size_t bytes_to_allocate); +typedef void (*deallocate_fptr)(uint8_t *memory, size_t bytes_to_allocate); + +/* Argon2 external data structures */ + +/* + ***** + * Context: structure to hold Argon2 inputs: + * output array and its length, + * password and its length, + * salt and its length, + * secret and its length, + * associated data and its length, + * number of passes, amount of used memory (in KBytes, can be rounded up a bit) + * number of parallel threads that will be run. + * All the parameters above affect the output hash value. + * Additionally, two function pointers can be provided to allocate and + * deallocate the memory (if NULL, memory will be allocated internally). + * Also, three flags indicate whether to erase password, secret as soon as they + * are pre-hashed (and thus not needed anymore), and the entire memory + ***** + * Simplest situation: you have output array out[8], password is stored in + * pwd[32], salt is stored in salt[16], you do not have keys nor associated + * data. You need to spend 1 GB of RAM and you run 5 passes of Argon2d with + * 4 parallel lanes. + * You want to erase the password, but you're OK with last pass not being + * erased. You want to use the default memory allocator. + * Then you initialize: + Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false) + */ +typedef struct Argon2_Context { + uint8_t *out; /* output array */ + uint32_t outlen; /* digest length */ + + uint8_t *pwd; /* password array */ + uint32_t pwdlen; /* password length */ + + uint8_t *salt; /* salt array */ + uint32_t saltlen; /* salt length */ + + uint8_t *secret; /* key array */ + uint32_t secretlen; /* key length */ + + uint8_t *ad; /* associated data array */ + uint32_t adlen; /* associated data length */ + + uint32_t t_cost; /* number of passes */ + uint32_t m_cost; /* amount of memory requested (KB) */ + uint32_t lanes; /* number of lanes */ + uint32_t threads; /* maximum number of threads */ + + uint32_t version; /* version number */ + + allocate_fptr allocate_cbk; /* pointer to memory allocator */ + deallocate_fptr free_cbk; /* pointer to memory deallocator */ + + uint32_t flags; /* array of bool options */ +} argon2_context; + +/* Argon2 primitive type */ +typedef enum Argon2_type { + Argon2_d = 0, + Argon2_i = 1, + Argon2_id = 2 +} argon2_type; + +/* Version of the algorithm */ +typedef enum Argon2_version { + ARGON2_VERSION_10 = 0x10, + ARGON2_VERSION_13 = 0x13, + ARGON2_VERSION_NUMBER = ARGON2_VERSION_13 +} argon2_version; + +/* + * Function that gives the string representation of an argon2_type. + * @param type The argon2_type that we want the string for + * @param uppercase Whether the string should have the first letter uppercase + * @return NULL if invalid type, otherwise the string representation. + */ +ARGON2_PUBLIC const char *argon2_type2string(argon2_type type, int uppercase); + +/* + * Function that performs memory-hard hashing with certain degree of parallelism + * @param context Pointer to the Argon2 internal structure + * @return Error code if smth is wrong, ARGON2_OK otherwise + */ +ARGON2_PUBLIC int argon2_ctx(argon2_context *context, argon2_type type); + +/** + * Hashes a password with Argon2i, producing an encoded hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hashlen Desired length of the hash in bytes + * @param encoded Buffer where to write the encoded hash + * @param encodedlen Size of the buffer (thus max size of the encoded hash) + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_hash_encoded(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, + const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, + const size_t hashlen, char *encoded, + const size_t encodedlen); + +/** + * Hashes a password with Argon2i, producing a raw hash at @hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hash Buffer where to write the raw hash - updated by the function + * @param hashlen Desired length of the hash in bytes + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen); + +ARGON2_PUBLIC int argon2d_hash_encoded(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, + const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, + const size_t hashlen, char *encoded, + const size_t encodedlen); + +ARGON2_PUBLIC int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen); + +ARGON2_PUBLIC int argon2id_hash_encoded(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, + const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, + const size_t hashlen, char *encoded, + const size_t encodedlen); + +ARGON2_PUBLIC int argon2id_hash_raw(const uint32_t t_cost, + const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, + const size_t hashlen, char *encoded, + const size_t encodedlen, argon2_type type, + const uint32_t version); + +/** + * Verifies a password against an encoded string + * Encoded string is restricted as in validate_inputs() + * @param encoded String encoding parameters, salt, hash + * @param pwd Pointer to password + * @pre Returns ARGON2_OK if successful + */ +ARGON2_PUBLIC int argon2i_verify(const char *encoded, const void *pwd, + const size_t pwdlen); + +ARGON2_PUBLIC int argon2d_verify(const char *encoded, const void *pwd, + const size_t pwdlen); + +ARGON2_PUBLIC int argon2id_verify(const char *encoded, const void *pwd, + const size_t pwdlen); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_verify(const char *encoded, const void *pwd, + const size_t pwdlen, argon2_type type); + +/** + * Argon2d: Version of Argon2 that picks memory blocks depending + * on the password and salt. Only for side-channel-free + * environment!! + ***** + * @param context Pointer to current Argon2 context + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2d_ctx(argon2_context *context); + +/** + * Argon2i: Version of Argon2 that picks memory blocks + * independent on the password and salt. Good for side-channels, + * but worse w.r.t. tradeoff attacks if only one pass is used. + ***** + * @param context Pointer to current Argon2 context + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2i_ctx(argon2_context *context); + +/** + * Argon2id: Version of Argon2 where the first half-pass over memory is + * password-independent, the rest are password-dependent (on the password and + * salt). OK against side channels (they reduce to 1/2-pass Argon2i), and + * better with w.r.t. tradeoff attacks (similar to Argon2d). + ***** + * @param context Pointer to current Argon2 context + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2id_ctx(argon2_context *context); + +/** + * Verify if a given password is correct for Argon2d hashing + * @param context Pointer to current Argon2 context + * @param hash The password hash to verify. The length of the hash is + * specified by the context outlen member + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2d_verify_ctx(argon2_context *context, const char *hash); + +/** + * Verify if a given password is correct for Argon2i hashing + * @param context Pointer to current Argon2 context + * @param hash The password hash to verify. The length of the hash is + * specified by the context outlen member + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2i_verify_ctx(argon2_context *context, const char *hash); + +/** + * Verify if a given password is correct for Argon2id hashing + * @param context Pointer to current Argon2 context + * @param hash The password hash to verify. The length of the hash is + * specified by the context outlen member + * @return Zero if successful, a non zero error code otherwise + */ +ARGON2_PUBLIC int argon2id_verify_ctx(argon2_context *context, + const char *hash); + +/* generic function underlying the above ones */ +ARGON2_PUBLIC int argon2_verify_ctx(argon2_context *context, const char *hash, + argon2_type type); + +/** + * Get the associated error message for given error code + * @return The error message associated with the given error code + */ +ARGON2_PUBLIC const char *argon2_error_message(int error_code); + +/** + * Returns the encoded hash length for the given input parameters + * @param t_cost Number of iterations + * @param m_cost Memory usage in kibibytes + * @param parallelism Number of threads; used to compute lanes + * @param saltlen Salt size in bytes + * @param hashlen Hash size in bytes + * @param type The argon2_type that we want the encoded length for + * @return The encoded hash length in bytes + */ +ARGON2_PUBLIC size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, + uint32_t parallelism, uint32_t saltlen, + uint32_t hashlen, argon2_type type); + +#if defined(__cplusplus) +} +#endif + +#endif +/*** End of #include "argon2.h" ***/ + + +#if defined(__cplusplus) +extern "C" { +#endif + +enum blake2b_constant { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +#pragma pack(push, 1) +typedef struct __blake2b_param { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint64_t node_offset; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ +} blake2b_param; +#pragma pack(pop) + +typedef struct __blake2b_state { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + unsigned buflen; + unsigned outlen; + uint8_t last_node; +} blake2b_state; + +/* Ensure param structs have not been wrongly padded */ +/* Poor man's static_assert */ +enum { + blake2_size_check_0 = 1 / !!(CHAR_BIT == 8), + blake2_size_check_2 = + 1 / !!(sizeof(blake2b_param) == sizeof(uint64_t) * CHAR_BIT) +}; + +/* Streaming API */ +ARGON2_LOCAL int blake2b_init(blake2b_state *S, size_t outlen); +ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, + size_t keylen); +ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P); +ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, size_t inlen); +ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, size_t outlen); + +/* Simple API */ +ARGON2_LOCAL int blake2b(void *out, size_t outlen, const void *in, size_t inlen, + const void *key, size_t keylen); + +/* Argon2 Team - Begin Code */ +ARGON2_LOCAL int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen); +/* Argon2 Team - End Code */ + +#if defined(__cplusplus) +} +#endif + +#endif +/*** End of #include "blake2.h" ***/ + +/* #include "blake2-impl.h" */ +/*** Begin of #include "blake2-impl.h" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef PORTABLE_BLAKE2_IMPL_H +#define PORTABLE_BLAKE2_IMPL_H + +#include +#include + +#ifdef _WIN32 +#define BLAKE2_INLINE __inline +#elif defined(__GNUC__) || defined(__clang__) +#define BLAKE2_INLINE __inline__ +#else +#define BLAKE2_INLINE +#endif + +/* Argon2 Team - Begin Code */ +/* + Not an exhaustive list, but should cover the majority of modern platforms + Additionally, the code will always be correct---this is only a performance + tweak. +*/ +#if (defined(__BYTE_ORDER__) && \ + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ + defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \ + defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) || \ + defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_ARM) +#define NATIVE_LITTLE_ENDIAN +#endif +/* Argon2 Team - End Code */ + +static BLAKE2_INLINE uint32_t _blake2b_load32(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = (const uint8_t *)src; + uint32_t w = *p++; + w |= (uint32_t)(*p++) << 8; + w |= (uint32_t)(*p++) << 16; + w |= (uint32_t)(*p++) << 24; + return w; +#endif +} + +static BLAKE2_INLINE uint64_t _blake2b_load64(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + w |= (uint64_t)(*p++) << 48; + w |= (uint64_t)(*p++) << 56; + return w; +#endif +} + +static BLAKE2_INLINE void _blake2b_store32(void *dst, uint32_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +static BLAKE2_INLINE void _blake2b_store64(void *dst, uint64_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +static BLAKE2_INLINE uint64_t _blake2b_load48(const void *src) { + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + return w; +} + +static BLAKE2_INLINE void _blake2b_store48(void *dst, uint64_t w) { + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +} + +static BLAKE2_INLINE uint32_t _blake2b_rotr32(const uint32_t w, const unsigned c) { + return (w >> c) | (w << (32 - c)); +} + +static BLAKE2_INLINE uint64_t _blake2b_rotr64(const uint64_t w, const unsigned c) { + return (w >> c) | (w << (64 - c)); +} + +ARGON2_PRIVATE +void _argon2_clear_internal_memory(void *v, size_t n); + +#endif +/*** End of #include "blake2-impl.h" ***/ + + +static const uint64_t blake2b_IV[8] = { + UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b), + UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1), + UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f), + UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179)}; + +static const unsigned int blake2b_sigma[12][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, +}; + +static BLAKE2_INLINE void blake2b_set_lastnode(blake2b_state *BS) { + BS->f[1] = (uint64_t)-1; +} + +static BLAKE2_INLINE void blake2b_set_lastblock(blake2b_state *BS) { + if (BS->last_node) { + blake2b_set_lastnode(BS); + } + BS->f[0] = (uint64_t)-1; +} + +static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *BS, + uint64_t inc) { + BS->t[0] += inc; + BS->t[1] += (BS->t[0] < inc); +} + +static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *BS) { + _argon2_clear_internal_memory(BS, sizeof(*BS)); /* wipe */ + blake2b_set_lastblock(BS); /* invalidate for further use */ +} + +static BLAKE2_INLINE void blake2b_init0(blake2b_state *BS) { + memset(BS, 0, sizeof(*BS)); + memcpy(BS->h, blake2b_IV, sizeof(BS->h)); +} + +BLAKE2B_API +int blake2b_init_param(blake2b_state *BS, const blake2b_param *BP) { + const unsigned char *p = (const unsigned char *)BP; + unsigned int i; + + if (NULL == BP || NULL == BS) { + return -1; + } + + blake2b_init0(BS); + /* IV XOR Parameter Block */ + for (i = 0; i < 8; ++i) { + BS->h[i] ^= _blake2b_load64(&p[i * sizeof(BS->h[i])]); + } + BS->outlen = BP->digest_length; + return 0; +} + +/* Sequential blake2b initialization */ +BLAKE2B_API +int blake2b_init(blake2b_state *BS, size_t outlen) { + blake2b_param BP; + + if (BS == NULL) { + return -1; + } + + if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { + blake2b_invalidate_state(BS); + return -1; + } + + /* Setup Parameter Block for unkeyed BLAKE2 */ + BP.digest_length = (uint8_t)outlen; + BP.key_length = 0; + BP.fanout = 1; + BP.depth = 1; + BP.leaf_length = 0; + BP.node_offset = 0; + BP.node_depth = 0; + BP.inner_length = 0; + memset(BP.reserved, 0, sizeof(BP.reserved)); + memset(BP.salt, 0, sizeof(BP.salt)); + memset(BP.personal, 0, sizeof(BP.personal)); + + return blake2b_init_param(BS, &BP); +} + +BLAKE2B_API +int blake2b_init_key(blake2b_state *BS, size_t outlen, const void *key, + size_t keylen) { + blake2b_param BP; + + if (BS == NULL) { + return -1; + } + + if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { + blake2b_invalidate_state(BS); + return -1; + } + + if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) { + blake2b_invalidate_state(BS); + return -1; + } + + /* Setup Parameter Block for keyed BLAKE2 */ + BP.digest_length = (uint8_t)outlen; + BP.key_length = (uint8_t)keylen; + BP.fanout = 1; + BP.depth = 1; + BP.leaf_length = 0; + BP.node_offset = 0; + BP.node_depth = 0; + BP.inner_length = 0; + memset(BP.reserved, 0, sizeof(BP.reserved)); + memset(BP.salt, 0, sizeof(BP.salt)); + memset(BP.personal, 0, sizeof(BP.personal)); + + if (blake2b_init_param(BS, &BP) < 0) { + blake2b_invalidate_state(BS); + return -1; + } + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset(block, 0, BLAKE2B_BLOCKBYTES); + memcpy(block, key, keylen); + blake2b_update(BS, block, BLAKE2B_BLOCKBYTES); + /* Burn the key from stack */ + _argon2_clear_internal_memory(block, BLAKE2B_BLOCKBYTES); + } + return 0; +} + +static void blake2b_compress(blake2b_state *BS, const uint8_t *block) { + uint64_t m[16]; + uint64_t v[16]; + unsigned int i, r; + + for (i = 0; i < 16; ++i) { + m[i] = _blake2b_load64(block + i * sizeof(m[i])); + } + + for (i = 0; i < 8; ++i) { + v[i] = BS->h[i]; + } + + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ BS->t[0]; + v[13] = blake2b_IV[5] ^ BS->t[1]; + v[14] = blake2b_IV[6] ^ BS->f[0]; + v[15] = blake2b_IV[7] ^ BS->f[1]; + +#define BLAKE2B_G(r, i, a, b, c, d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ + d = _blake2b_rotr64(d ^ a, 32); \ + c = c + d; \ + b = _blake2b_rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ + d = _blake2b_rotr64(d ^ a, 16); \ + c = c + d; \ + b = _blake2b_rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define BLAKE2B_ROUND(r) \ + do { \ + BLAKE2B_G(r, 0, v[0], v[4], v[8], v[12]); \ + BLAKE2B_G(r, 1, v[1], v[5], v[9], v[13]); \ + BLAKE2B_G(r, 2, v[2], v[6], v[10], v[14]); \ + BLAKE2B_G(r, 3, v[3], v[7], v[11], v[15]); \ + BLAKE2B_G(r, 4, v[0], v[5], v[10], v[15]); \ + BLAKE2B_G(r, 5, v[1], v[6], v[11], v[12]); \ + BLAKE2B_G(r, 6, v[2], v[7], v[8], v[13]); \ + BLAKE2B_G(r, 7, v[3], v[4], v[9], v[14]); \ + } while ((void)0, 0) + + for (r = 0; r < 12; ++r) { + BLAKE2B_ROUND(r); + } + + for (i = 0; i < 8; ++i) { + BS->h[i] = BS->h[i] ^ v[i] ^ v[i + 8]; + } + +#undef BLAKE2B_G +#undef BLAKE2B_ROUND +} + +BLAKE2B_API +int blake2b_update(blake2b_state *BS, const void *in, size_t inlen) { + const uint8_t *pin = (const uint8_t *)in; + + if (inlen == 0) { + return 0; + } + + /* Sanity check */ + if (BS == NULL || in == NULL) { + return -1; + } + + /* Is this a reused state? */ + if (BS->f[0] != 0) { + return -1; + } + + if (BS->buflen + inlen > BLAKE2B_BLOCKBYTES) { + /* Complete current block */ + size_t left = BS->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + memcpy(&BS->buf[left], pin, fill); + blake2b_increment_counter(BS, BLAKE2B_BLOCKBYTES); + blake2b_compress(BS, BS->buf); + BS->buflen = 0; + inlen -= fill; + pin += fill; + /* Avoid buffer copies when possible */ + while (inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(BS, BLAKE2B_BLOCKBYTES); + blake2b_compress(BS, pin); + inlen -= BLAKE2B_BLOCKBYTES; + pin += BLAKE2B_BLOCKBYTES; + } + } + memcpy(&BS->buf[BS->buflen], pin, inlen); + BS->buflen += (unsigned int)inlen; + return 0; +} + +BLAKE2B_API +int blake2b_final(blake2b_state *BS, void *out, size_t outlen) { + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + unsigned int i; + + /* Sanity checks */ + if (BS == NULL || out == NULL || outlen < BS->outlen) { + return -1; + } + + /* Is this a reused state? */ + if (BS->f[0] != 0) { + return -1; + } + + blake2b_increment_counter(BS, BS->buflen); + blake2b_set_lastblock(BS); + memset(&BS->buf[BS->buflen], 0, BLAKE2B_BLOCKBYTES - BS->buflen); /* Padding */ + blake2b_compress(BS, BS->buf); + + for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */ + _blake2b_store64(buffer + sizeof(BS->h[i]) * i, BS->h[i]); + } + + memcpy(out, buffer, BS->outlen); + _argon2_clear_internal_memory(buffer, sizeof(buffer)); + _argon2_clear_internal_memory(BS->buf, sizeof(BS->buf)); + _argon2_clear_internal_memory(BS->h, sizeof(BS->h)); + return 0; +} + +BLAKE2B_API +int blake2b(void *out, size_t outlen, const void *in, size_t inlen, + const void *key, size_t keylen) { + blake2b_state BS; + int ret = -1; + + /* Verify parameters */ + if (NULL == in && inlen > 0) { + goto fail; + } + + if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) { + goto fail; + } + + if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) { + goto fail; + } + + if (keylen > 0) { + if (blake2b_init_key(&BS, outlen, key, keylen) < 0) { + goto fail; + } + } else { + if (blake2b_init(&BS, outlen) < 0) { + goto fail; + } + } + + if (blake2b_update(&BS, in, inlen) < 0) { + goto fail; + } + ret = blake2b_final(&BS, out, outlen); + +fail: + _argon2_clear_internal_memory(&BS, sizeof(BS)); + return ret; +} + +/* Argon2 Team - Begin Code */ +BLAKE2B_API +int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) { + uint8_t *out = (uint8_t *)pout; + blake2b_state blake_state; + uint8_t outlen_bytes[sizeof(uint32_t)] = {0}; + int ret = -1; + + if (outlen > UINT32_MAX) { + goto fail; + } + + /* Ensure little-endian byte order! */ + _blake2b_store32(outlen_bytes, (uint32_t)outlen); + +#define BLAKE2B_TRY(statement) \ + do { \ + ret = statement; \ + if (ret < 0) { \ + goto fail; \ + } \ + } while ((void)0, 0) + + if (outlen <= BLAKE2B_OUTBYTES) { + BLAKE2B_TRY(blake2b_init(&blake_state, outlen)); + BLAKE2B_TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + BLAKE2B_TRY(blake2b_update(&blake_state, in, inlen)); + BLAKE2B_TRY(blake2b_final(&blake_state, out, outlen)); + } else { + uint32_t toproduce; + uint8_t out_buffer[BLAKE2B_OUTBYTES]; + uint8_t in_buffer[BLAKE2B_OUTBYTES]; + BLAKE2B_TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES)); + BLAKE2B_TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + BLAKE2B_TRY(blake2b_update(&blake_state, in, inlen)); + BLAKE2B_TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES)); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce = (uint32_t)outlen - BLAKE2B_OUTBYTES / 2; + + while (toproduce > BLAKE2B_OUTBYTES) { + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + BLAKE2B_TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer, + BLAKE2B_OUTBYTES, NULL, 0)); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce -= BLAKE2B_OUTBYTES / 2; + } + + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + BLAKE2B_TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL, + 0)); + memcpy(out, out_buffer, toproduce); + } +fail: + _argon2_clear_internal_memory(&blake_state, sizeof(blake_state)); + return ret; +#undef BLAKE2B_TRY +} +/* Argon2 Team - End Code */ +/*** End of #include "src/blake2/blake2b.c" ***/ + +/* #include "src/argon2.c" */ +/*** Begin of #include "src/argon2.c" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#include +#include +#include + +/* #include "argon2.h" */ + +/* #include "encoding.h" */ +/*** Begin of #include "encoding.h" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef ARGON2_ENCODING_H +#define ARGON2_ENCODING_H +/* #include "argon2.h" */ + + +#define ARGON2_MAX_DECODED_LANES UINT32_C(255) +#define ARGON2_MIN_DECODED_SALT_LEN UINT32_C(8) +#define ARGON2_MIN_DECODED_OUT_LEN UINT32_C(12) + +/* +* encode an Argon2 hash string into the provided buffer. 'dst_len' +* contains the size, in characters, of the 'dst' buffer; if 'dst_len' +* is less than the number of required characters (including the +* terminating 0), then this function returns ARGON2_ENCODING_ERROR. +* +* on success, ARGON2_OK is returned. +*/ +ARGON2_PRIVATE +int _argon2_encode_string(char *dst, size_t dst_len, argon2_context *ctx, + argon2_type type); + +/* +* Decodes an Argon2 hash string into the provided structure 'ctx'. +* The only fields that must be set prior to this call are ctx.saltlen and +* ctx.outlen (which must be the maximal salt and out length values that are +* allowed), ctx.salt and ctx.out (which must be buffers of the specified +* length), and ctx.pwd and ctx.pwdlen which must hold a valid password. +* +* Invalid input string causes an error. On success, the ctx is valid and all +* fields have been initialized. +* +* Returned value is ARGON2_OK on success, other ARGON2_ codes on error. +*/ +ARGON2_PRIVATE +int _argon2_decode_string(argon2_context *ctx, const char *str, argon2_type type); + +/* Returns the length of the encoded byte stream with length len */ +ARGON2_PRIVATE +size_t _argon2_b64len(uint32_t len); + +/* Returns the length of the encoded number num */ +ARGON2_PRIVATE +size_t _argon2_numlen(uint32_t num); + +#endif +/*** End of #include "encoding.h" ***/ + +/* #include "core.h" */ +/*** Begin of #include "core.h" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef ARGON2_CORE_H +#define ARGON2_CORE_H + +/* #include "argon2.h" */ + + +#define CONST_CAST(x) (x)(uintptr_t) + +/**********************Argon2 internal constants*******************************/ + +enum argon2_core_constants { + /* Memory block size in bytes */ + ARGON2_BLOCK_SIZE = 1024, + ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8, + ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16, + ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32, + ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64, + + /* Number of pseudo-random values generated by one call to Blake in Argon2i + to + generate reference block positions */ + ARGON2_ADDRESSES_IN_BLOCK = 128, + + /* Pre-hashing digest length and its extension*/ + ARGON2_PREHASH_DIGEST_LENGTH = 64, + ARGON2_PREHASH_SEED_LENGTH = 72 +}; + +/*************************Argon2 internal data types***********************/ + +/* + * Structure for the (1KB) memory block implemented as 128 64-bit words. + * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no + * bounds checking). + */ +typedef struct block_ { uint64_t v[ARGON2_QWORDS_IN_BLOCK]; } block; + +/*****************Functions that work with the block******************/ + +/* Initialize each byte of the block with @in */ +ARGON2_PRIVATE +void _argon2_init_block_value(block *b, uint8_t in); + +/* Copy block @src to block @dst */ +ARGON2_PRIVATE +void _argon2_copy_block(block *dst, const block *src); + +/* XOR @src onto @dst bytewise */ +ARGON2_PRIVATE +void _argon2_xor_block(block *dst, const block *src); + +/* + * Argon2 instance: memory pointer, number of passes, amount of memory, type, + * and derived values. + * Used to evaluate the number and location of blocks to construct in each + * thread + */ +typedef struct Argon2_instance_t { + block *memory; /* Memory pointer */ + uint32_t version; + uint32_t passes; /* Number of passes */ + uint32_t memory_blocks; /* Number of blocks in memory */ + uint32_t segment_length; + uint32_t lane_length; + uint32_t lanes; + uint32_t threads; + argon2_type type; + int print_internals; /* whether to print the memory blocks */ + argon2_context *context_ptr; /* points back to original context */ +} argon2_instance_t; + +/* + * Argon2 position: where we construct the block right now. Used to distribute + * work between threads. + */ +typedef struct Argon2_position_t { + uint32_t pass; + uint32_t lane; + uint8_t slice; + uint32_t index; +} argon2_position_t; + +/*Struct that holds the inputs for thread handling FillSegment*/ +typedef struct Argon2_thread_data { + argon2_instance_t *instance_ptr; + argon2_position_t pos; +} argon2_thread_data; + +/*************************Argon2 core functions********************************/ + +/* Allocates memory to the given pointer, uses the appropriate allocator as + * specified in the context. Total allocated memory is num*size. + * @param context argon2_context which specifies the allocator + * @param memory pointer to the pointer to the memory + * @param size the size in bytes for each element to be allocated + * @param num the number of elements to be allocated + * @return ARGON2_OK if @memory is a valid pointer and memory is allocated + */ +ARGON2_PRIVATE +int _argon2_allocate_memory(const argon2_context *context, uint8_t **memory, + size_t num, size_t size); + +/* + * Frees memory at the given pointer, uses the appropriate deallocator as + * specified in the context. Also cleans the memory using clear_internal_memory. + * @param context argon2_context which specifies the deallocator + * @param memory pointer to buffer to be freed + * @param size the size in bytes for each element to be deallocated + * @param num the number of elements to be deallocated + */ +ARGON2_PRIVATE +void _argon2_free_memory(const argon2_context *context, uint8_t *memory, + size_t num, size_t size); + +/* Function that securely cleans the memory. This ignores any flags set + * regarding clearing memory. Usually one just calls clear_internal_memory. + * @param mem Pointer to the memory + * @param s Memory size in bytes + */ +ARGON2_PRIVATE +void _argon2_secure_wipe_memory(void *v, size_t n); + +/* Function that securely clears the memory if FLAG_clear_internal_memory is + * set. If the flag isn't set, this function does nothing. + * @param mem Pointer to the memory + * @param s Memory size in bytes + */ +ARGON2_PRIVATE +void _argon2_clear_internal_memory(void *v, size_t n); + +/* + * Computes absolute position of reference block in the lane following a skewed + * distribution and using a pseudo-random value as input + * @param instance Pointer to the current instance + * @param position Pointer to the current position + * @param pseudo_rand 32-bit pseudo-random value used to determine the position + * @param same_lane Indicates if the block will be taken from the current lane. + * If so we can reference the current segment + * @pre All pointers must be valid + */ +ARGON2_PRIVATE +uint32_t _argon2_index_alpha(const argon2_instance_t *instance, + const argon2_position_t *position, uint32_t pseudo_rand, + int same_lane); + +/* + * Function that validates all inputs against predefined restrictions and return + * an error code + * @param context Pointer to current Argon2 context + * @return ARGON2_OK if everything is all right, otherwise one of error codes + * (all defined in + */ +ARGON2_PRIVATE +int _argon2_validate_inputs(const argon2_context *context); + +/* + * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears + * password and secret if needed + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param blockhash Buffer for pre-hashing digest + * @param type Argon2 type + * @pre @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes + * allocated + */ +ARGON2_PRIVATE +void _argon2_initial_hash(uint8_t *blockhash, argon2_context *context, + argon2_type type); + +/* + * Function creates first 2 blocks per lane + * @param instance Pointer to the current instance + * @param blockhash Pointer to the pre-hashing digest + * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values + */ +ARGON2_PRIVATE +void _argon2_fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance); + +/* + * Function allocates memory, hashes the inputs with Blake, and creates first + * two blocks. Returns the pointer to the main memory with 2 blocks per lane + * initialized + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param instance Current Argon2 instance + * @return Zero if successful, -1 if memory failed to allocate. @context->state + * will be modified if successful. + */ +ARGON2_PRIVATE +int _argon2_initialize(argon2_instance_t *instance, argon2_context *context); + +/* + * XORing the last block of each lane, hashing it, making the tag. Deallocates + * the memory. + * @param context Pointer to current Argon2 context (use only the out parameters + * from it) + * @param instance Pointer to current instance of Argon2 + * @pre instance->state must point to necessary amount of memory + * @pre context->out must point to outlen bytes of memory + * @pre if context->free_cbk is not NULL, it should point to a function that + * deallocates memory + */ +ARGON2_PRIVATE +void _argon2_finalize(const argon2_context *context, argon2_instance_t *instance); + +/* + * Function that fills the segment using previous segments also from other + * threads + * @param context current context + * @param instance Pointer to the current instance + * @param position Current position + * @pre all block pointers must be valid + */ +ARGON2_PRIVATE +void _argon2_fill_segment(const argon2_instance_t *instance, + argon2_position_t position); + +/* + * Function that fills the entire memory t_cost times based on the first two + * blocks in each lane + * @param instance Pointer to the current instance + * @return ARGON2_OK if successful, @context->state + */ +ARGON2_PRIVATE +int _argon2_fill_memory_blocks(argon2_instance_t *instance); + +#endif +/*** End of #include "core.h" ***/ + + +const char *argon2_type2string(argon2_type type, int uppercase) { + switch (type) { + case Argon2_d: + return uppercase ? "Argon2d" : "argon2d"; + case Argon2_i: + return uppercase ? "Argon2i" : "argon2i"; + case Argon2_id: + return uppercase ? "Argon2id" : "argon2id"; + } + + return NULL; +} + +int argon2_ctx(argon2_context *context, argon2_type type) { + /* 1. Validate all inputs */ + int result = _argon2_validate_inputs(context); + uint32_t memory_blocks, segment_length; + argon2_instance_t instance; + + if (ARGON2_OK != result) { + return result; + } + + if (Argon2_d != type && Argon2_i != type && Argon2_id != type) { + return ARGON2_INCORRECT_TYPE; + } + + /* 2. Align memory size */ + /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */ + memory_blocks = context->m_cost; + + if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes) { + memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes; + } + + segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS); + /* Ensure that all segments have equal length */ + memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS); + + instance.version = context->version; + instance.memory = NULL; + instance.passes = context->t_cost; + instance.memory_blocks = memory_blocks; + instance.segment_length = segment_length; + instance.lane_length = segment_length * ARGON2_SYNC_POINTS; + instance.lanes = context->lanes; + instance.threads = context->threads; + instance.type = type; + + if (instance.threads > instance.lanes) { + instance.threads = instance.lanes; + } + + /* 3. Initialization: Hashing inputs, allocating memory, filling first + * blocks + */ + result = _argon2_initialize(&instance, context); + + if (ARGON2_OK != result) { + return result; + } + + /* 4. Filling memory */ + result = _argon2_fill_memory_blocks(&instance); + + if (ARGON2_OK != result) { + return result; + } + /* 5. Finalization */ + _argon2_finalize(context, &instance); + + return ARGON2_OK; +} + +int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, const size_t saltlen, + void *hash, const size_t hashlen, char *encoded, + const size_t encodedlen, argon2_type type, + const uint32_t version){ + + argon2_context context; + int result; + uint8_t *out; + + if (pwdlen > ARGON2_MAX_PWD_LENGTH) { + return ARGON2_PWD_TOO_LONG; + } + + if (saltlen > ARGON2_MAX_SALT_LENGTH) { + return ARGON2_SALT_TOO_LONG; + } + + if (hashlen > ARGON2_MAX_OUTLEN) { + return ARGON2_OUTPUT_TOO_LONG; + } + + if (hashlen < ARGON2_MIN_OUTLEN) { + return ARGON2_OUTPUT_TOO_SHORT; + } + + out = malloc(hashlen); + if (!out) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + context.out = (uint8_t *)out; + context.outlen = (uint32_t)hashlen; + context.pwd = CONST_CAST(uint8_t *)pwd; + context.pwdlen = (uint32_t)pwdlen; + context.salt = CONST_CAST(uint8_t *)salt; + context.saltlen = (uint32_t)saltlen; + context.secret = NULL; + context.secretlen = 0; + context.ad = NULL; + context.adlen = 0; + context.t_cost = t_cost; + context.m_cost = m_cost; + context.lanes = parallelism; + context.threads = parallelism; + context.allocate_cbk = NULL; + context.free_cbk = NULL; + context.flags = ARGON2_DEFAULT_FLAGS; + context.version = version; + + result = argon2_ctx(&context, type); + + if (result != ARGON2_OK) { + _argon2_clear_internal_memory(out, hashlen); + free(out); + return result; + } + + /* if raw hash requested, write it */ + if (hash) { + memcpy(hash, out, hashlen); + } + + /* if encoding requested, write it */ + if (encoded && encodedlen) { + if (_argon2_encode_string(encoded, encodedlen, &context, type) != ARGON2_OK) { + _argon2_clear_internal_memory(out, hashlen); /* wipe buffers if error */ + _argon2_clear_internal_memory(encoded, encodedlen); + free(out); + return ARGON2_ENCODING_FAIL; + } + } + _argon2_clear_internal_memory(out, hashlen); + free(out); + + return ARGON2_OK; +} + +int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_i, + ARGON2_VERSION_NUMBER); +} + +int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_i, ARGON2_VERSION_NUMBER); +} + +int argon2d_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_d, + ARGON2_VERSION_NUMBER); +} + +int argon2d_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_d, ARGON2_VERSION_NUMBER); +} + +int argon2id_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen) { + + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_id, + ARGON2_VERSION_NUMBER); +} + +int argon2id_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen) { + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_id, + ARGON2_VERSION_NUMBER); +} + +static int argon2_compare(const uint8_t *b1, const uint8_t *b2, size_t len) { + size_t i; + uint8_t d = 0U; + + for (i = 0U; i < len; i++) { + d |= b1[i] ^ b2[i]; + } + return (int)((1 & ((d - 1) >> 8)) - 1); +} + +int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen, + argon2_type type) { + + argon2_context ctx; + uint8_t *desired_result = NULL; + + int ret = ARGON2_OK; + + size_t encoded_len; + uint32_t max_field_len; + + if (pwdlen > ARGON2_MAX_PWD_LENGTH) { + return ARGON2_PWD_TOO_LONG; + } + + if (encoded == NULL) { + return ARGON2_DECODING_FAIL; + } + + encoded_len = strlen(encoded); + if (encoded_len > UINT32_MAX) { + return ARGON2_DECODING_FAIL; + } + + /* No field can be longer than the encoded length */ + max_field_len = (uint32_t)encoded_len; + + ctx.saltlen = max_field_len; + ctx.outlen = max_field_len; + + ctx.salt = malloc(ctx.saltlen); + ctx.out = malloc(ctx.outlen); + if (!ctx.salt || !ctx.out) { + ret = ARGON2_MEMORY_ALLOCATION_ERROR; + goto fail; + } + + ctx.pwd = (uint8_t *)pwd; + ctx.pwdlen = (uint32_t)pwdlen; + + ret = _argon2_decode_string(&ctx, encoded, type); + if (ret != ARGON2_OK) { + goto fail; + } + + /* Set aside the desired result, and get a new buffer. */ + desired_result = ctx.out; + ctx.out = malloc(ctx.outlen); + if (!ctx.out) { + ret = ARGON2_MEMORY_ALLOCATION_ERROR; + goto fail; + } + + ret = argon2_verify_ctx(&ctx, (char *)desired_result, type); + if (ret != ARGON2_OK) { + goto fail; + } + +fail: + free(ctx.salt); + free(ctx.out); + free(desired_result); + + return ret; +} + +int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen) { + + return argon2_verify(encoded, pwd, pwdlen, Argon2_i); +} + +int argon2d_verify(const char *encoded, const void *pwd, const size_t pwdlen) { + + return argon2_verify(encoded, pwd, pwdlen, Argon2_d); +} + +int argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen) { + + return argon2_verify(encoded, pwd, pwdlen, Argon2_id); +} + +int argon2d_ctx(argon2_context *context) { + return argon2_ctx(context, Argon2_d); +} + +int argon2i_ctx(argon2_context *context) { + return argon2_ctx(context, Argon2_i); +} + +int argon2id_ctx(argon2_context *context) { + return argon2_ctx(context, Argon2_id); +} + +int argon2_verify_ctx(argon2_context *context, const char *hash, + argon2_type type) { + int ret = argon2_ctx(context, type); + if (ret != ARGON2_OK) { + return ret; + } + + if (argon2_compare((uint8_t *)hash, context->out, context->outlen)) { + return ARGON2_VERIFY_MISMATCH; + } + + return ARGON2_OK; +} + +int argon2d_verify_ctx(argon2_context *context, const char *hash) { + return argon2_verify_ctx(context, hash, Argon2_d); +} + +int argon2i_verify_ctx(argon2_context *context, const char *hash) { + return argon2_verify_ctx(context, hash, Argon2_i); +} + +int argon2id_verify_ctx(argon2_context *context, const char *hash) { + return argon2_verify_ctx(context, hash, Argon2_id); +} + +const char *argon2_error_message(int error_code) { + switch (error_code) { + case ARGON2_OK: + return "OK"; + case ARGON2_OUTPUT_PTR_NULL: + return "Output pointer is NULL"; + case ARGON2_OUTPUT_TOO_SHORT: + return "Output is too short"; + case ARGON2_OUTPUT_TOO_LONG: + return "Output is too long"; + case ARGON2_PWD_TOO_SHORT: + return "Password is too short"; + case ARGON2_PWD_TOO_LONG: + return "Password is too long"; + case ARGON2_SALT_TOO_SHORT: + return "Salt is too short"; + case ARGON2_SALT_TOO_LONG: + return "Salt is too long"; + case ARGON2_AD_TOO_SHORT: + return "Associated data is too short"; + case ARGON2_AD_TOO_LONG: + return "Associated data is too long"; + case ARGON2_SECRET_TOO_SHORT: + return "Secret is too short"; + case ARGON2_SECRET_TOO_LONG: + return "Secret is too long"; + case ARGON2_TIME_TOO_SMALL: + return "Time cost is too small"; + case ARGON2_TIME_TOO_LARGE: + return "Time cost is too large"; + case ARGON2_MEMORY_TOO_LITTLE: + return "Memory cost is too small"; + case ARGON2_MEMORY_TOO_MUCH: + return "Memory cost is too large"; + case ARGON2_LANES_TOO_FEW: + return "Too few lanes"; + case ARGON2_LANES_TOO_MANY: + return "Too many lanes"; + case ARGON2_PWD_PTR_MISMATCH: + return "Password pointer is NULL, but password length is not 0"; + case ARGON2_SALT_PTR_MISMATCH: + return "Salt pointer is NULL, but salt length is not 0"; + case ARGON2_SECRET_PTR_MISMATCH: + return "Secret pointer is NULL, but secret length is not 0"; + case ARGON2_AD_PTR_MISMATCH: + return "Associated data pointer is NULL, but ad length is not 0"; + case ARGON2_MEMORY_ALLOCATION_ERROR: + return "Memory allocation error"; + case ARGON2_FREE_MEMORY_CBK_NULL: + return "The free memory callback is NULL"; + case ARGON2_ALLOCATE_MEMORY_CBK_NULL: + return "The allocate memory callback is NULL"; + case ARGON2_INCORRECT_PARAMETER: + return "Argon2_Context context is NULL"; + case ARGON2_INCORRECT_TYPE: + return "There is no such version of Argon2"; + case ARGON2_OUT_PTR_MISMATCH: + return "Output pointer mismatch"; + case ARGON2_THREADS_TOO_FEW: + return "Not enough threads"; + case ARGON2_THREADS_TOO_MANY: + return "Too many threads"; + case ARGON2_MISSING_ARGS: + return "Missing arguments"; + case ARGON2_ENCODING_FAIL: + return "Encoding failed"; + case ARGON2_DECODING_FAIL: + return "Decoding failed"; + case ARGON2_THREAD_FAIL: + return "Threading failure"; + case ARGON2_DECODING_LENGTH_FAIL: + return "Some of encoded parameters are too long or too short"; + case ARGON2_VERIFY_MISMATCH: + return "The password does not match the supplied hash"; + default: + return "Unknown error code"; + } +} + +size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost, uint32_t parallelism, + uint32_t saltlen, uint32_t hashlen, argon2_type type) { + return strlen("$$v=$m=,t=,p=$$") + strlen(argon2_type2string(type, 0)) + + _argon2_numlen(t_cost) + _argon2_numlen(m_cost) + _argon2_numlen(parallelism) + + _argon2_b64len(saltlen) + _argon2_b64len(hashlen) + _argon2_numlen(ARGON2_VERSION_NUMBER) + 1; +} +/*** End of #include "src/argon2.c" ***/ + +/* #include "src/core.c" */ +/*** Begin of #include "src/core.c" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +/*For memory wiping*/ +#ifdef _WIN32 +#include +#include /* For SecureZeroMemory */ +#endif +#if defined __STDC_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 +#endif +#define VC_GE_2005(version) (version >= 1400) + +/* for explicit_bzero() on glibc */ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#include +#include +#include + +/* #include "core.h" */ + +/* #include "thread.h" */ +/*** Begin of #include "thread.h" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef ARGON2_THREAD_H +#define ARGON2_THREAD_H + +#if !defined(ARGON2_NO_THREADS) + +/* + Here we implement an abstraction layer for the simple requirements + of the Argon2 code. We only require 3 primitives---thread creation, + joining, and termination---so full emulation of the pthreads API + is unwarranted. Currently we wrap pthreads and Win32 threads. + + The API defines 2 types: the function pointer type, + argon2_thread_func_t, + and the type of the thread handle---argon2_thread_handle_t. +*/ +#if defined(_WIN32) +#include +typedef unsigned(__stdcall *argon2_thread_func_t)(void *); +typedef uintptr_t argon2_thread_handle_t; +#else +#include +typedef void *(*argon2_thread_func_t)(void *); +typedef pthread_t argon2_thread_handle_t; +#endif + +/* Creates a thread + * @param handle pointer to a thread handle, which is the output of this + * function. Must not be NULL. + * @param func A function pointer for the thread's entry point. Must not be + * NULL. + * @param args Pointer that is passed as an argument to @func. May be NULL. + * @return 0 if @handle and @func are valid pointers and a thread is successfully + * created. + */ +ARGON2_PRIVATE +int argon2_thread_create(argon2_thread_handle_t *handle, + argon2_thread_func_t func, void *args); + +/* Waits for a thread to terminate + * @param handle Handle to a thread created with argon2_thread_create. + * @return 0 if @handle is a valid handle, and joining completed successfully. +*/ +ARGON2_PRIVATE +int argon2_thread_join(argon2_thread_handle_t handle); + +/* Terminate the current thread. Must be run inside a thread created by + * argon2_thread_create. +*/ +ARGON2_PRIVATE +void argon2_thread_exit(void); + +#endif /* ARGON2_NO_THREADS */ +#endif +/*** End of #include "thread.h" ***/ + +/* #include "blake2/blake2.h" */ + +/* #include "blake2/blake2-impl.h" */ + + +#ifdef GENKAT +/* #include "genkat.h" */ +/*** Begin of #include "genkat.h" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef ARGON2_KAT_H +#define ARGON2_KAT_H + +/* #include "core.h" */ + + +/* + * Initial KAT function that prints the inputs to the file + * @param blockhash Array that contains pre-hashing digest + * @param context Holds inputs + * @param type Argon2 type + * @pre blockhash must point to INPUT_INITIAL_HASH_LENGTH bytes + * @pre context member pointers must point to allocated memory of size according + * to the length values + */ +void initial_kat(const uint8_t *blockhash, const argon2_context *context, + argon2_type type); + +/* + * Function that prints the output tag + * @param out output array pointer + * @param outlen digest length + * @pre out must point to @a outlen bytes + **/ +void print_tag(const void *out, uint32_t outlen); + +/* + * Function that prints the internal state at given moment + * @param instance pointer to the current instance + * @param pass current pass number + * @pre instance must have necessary memory allocated + **/ +void internal_kat(const argon2_instance_t *instance, uint32_t pass); + +#endif +/*** End of #include "genkat.h" ***/ + +#endif + +#if defined(__clang__) +#if __has_attribute(optnone) +#define NOT_OPTIMIZED __attribute__((optnone)) +#endif +#elif defined(__GNUC__) +#ifndef GCC_VERSION +#define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif +#if GCC_VERSION >= 40400 +#define NOT_OPTIMIZED __attribute__((optimize("O0"))) +#endif +#endif +#ifndef NOT_OPTIMIZED +#define NOT_OPTIMIZED +#endif + +/***************Instance and Position constructors**********/ +ARGON2_PRIVATE +void _argon2_init_block_value(block *b, uint8_t in) { memset(b->v, in, sizeof(b->v)); } + +ARGON2_PRIVATE +void _argon2_copy_block(block *dst, const block *src) { + memcpy(dst->v, src->v, sizeof(uint64_t) * ARGON2_QWORDS_IN_BLOCK); +} + +ARGON2_PRIVATE +void _argon2_xor_block(block *dst, const block *src) { + int i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] ^= src->v[i]; + } +} + +static void _argon2_load_block(block *dst, const void *input) { + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] = _blake2b_load64((const uint8_t *)input + i * sizeof(dst->v[i])); + } +} + +static void _argon2_store_block(void *output, const block *src) { + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + _blake2b_store64((uint8_t *)output + i * sizeof(src->v[i]), src->v[i]); + } +} + +/***************Memory functions*****************/ + +ARGON2_PRIVATE +int _argon2_allocate_memory(const argon2_context *context, uint8_t **memory, + size_t num, size_t size) { + size_t memory_size = num*size; + if (memory == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + /* 1. Check for multiplication overflow */ + if (size != 0 && memory_size / size != num) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + /* 2. Try to allocate with appropriate allocator */ + if (context->allocate_cbk) { + (context->allocate_cbk)(memory, memory_size); + } else { + *memory = malloc(memory_size); + } + + if (*memory == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + return ARGON2_OK; +} + +ARGON2_PRIVATE +void _argon2_free_memory(const argon2_context *context, uint8_t *memory, + size_t num, size_t size) { + size_t memory_size = num*size; + _argon2_clear_internal_memory(memory, memory_size); + if (context->free_cbk) { + (context->free_cbk)(memory, memory_size); + } else { + free(memory); + } +} + +#if defined(__OpenBSD__) +#define HAVE_EXPLICIT_BZERO 1 +#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ) +#if __GLIBC_PREREQ(2,25) +#define HAVE_EXPLICIT_BZERO 1 +#endif +#endif + +ARGON2_PRIVATE +void NOT_OPTIMIZED _argon2_secure_wipe_memory(void *v, size_t n) { +#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER) || defined(__MINGW32__) + SecureZeroMemory(v, n); +#elif defined memset_s + memset_s(v, n, 0, n); +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(v, n); +#else + static void *(*const volatile memset_sec)(void *, int, size_t) = &memset; + memset_sec(v, 0, n); +#endif +} + +/* Memory clear flag defaults to true. */ +ARGON2_PUBLIC +int FLAG_clear_internal_memory = 1; + +ARGON2_PRIVATE +void _argon2_clear_internal_memory(void *v, size_t n) { + if (FLAG_clear_internal_memory && v) { + _argon2_secure_wipe_memory(v, n); + } +} + +ARGON2_PRIVATE +void _argon2_finalize(const argon2_context *context, argon2_instance_t *instance) { + if (context != NULL && instance != NULL) { + block blockhash; + uint32_t l; + + _argon2_copy_block(&blockhash, instance->memory + instance->lane_length - 1); + + /* XOR the last blocks */ + for (l = 1; l < instance->lanes; ++l) { + uint32_t last_block_in_lane = + l * instance->lane_length + (instance->lane_length - 1); + _argon2_xor_block(&blockhash, instance->memory + last_block_in_lane); + } + + /* Hash the result */ + { + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + _argon2_store_block(blockhash_bytes, &blockhash); + blake2b_long(context->out, context->outlen, blockhash_bytes, + ARGON2_BLOCK_SIZE); + /* clear blockhash and blockhash_bytes */ + _argon2_clear_internal_memory(blockhash.v, ARGON2_BLOCK_SIZE); + _argon2_clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE); + } + +#ifdef GENKAT + print_tag(context->out, context->outlen); +#endif + + _argon2_free_memory(context, (uint8_t *)instance->memory, + instance->memory_blocks, sizeof(block)); + } +} + +ARGON2_PRIVATE +uint32_t _argon2_index_alpha(const argon2_instance_t *instance, + const argon2_position_t *position, uint32_t pseudo_rand, + int same_lane) { + /* + * Pass 0: + * This lane : all already finished segments plus already constructed + * blocks in this segment + * Other lanes : all already finished segments + * Pass 1+: + * This lane : (SYNC_POINTS - 1) last segments plus already constructed + * blocks in this segment + * Other lanes : (SYNC_POINTS - 1) last segments + */ + uint32_t reference_area_size; + uint64_t relative_position; + uint32_t start_position, absolute_position; + + if (0 == position->pass) { + /* First pass */ + if (0 == position->slice) { + /* First slice */ + reference_area_size = + position->index - 1; /* all but the previous */ + } else { + if (same_lane) { + /* The same lane => add current segment */ + reference_area_size = + position->slice * instance->segment_length + + position->index - 1; + } else { + reference_area_size = + position->slice * instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + } else { + /* Second pass */ + if (same_lane) { + reference_area_size = instance->lane_length - + instance->segment_length + position->index - + 1; + } else { + reference_area_size = instance->lane_length - + instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + + /* 1.2.4. Mapping pseudo_rand to 0.. and produce + * relative position */ + relative_position = pseudo_rand; + relative_position = relative_position * relative_position >> 32; + relative_position = reference_area_size - 1 - + (reference_area_size * relative_position >> 32); + + /* 1.2.5 Computing starting position */ + start_position = 0; + + if (0 != position->pass) { + start_position = (position->slice == ARGON2_SYNC_POINTS - 1) + ? 0 + : (position->slice + 1) * instance->segment_length; + } + + /* 1.2.6. Computing absolute position */ + absolute_position = (start_position + relative_position) % + instance->lane_length; /* absolute position */ + return absolute_position; +} + +/* Single-threaded version for p=1 case */ +static int _argon2_fill_memory_blocks_st(argon2_instance_t *instance) { + uint32_t r, s, l; + + for (r = 0; r < instance->passes; ++r) { + for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { + for (l = 0; l < instance->lanes; ++l) { + argon2_position_t position = {r, l, (uint8_t)s, 0}; + _argon2_fill_segment(instance, position); + } + } +#ifdef GENKAT + internal_kat(instance, r); /* Print all memory blocks */ +#endif + } + return ARGON2_OK; +} + +#if !defined(ARGON2_NO_THREADS) + +#ifdef _WIN32 +static unsigned __stdcall _argon2_fill_segment_thr(void *thread_data) +#else +static void *_argon2_fill_segment_thr(void *thread_data) +#endif +{ + argon2_thread_data *my_data = thread_data; + _argon2_fill_segment(my_data->instance_ptr, my_data->pos); + argon2_thread_exit(); + return 0; +} + +/* Multi-threaded version for p > 1 case */ +static int _argon2_fill_memory_blocks_mt(argon2_instance_t *instance) { + uint32_t r, s; + argon2_thread_handle_t *thread = NULL; + argon2_thread_data *thr_data = NULL; + int rc = ARGON2_OK; + + /* 1. Allocating space for threads */ + thread = calloc(instance->lanes, sizeof(argon2_thread_handle_t)); + if (thread == NULL) { + rc = ARGON2_MEMORY_ALLOCATION_ERROR; + goto fail; + } + + thr_data = calloc(instance->lanes, sizeof(argon2_thread_data)); + if (thr_data == NULL) { + rc = ARGON2_MEMORY_ALLOCATION_ERROR; + goto fail; + } + + for (r = 0; r < instance->passes; ++r) { + for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { + uint32_t l, ll; + + /* 2. Calling threads */ + for (l = 0; l < instance->lanes; ++l) { + argon2_position_t position; + + /* 2.1 Join a thread if limit is exceeded */ + if (l >= instance->threads) { + if (argon2_thread_join(thread[l - instance->threads])) { + rc = ARGON2_THREAD_FAIL; + goto fail; + } + } + + /* 2.2 Create thread */ + position.pass = r; + position.lane = l; + position.slice = (uint8_t)s; + position.index = 0; + thr_data[l].instance_ptr = + instance; /* preparing the thread input */ + memcpy(&(thr_data[l].pos), &position, + sizeof(argon2_position_t)); + if (argon2_thread_create(&thread[l], &_argon2_fill_segment_thr, + (void *)&thr_data[l])) { + /* Wait for already running threads */ + for (ll = 0; ll < l; ++ll) + argon2_thread_join(thread[ll]); + rc = ARGON2_THREAD_FAIL; + goto fail; + } + + /* fill_segment(instance, position); */ + /*Non-thread equivalent of the lines above */ + } + + /* 3. Joining remaining threads */ + for (l = instance->lanes - instance->threads; l < instance->lanes; + ++l) { + if (argon2_thread_join(thread[l])) { + rc = ARGON2_THREAD_FAIL; + goto fail; + } + } + } + +#ifdef GENKAT + internal_kat(instance, r); /* Print all memory blocks */ +#endif + } + +fail: + if (thread != NULL) { + free(thread); + } + if (thr_data != NULL) { + free(thr_data); + } + return rc; +} + +#endif /* ARGON2_NO_THREADS */ + +ARGON2_PRIVATE +int _argon2_fill_memory_blocks(argon2_instance_t *instance) { + if (instance == NULL || instance->lanes == 0) { + return ARGON2_INCORRECT_PARAMETER; + } +#if defined(ARGON2_NO_THREADS) + return _argon2_fill_memory_blocks_st(instance); +#else + return instance->threads == 1 ? + _argon2_fill_memory_blocks_st(instance) : _argon2_fill_memory_blocks_mt(instance); +#endif +} + +ARGON2_PRIVATE +int _argon2_validate_inputs(const argon2_context *context) { + if (NULL == context) { + return ARGON2_INCORRECT_PARAMETER; + } + + if (NULL == context->out) { + return ARGON2_OUTPUT_PTR_NULL; + } + + /* Validate output length */ + if (ARGON2_MIN_OUTLEN > context->outlen) { + return ARGON2_OUTPUT_TOO_SHORT; + } + + if (ARGON2_MAX_OUTLEN < context->outlen) { + return ARGON2_OUTPUT_TOO_LONG; + } + + /* Validate password (required param) */ + if (NULL == context->pwd) { + if (0 != context->pwdlen) { + return ARGON2_PWD_PTR_MISMATCH; + } + } + + if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) { + return ARGON2_PWD_TOO_SHORT; + } + + if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) { + return ARGON2_PWD_TOO_LONG; + } + + /* Validate salt (required param) */ + if (NULL == context->salt) { + if (0 != context->saltlen) { + return ARGON2_SALT_PTR_MISMATCH; + } + } + + if (ARGON2_MIN_SALT_LENGTH > context->saltlen) { + return ARGON2_SALT_TOO_SHORT; + } + + if (ARGON2_MAX_SALT_LENGTH < context->saltlen) { + return ARGON2_SALT_TOO_LONG; + } + + /* Validate secret (optional param) */ + if (NULL == context->secret) { + if (0 != context->secretlen) { + return ARGON2_SECRET_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_SECRET > context->secretlen) { + return ARGON2_SECRET_TOO_SHORT; + } + if (ARGON2_MAX_SECRET < context->secretlen) { + return ARGON2_SECRET_TOO_LONG; + } + } + + /* Validate associated data (optional param) */ + if (NULL == context->ad) { + if (0 != context->adlen) { + return ARGON2_AD_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_AD_LENGTH > context->adlen) { + return ARGON2_AD_TOO_SHORT; + } + if (ARGON2_MAX_AD_LENGTH < context->adlen) { + return ARGON2_AD_TOO_LONG; + } + } + + /* Validate memory cost */ + if (ARGON2_MIN_MEMORY > context->m_cost) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + if (ARGON2_MAX_MEMORY < context->m_cost) { + return ARGON2_MEMORY_TOO_MUCH; + } + + if (context->m_cost < 8 * context->lanes) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + /* Validate time cost */ + if (ARGON2_MIN_TIME > context->t_cost) { + return ARGON2_TIME_TOO_SMALL; + } + + if (ARGON2_MAX_TIME < context->t_cost) { + return ARGON2_TIME_TOO_LARGE; + } + + /* Validate lanes */ + if (ARGON2_MIN_LANES > context->lanes) { + return ARGON2_LANES_TOO_FEW; + } + + if (ARGON2_MAX_LANES < context->lanes) { + return ARGON2_LANES_TOO_MANY; + } + + /* Validate threads */ + if (ARGON2_MIN_THREADS > context->threads) { + return ARGON2_THREADS_TOO_FEW; + } + + if (ARGON2_MAX_THREADS < context->threads) { + return ARGON2_THREADS_TOO_MANY; + } + + if (NULL != context->allocate_cbk && NULL == context->free_cbk) { + return ARGON2_FREE_MEMORY_CBK_NULL; + } + + if (NULL == context->allocate_cbk && NULL != context->free_cbk) { + return ARGON2_ALLOCATE_MEMORY_CBK_NULL; + } + + return ARGON2_OK; +} + +ARGON2_PRIVATE +void _argon2_fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance) { + uint32_t l; + /* Make the first and second block in each lane as G(H0||0||i) or + G(H0||1||i) */ + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + for (l = 0; l < instance->lanes; ++l) { + + _blake2b_store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0); + _blake2b_store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + _argon2_load_block(&instance->memory[l * instance->lane_length + 0], + blockhash_bytes); + + _blake2b_store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + _argon2_load_block(&instance->memory[l * instance->lane_length + 1], + blockhash_bytes); + } + _argon2_clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE); +} + +ARGON2_PRIVATE +void _argon2_initial_hash(uint8_t *blockhash, argon2_context *context, + argon2_type type) { + blake2b_state BlakeHash; + uint8_t value[sizeof(uint32_t)]; + + if (NULL == context || NULL == blockhash) { + return; + } + + blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH); + + _blake2b_store32(&value, context->lanes); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + _blake2b_store32(&value, context->outlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + _blake2b_store32(&value, context->m_cost); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + _blake2b_store32(&value, context->t_cost); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + _blake2b_store32(&value, context->version); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + _blake2b_store32(&value, (uint32_t)type); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + _blake2b_store32(&value, context->pwdlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->pwd != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->pwd, + context->pwdlen); + + if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) { + _argon2_secure_wipe_memory(context->pwd, context->pwdlen); + context->pwdlen = 0; + } + } + + _blake2b_store32(&value, context->saltlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->salt != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->salt, + context->saltlen); + } + + _blake2b_store32(&value, context->secretlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->secret != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->secret, + context->secretlen); + + if (context->flags & ARGON2_FLAG_CLEAR_SECRET) { + _argon2_secure_wipe_memory(context->secret, context->secretlen); + context->secretlen = 0; + } + } + + _blake2b_store32(&value, context->adlen); + blake2b_update(&BlakeHash, (const uint8_t *)&value, sizeof(value)); + + if (context->ad != NULL) { + blake2b_update(&BlakeHash, (const uint8_t *)context->ad, + context->adlen); + } + + blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH); +} + +ARGON2_PRIVATE +int _argon2_initialize(argon2_instance_t *instance, argon2_context *context) { + uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; + int result = ARGON2_OK; + + if (instance == NULL || context == NULL) + return ARGON2_INCORRECT_PARAMETER; + instance->context_ptr = context; + + /* 1. Memory allocation */ + result = _argon2_allocate_memory(context, (uint8_t **)&(instance->memory), + instance->memory_blocks, sizeof(block)); + if (result != ARGON2_OK) { + return result; + } + + /* 2. Initial hashing */ + /* H_0 + 8 extra bytes to produce the first blocks */ + /* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */ + /* Hashing all inputs */ + _argon2_initial_hash(blockhash, context, instance->type); + /* Zeroing 8 extra bytes */ + _argon2_clear_internal_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, + ARGON2_PREHASH_SEED_LENGTH - + ARGON2_PREHASH_DIGEST_LENGTH); + +#ifdef GENKAT + initial_kat(blockhash, context, instance->type); +#endif + + /* 3. Creating first blocks, we always have at least two blocks in a slice + */ + _argon2_fill_first_blocks(blockhash, instance); + /* Clearing the hash */ + _argon2_clear_internal_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH); + + return ARGON2_OK; +} +/*** End of #include "src/core.c" ***/ + +/* #include "src/encoding.c" */ +/*** Begin of #include "src/encoding.c" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#include +#include +#include +#include +/* #include "encoding.h" */ + +/* #include "core.h" */ + + +/* + * Example code for a decoder and encoder of "hash strings", with Argon2 + * parameters. + * + * This code comprises three sections: + * + * -- The first section contains generic Base64 encoding and decoding + * functions. It is conceptually applicable to any hash function + * implementation that uses Base64 to encode and decode parameters, + * salts and outputs. It could be made into a library, provided that + * the relevant functions are made public (non-static) and be given + * reasonable names to avoid collisions with other functions. + * + * -- The second section is specific to Argon2. It encodes and decodes + * the parameters, salts and outputs. It does not compute the hash + * itself. + * + * The code was originally written by Thomas Pornin , + * to whom comments and remarks may be sent. It is released under what + * should amount to Public Domain or its closest equivalent; the + * following mantra is supposed to incarnate that fact with all the + * proper legal rituals: + * + * --------------------------------------------------------------------- + * This file is provided under the terms of Creative Commons CC0 1.0 + * Public Domain Dedication. To the extent possible under law, the + * author (Thomas Pornin) has waived all copyright and related or + * neighboring rights to this file. This work is published from: Canada. + * --------------------------------------------------------------------- + * + * Copyright (c) 2015 Thomas Pornin + */ + +/* ==================================================================== */ +/* + * Common code; could be shared between different hash functions. + * + * Note: the Base64 functions below assume that uppercase letters (resp. + * lowercase letters) have consecutive numerical codes, that fit on 8 + * bits. All modern systems use ASCII-compatible charsets, where these + * properties are true. If you are stuck with a dinosaur of a system + * that still defaults to EBCDIC then you already have much bigger + * interoperability issues to deal with. + */ + +/* + * Some macros for constant-time comparisons. These work over values in + * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true". + */ +#define ARGON2_EQ(x, y) ((((0U - ((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF) +#define ARGON2_GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF) +#define ARGON2_GE(x, y) (ARGON2_GT(y, x) ^ 0xFF) +#define ARGON2_LT(x, y) ARGON2_GT(y, x) +#define ARGON2_LE(x, y) ARGON2_GE(y, x) + +/* + * Convert value x (0..63) to corresponding Base64 character. + */ +static int _argon2_b64_byte_to_char(unsigned x) { + return (ARGON2_LT(x, 26) & (x + 'A')) | + (ARGON2_GE(x, 26) & ARGON2_LT(x, 52) & (x + ('a' - 26))) | + (ARGON2_GE(x, 52) & ARGON2_LT(x, 62) & (x + ('0' - 52))) | (ARGON2_EQ(x, 62) & '+') | + (ARGON2_EQ(x, 63) & '/'); +} + +/* + * Convert character c to the corresponding 6-bit value. If character c + * is not a Base64 character, then 0xFF (255) is returned. + */ +static unsigned _argon2_b64_char_to_byte(int c) { + unsigned x; + + x = (ARGON2_GE(c, 'A') & ARGON2_LE(c, 'Z') & (c - 'A')) | + (ARGON2_GE(c, 'a') & ARGON2_LE(c, 'z') & (c - ('a' - 26))) | + (ARGON2_GE(c, '0') & ARGON2_LE(c, '9') & (c - ('0' - 52))) | (ARGON2_EQ(c, '+') & 62) | + (ARGON2_EQ(c, '/') & 63); + return x | (ARGON2_EQ(x, 0) & (ARGON2_EQ(c, 'A') ^ 0xFF)); +} + +/* + * Convert some bytes to Base64. 'dst_len' is the length (in characters) + * of the output buffer 'dst'; if that buffer is not large enough to + * receive the result (including the terminating 0), then (size_t)-1 + * is returned. Otherwise, the zero-terminated Base64 string is written + * in the buffer, and the output length (counted WITHOUT the terminating + * zero) is returned. + */ +static size_t _argon2_to_base64(char *dst, size_t dst_len, const void *src, + size_t src_len) { + size_t olen; + const unsigned char *buf; + unsigned acc, acc_len; + + olen = (src_len / 3) << 2; + switch (src_len % 3) { + case 2: + olen++; + /* fall through */ + case 1: + olen += 2; + break; + } + if (dst_len <= olen) { + return (size_t)-1; + } + acc = 0; + acc_len = 0; + buf = (const unsigned char *)src; + while (src_len-- > 0) { + acc = (acc << 8) + (*buf++); + acc_len += 8; + while (acc_len >= 6) { + acc_len -= 6; + *dst++ = (char)_argon2_b64_byte_to_char((acc >> acc_len) & 0x3F); + } + } + if (acc_len > 0) { + *dst++ = (char)_argon2_b64_byte_to_char((acc << (6 - acc_len)) & 0x3F); + } + *dst++ = 0; + return olen; +} + +/* + * Decode Base64 chars into bytes. The '*dst_len' value must initially + * contain the length of the output buffer '*dst'; when the decoding + * ends, the actual number of decoded bytes is written back in + * '*dst_len'. + * + * Decoding stops when a non-Base64 character is encountered, or when + * the output buffer capacity is exceeded. If an error occurred (output + * buffer is too small, invalid last characters leading to unprocessed + * buffered bits), then NULL is returned; otherwise, the returned value + * points to the first non-Base64 character in the source stream, which + * may be the terminating zero. + */ +static const char *_argon2_from_base64(void *dst, size_t *dst_len, const char *src) { + size_t len; + unsigned char *buf; + unsigned acc, acc_len; + + buf = (unsigned char *)dst; + len = 0; + acc = 0; + acc_len = 0; + for (;;) { + unsigned d; + + d = _argon2_b64_char_to_byte(*src); + if (d == 0xFF) { + break; + } + src++; + acc = (acc << 6) + d; + acc_len += 6; + if (acc_len >= 8) { + acc_len -= 8; + if ((len++) >= *dst_len) { + return NULL; + } + *buf++ = (acc >> acc_len) & 0xFF; + } + } + + /* + * If the input length is equal to 1 modulo 4 (which is + * invalid), then there will remain 6 unprocessed bits; + * otherwise, only 0, 2 or 4 bits are buffered. The buffered + * bits must also all be zero. + */ + if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) { + return NULL; + } + *dst_len = len; + return src; +} + +/* + * Decode decimal integer from 'str'; the value is written in '*v'. + * Returned value is a pointer to the next non-decimal character in the + * string. If there is no digit at all, or the value encoding is not + * minimal (extra leading zeros), or the value does not fit in an + * 'unsigned long', then NULL is returned. + */ +static const char *_argon2_decode_decimal(const char *str, unsigned long *v) { + const char *orig; + unsigned long acc; + + acc = 0; + for (orig = str;; str++) { + int c; + + c = *str; + if (c < '0' || c > '9') { + break; + } + c -= '0'; + if (acc > (ULONG_MAX / 10)) { + return NULL; + } + acc *= 10; + if ((unsigned long)c > (ULONG_MAX - acc)) { + return NULL; + } + acc += (unsigned long)c; + } + if (str == orig || (*orig == '0' && str != (orig + 1))) { + return NULL; + } + *v = acc; + return str; +} + +/* ==================================================================== */ +/* + * Code specific to Argon2. + * + * The code below applies the following format: + * + * $argon2[$v=]$m=,t=,p=$$ + * + * where is either 'd', 'id', or 'i', is a decimal integer (positive, + * fits in an 'unsigned long'), and is Base64-encoded data (no '=' padding + * characters, no newline or whitespace). + * + * The last two binary chunks (encoded in Base64) are, in that order, + * the salt and the output. Both are required. The binary salt length and the + * output length must be in the allowed ranges defined in argon2.h. + * + * The ctx struct must contain buffers large enough to hold the salt and pwd + * when it is fed into decode_string. + */ + +ARGON2_PRIVATE +int _argon2_decode_string(argon2_context *ctx, const char *str, argon2_type type) { + +/* check for prefix */ +#define ARGON2_CC(prefix) \ + do { \ + size_t cc_len = strlen(prefix); \ + if (strncmp(str, prefix, cc_len) != 0) { \ + return ARGON2_DECODING_FAIL; \ + } \ + str += cc_len; \ + } while ((void)0, 0) + +/* optional prefix checking with supplied code */ +#define ARGON2_CC_opt(prefix, code) \ + do { \ + size_t cc_len = strlen(prefix); \ + if (strncmp(str, prefix, cc_len) == 0) { \ + str += cc_len; \ + { code; } \ + } \ + } while ((void)0, 0) + +/* Decoding prefix into decimal */ +#define ARGON2_DECIMAL(x) \ + do { \ + unsigned long dec_x; \ + str = _argon2_decode_decimal(str, &dec_x); \ + if (str == NULL) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (x) = dec_x; \ + } while ((void)0, 0) + + +/* Decoding prefix into uint32_t decimal */ +#define ARGON2_DECIMAL_U32(x) \ + do { \ + unsigned long dec_x; \ + str = _argon2_decode_decimal(str, &dec_x); \ + if (str == NULL || dec_x > UINT32_MAX) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (x) = (uint32_t)dec_x; \ + } while ((void)0, 0) + + +/* Decoding base64 into a binary buffer */ +#define ARGON2_BIN(buf, max_len, len) \ + do { \ + size_t bin_len = (max_len); \ + str = _argon2_from_base64(buf, &bin_len, str); \ + if (str == NULL || bin_len > UINT32_MAX) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (len) = (uint32_t)bin_len; \ + } while ((void)0, 0) + + size_t maxsaltlen = ctx->saltlen; + size_t maxoutlen = ctx->outlen; + int validation_result; + const char* type_string; + + /* We should start with the argon2_type we are using */ + type_string = argon2_type2string(type, 0); + if (!type_string) { + return ARGON2_INCORRECT_TYPE; + } + + ARGON2_CC("$"); + ARGON2_CC(type_string); + + /* Reading the version number if the default is suppressed */ + ctx->version = ARGON2_VERSION_10; + ARGON2_CC_opt("$v=", ARGON2_DECIMAL_U32(ctx->version)); + + ARGON2_CC("$m="); + ARGON2_DECIMAL_U32(ctx->m_cost); + ARGON2_CC(",t="); + ARGON2_DECIMAL_U32(ctx->t_cost); + ARGON2_CC(",p="); + ARGON2_DECIMAL_U32(ctx->lanes); + ctx->threads = ctx->lanes; + + ARGON2_CC("$"); + ARGON2_BIN(ctx->salt, maxsaltlen, ctx->saltlen); + ARGON2_CC("$"); + ARGON2_BIN(ctx->out, maxoutlen, ctx->outlen); + + /* The rest of the fields get the default values */ + ctx->secret = NULL; + ctx->secretlen = 0; + ctx->ad = NULL; + ctx->adlen = 0; + ctx->allocate_cbk = NULL; + ctx->free_cbk = NULL; + ctx->flags = ARGON2_DEFAULT_FLAGS; + + /* On return, must have valid context */ + validation_result = _argon2_validate_inputs(ctx); + if (validation_result != ARGON2_OK) { + return validation_result; + } + + /* Can't have any additional characters */ + if (*str == 0) { + return ARGON2_OK; + } else { + return ARGON2_DECODING_FAIL; + } +#undef ARGON2_CC +#undef ARGON2_CC_opt +#undef ARGON2_DECIMAL +#undef ARGON2_DECIMAL_U32 +#undef ARGON2_BIN +} + +ARGON2_PRIVATE +int _argon2_encode_string(char *dst, size_t dst_len, argon2_context *ctx, + argon2_type type) { +#define ARGON2_SS(str) \ + do { \ + size_t pp_len = strlen(str); \ + if (pp_len >= dst_len) { \ + return ARGON2_ENCODING_FAIL; \ + } \ + memcpy(dst, str, pp_len + 1); \ + dst += pp_len; \ + dst_len -= pp_len; \ + } while ((void)0, 0) + +#define ARGON2_SX(x) \ + do { \ + char tmp[30]; \ + sprintf(tmp, "%lu", (unsigned long)(x)); \ + ARGON2_SS(tmp); \ + } while ((void)0, 0) + +#define ARGON2_SB(buf, len) \ + do { \ + size_t sb_len = _argon2_to_base64(dst, dst_len, buf, len); \ + if (sb_len == (size_t)-1) { \ + return ARGON2_ENCODING_FAIL; \ + } \ + dst += sb_len; \ + dst_len -= sb_len; \ + } while ((void)0, 0) + + const char* type_string = argon2_type2string(type, 0); + int validation_result = _argon2_validate_inputs(ctx); + + if (!type_string) { + return ARGON2_ENCODING_FAIL; + } + + if (validation_result != ARGON2_OK) { + return validation_result; + } + + + ARGON2_SS("$"); + ARGON2_SS(type_string); + + ARGON2_SS("$v="); + ARGON2_SX(ctx->version); + + ARGON2_SS("$m="); + ARGON2_SX(ctx->m_cost); + ARGON2_SS(",t="); + ARGON2_SX(ctx->t_cost); + ARGON2_SS(",p="); + ARGON2_SX(ctx->lanes); + + ARGON2_SS("$"); + ARGON2_SB(ctx->salt, ctx->saltlen); + + ARGON2_SS("$"); + ARGON2_SB(ctx->out, ctx->outlen); + return ARGON2_OK; + +#undef ARGON2_SS +#undef ARGON2_SX +#undef ARGON2_SB +} + +ARGON2_PRIVATE +size_t _argon2_b64len(uint32_t len) { + size_t olen = ((size_t)len / 3) << 2; + + switch (len % 3) { + case 2: + olen++; + /* fall through */ + case 1: + olen += 2; + break; + } + + return olen; +} + +ARGON2_PRIVATE +size_t _argon2_numlen(uint32_t num) { + size_t len = 1; + while (num >= 10) { + ++len; + num = num / 10; + } + return len; +} + +/*** End of #include "src/encoding.c" ***/ + +/* #include "src/ref.c" */ +/*** Begin of #include "src/ref.c" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#include +#include +#include + +/* #include "argon2.h" */ + +/* #include "core.h" */ + + +/* #include "blake2/blamka-round-ref.h" */ +/*** Begin of #include "blake2/blamka-round-ref.h" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#ifndef BLAKE_ROUND_MKA_H +#define BLAKE_ROUND_MKA_H + +/* #include "blake2.h" */ + +/* #include "blake2-impl.h" */ + + +/* designed by the Lyra PHC team */ +static BLAKE2_INLINE uint64_t fBlaMka(uint64_t x, uint64_t y) { + const uint64_t m = UINT64_C(0xFFFFFFFF); + const uint64_t xy = (x & m) * (y & m); + return x + y + 2 * xy; +} + +#define BLAKE2_G(a, b, c, d) \ + do { \ + a = fBlaMka(a, b); \ + d = _blake2b_rotr64(d ^ a, 32); \ + c = fBlaMka(c, d); \ + b = _blake2b_rotr64(b ^ c, 24); \ + a = fBlaMka(a, b); \ + d = _blake2b_rotr64(d ^ a, 16); \ + c = fBlaMka(c, d); \ + b = _blake2b_rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, \ + v12, v13, v14, v15) \ + do { \ + BLAKE2_G(v0, v4, v8, v12); \ + BLAKE2_G(v1, v5, v9, v13); \ + BLAKE2_G(v2, v6, v10, v14); \ + BLAKE2_G(v3, v7, v11, v15); \ + BLAKE2_G(v0, v5, v10, v15); \ + BLAKE2_G(v1, v6, v11, v12); \ + BLAKE2_G(v2, v7, v8, v13); \ + BLAKE2_G(v3, v4, v9, v14); \ + } while ((void)0, 0) + +#endif +/*** End of #include "blake2/blamka-round-ref.h" ***/ + +/* #include "blake2/blake2-impl.h" */ + +/* #include "blake2/blake2.h" */ + + + +/* + * Function fills a new memory block and optionally XORs the old block over the new one. + * @next_block must be initialized. + * @param prev_block Pointer to the previous block + * @param ref_block Pointer to the reference block + * @param next_block Pointer to the block to be constructed + * @param with_xor Whether to XOR into the new block (1) or just overwrite (0) + * @pre all block pointers must be valid + */ +static void _argon2_fill_block(const block *prev_block, const block *ref_block, + block *next_block, int with_xor) { + block blockR, block_tmp; + unsigned i; + + _argon2_copy_block(&blockR, ref_block); + _argon2_xor_block(&blockR, prev_block); + _argon2_copy_block(&block_tmp, &blockR); + /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */ + if (with_xor) { + /* Saving the next block contents for XOR over: */ + _argon2_xor_block(&block_tmp, next_block); + /* Now blockR = ref_block + prev_block and + block_tmp = ref_block + prev_block + next_block */ + } + + /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then + (16,17,..31)... finally (112,113,...127) */ + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND_NOMSG( + blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], + blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], + blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], + blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], + blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], + blockR.v[16 * i + 15]); + } + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + for (i = 0; i < 8; i++) { + BLAKE2_ROUND_NOMSG( + blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], + blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], + blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], + blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], + blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], + blockR.v[2 * i + 113]); + } + + _argon2_copy_block(next_block, &block_tmp); + _argon2_xor_block(next_block, &blockR); +} + +static void _argon2_next_addresses(block *address_block, block *input_block, + const block *zero_block) { + input_block->v[6]++; + _argon2_fill_block(zero_block, input_block, address_block, 0); + _argon2_fill_block(zero_block, address_block, address_block, 0); +} + +ARGON2_PRIVATE +void _argon2_fill_segment(const argon2_instance_t *instance, + argon2_position_t position) { + block *ref_block = NULL, *curr_block = NULL; + block address_block, input_block, zero_block; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index; + uint32_t i; + int data_independent_addressing; + + if (instance == NULL) { + return; + } + + data_independent_addressing = + (instance->type == Argon2_i) || + (instance->type == Argon2_id && (position.pass == 0) && + (position.slice < ARGON2_SYNC_POINTS / 2)); + + if (data_independent_addressing) { + _argon2_init_block_value(&zero_block, 0); + _argon2_init_block_value(&input_block, 0); + + input_block.v[0] = position.pass; + input_block.v[1] = position.lane; + input_block.v[2] = position.slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + + /* Don't forget to generate the first block of addresses: */ + if (data_independent_addressing) { + _argon2_next_addresses(&address_block, &input_block, &zero_block); + } + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + _argon2_next_addresses(&address_block, &input_block, &zero_block); + } + pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } else { + pseudo_rand = instance->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = _argon2_index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = + instance->memory + instance->lane_length * ref_lane + ref_index; + curr_block = instance->memory + curr_offset; + if (ARGON2_VERSION_10 == instance->version) { + /* version 1.2.1 and earlier: overwrite, not XOR */ + _argon2_fill_block(instance->memory + prev_offset, ref_block, curr_block, 0); + } else { + if(0 == position.pass) { + _argon2_fill_block(instance->memory + prev_offset, ref_block, + curr_block, 0); + } else { + _argon2_fill_block(instance->memory + prev_offset, ref_block, + curr_block, 1); + } + } + } +} +/*** End of #include "src/ref.c" ***/ + +/* #include "src/thread.c" */ +/*** Begin of #include "src/thread.c" ***/ +/* + * Argon2 reference source code package - reference C implementations + * + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves + * + * You may use this work under the terms of a Creative Commons CC0 1.0 + * License/Waiver or the Apache Public License 2.0, at your option. The terms of + * these licenses can be found at: + * + * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0 + * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0 + * + * You should have received a copy of both of these licenses along with this + * software. If not, they may be obtained at the above URLs. + */ + +#if !defined(ARGON2_NO_THREADS) + +/* #include "thread.h" */ + +#if defined(_WIN32) +#include +#endif + +ARGON2_PRIVATE +int argon2_thread_create(argon2_thread_handle_t *handle, + argon2_thread_func_t func, void *args) { + if (NULL == handle || func == NULL) { + return -1; + } +#if defined(_WIN32) + *handle = _beginthreadex(NULL, 0, func, args, 0, NULL); + return *handle != 0 ? 0 : -1; +#else + return pthread_create(handle, NULL, func, args); +#endif +} + +ARGON2_PRIVATE +int argon2_thread_join(argon2_thread_handle_t handle) { +#if defined(_WIN32) + if (WaitForSingleObject((HANDLE)handle, INFINITE) == WAIT_OBJECT_0) { + return CloseHandle((HANDLE)handle) != 0 ? 0 : -1; + } + return -1; +#else + return pthread_join(handle, NULL); +#endif +} + +ARGON2_PRIVATE +void argon2_thread_exit(void) { +#if defined(_WIN32) + _endthreadex(0); +#else + pthread_exit(NULL); +#endif +} + +#endif /* ARGON2_NO_THREADS */ +/*** End of #include "src/thread.c" ***/ + +/*** End of #include "argon2/libargon2.c" ***/ + +#endif + +/* #include "codec_algos.c" */ +/*** Begin of #include "codec_algos.c" ***/ +/* +** Name: codec_algos.c +** Purpose: Implementation of SQLite codec algorithms +** Author: Ulrich Telle +** Created: 2020-02-02 +** Copyright: (c) 2006-2020 Ulrich Telle +** License: MIT +*/ + +/* #include "cipher_common.h" */ +/*** Begin of #include "cipher_common.h" ***/ +/* +** Name: cipher_common.h +** Purpose: Header for the ciphers of SQLite3 Multiple Ciphers +** Author: Ulrich Telle +** Created: 2020-02-02 +** Copyright: (c) 2006-2026 Ulrich Telle +** License: MIT +*/ + +#ifndef CIPHER_COMMON_H_ +#define CIPHER_COMMON_H_ + +/* #include "sqlite3mc.h" */ + + +/* +// ATTENTION: Macro similar to that in pager.c +// TODO: Check in case of new version of SQLite +*/ +#define WX_PAGER_MJ_PGNO(x) ((PENDING_BYTE/(x))+1) + +#define CODEC_TYPE_DEFAULT CODEC_TYPE_CHACHA20 + +#ifndef CODEC_TYPE +#define CODEC_TYPE CODEC_TYPE_DEFAULT +#endif + +#if CODEC_TYPE < 1 || CODEC_TYPE > CODEC_TYPE_MAX_BUILTIN +#error "Invalid codec type selected" +#endif + +/* +** Define the maximum number of ciphers that can be registered +*/ + +/* Use a reasonable upper limit for the maximum number of ciphers */ +#define CODEC_COUNT_LIMIT 16 + +#ifdef SQLITE3MC_MAX_CODEC_COUNT +/* Allow at least to register all built-in ciphers, but use a reasonable upper limit */ +#if SQLITE3MC_MAX_CODEC_COUNT >= CODEC_TYPE_MAX_BUILTIN && SQLITE3MC_MAX_CODEC_COUNT <= CODEC_COUNT_LIMIT +#define CODEC_COUNT_MAX SQLITE3MC_MAX_CODEC_COUNT +#else +#error "Maximum cipher count not in range [CODEC_TYPE_MAX_BUILTIN .. CODEC_COUNT_LIMIT]" +#endif +#else +#define CODEC_COUNT_MAX CODEC_COUNT_LIMIT +#endif + +#define CIPHER_NAME_MAXLEN 32 +#define CIPHER_PARAMS_COUNT_MAX 64 + +#define MAXKEYLENGTH 32 +#define KEYLENGTH_AES128 16 +#define KEYLENGTH_AES256 32 +#define KEYSALT_LENGTH 16 + +#define CODEC_SHA_ITER 4001 + +/* Restrict possible plaintext header size to db header size */ +#define PLAINTEXT_HEADER_MAX 100 + +typedef struct _CodecParameter +{ + char* m_name; + int m_id; + CipherParams* m_params; +} CodecParameter; + +typedef struct _Codec +{ + int m_isEncrypted; + int m_hmacCheck; + int m_walLegacy; + /* Read cipher */ + int m_hasReadCipher; + int m_readCipherType; + void* m_readCipher; + int m_readReserved; + /* Write cipher */ + int m_hasWriteCipher; + int m_writeCipherType; + void* m_writeCipher; + int m_writeReserved; + + sqlite3* m_db; /* Pointer to DB */ +#if 0 + Btree* m_bt; /* Pointer to B-tree used by DB */ +#endif + BtShared* m_btShared; /* Pointer to shared B-tree used by DB */ + unsigned char m_page[SQLITE_MAX_PAGE_SIZE + 24]; + int m_pageSize; + int m_reserved; + int m_lastError; + int m_hasKeySalt; + unsigned char m_keySalt[KEYSALT_LENGTH]; +} Codec; + +#define CIPHER_PARAMS_SENTINEL { "", 0, 0, 0, 0 } +#define CIPHER_PAGE1_OFFSET 24 + +SQLITE_PRIVATE int sqlite3mcGetCipherParameter(CipherParams* cipherParams, const char* paramName); + +SQLITE_PRIVATE int sqlite3mcGetCipherType(sqlite3* db); + +SQLITE_PRIVATE CipherParams* sqlite3mcGetCipherParams(sqlite3* db, const char* cipherName); + +SQLITE_PRIVATE int sqlite3mcCodecInit(Codec* codec); + +SQLITE_PRIVATE void sqlite3mcCodecTerm(Codec* codec); + +SQLITE_PRIVATE void sqlite3mcClearKeySalt(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcCodecSetup(Codec* codec, int cipherType, char* userPassword, int passwordLength); + +SQLITE_PRIVATE int sqlite3mcSetupWriteCipher(Codec* codec, int cipherType, char* userPassword, int passwordLength, int usesWal); + +SQLITE_PRIVATE void sqlite3mcSetIsEncrypted(Codec* codec, int isEncrypted); + +SQLITE_PRIVATE void sqlite3mcSetReadCipherType(Codec* codec, int cipherType); + +SQLITE_PRIVATE void sqlite3mcSetWriteCipherType(Codec* codec, int cipherType); + +SQLITE_PRIVATE void sqlite3mcSetHasReadCipher(Codec* codec, int hasReadCipher); + +SQLITE_PRIVATE void sqlite3mcSetHasWriteCipher(Codec* codec, int hasWriteCipher); + +SQLITE_PRIVATE void sqlite3mcSetDb(Codec* codec, sqlite3* db); + +SQLITE_PRIVATE void sqlite3mcSetBtree(Codec* codec, Btree* bt); + +SQLITE_PRIVATE void sqlite3mcSetReadReserved(Codec* codec, int reserved); + +SQLITE_PRIVATE void sqlite3mcSetWriteReserved(Codec* codec, int reserved); + +SQLITE_PRIVATE int sqlite3mcIsEncrypted(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcHasReadCipher(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcHasWriteCipher(Codec* codec); + +SQLITE_PRIVATE BtShared* sqlite3mcGetBtShared(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcGetPageSize(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcGetReadReserved(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcGetWriteReserved(Codec* codec); + +SQLITE_PRIVATE unsigned char* sqlite3mcGetPageBuffer(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcGetLegacyReadCipher(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcGetLegacyWriteCipher(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcGetPageSizeReadCipher(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcGetPageSizeWriteCipher(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcGetReservedReadCipher(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcGetReservedWriteCipher(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcReservedEqual(Codec* codec); + +SQLITE_PRIVATE void sqlite3mcSetCodecLastError(Codec* codec, int error); +SQLITE_PRIVATE int sqlite3mcGetCodecLastError(Codec* codec); + +SQLITE_PRIVATE unsigned char* sqlite3mcGetSaltWriteCipher(Codec* codec); + +SQLITE_PRIVATE int sqlite3mcCodecCopy(Codec* codec, Codec* other); + +SQLITE_PRIVATE void sqlite3mcGenerateReadKey(Codec* codec, char* userPassword, int passwordLength, unsigned char* cipherSalt); + +SQLITE_PRIVATE void sqlite3mcGenerateWriteKey(Codec* codec, char* userPassword, int passwordLength, unsigned char* cipherSalt, int usesWal); + +SQLITE_PRIVATE int sqlite3mcEncrypt(Codec* codec, int page, unsigned char* data, int len, int useWriteKey); + +SQLITE_PRIVATE int sqlite3mcDecrypt(Codec* codec, int page, unsigned char* data, int len); + +SQLITE_PRIVATE int sqlite3mcCopyCipher(Codec* codec, int read2write); + +SQLITE_PRIVATE void sqlite3mcPadPassword(char* password, int pswdlen, unsigned char pswd[32]); + +SQLITE_PRIVATE void sqlite3mcRC4(unsigned char* key, int keylen, unsigned char* textin, int textlen, unsigned char* textout); + +SQLITE_PRIVATE void sqlite3mcGetMD5Binary(unsigned char* data, int length, unsigned char* digest); + +SQLITE_PRIVATE void sqlite3mcGetSHABinary(unsigned char* data, int length, unsigned char* digest); + +SQLITE_PRIVATE void sqlite3mcGenerateInitialVector(int seed, unsigned char iv[16]); + +SQLITE_PRIVATE int sqlite3mcIsHexKey(const unsigned char* hex, int len); + +SQLITE_PRIVATE int sqlite3mcConvertHex2Int(char c); + +SQLITE_PRIVATE void sqlite3mcConvertHex2Bin(const unsigned char* hex, int len, unsigned char* bin); + +SQLITE_PRIVATE int sqlite3mcExtractRawKey(const char* password, int passwordLength, + int keyOnly, int keyLength, int saltLength, + unsigned char* key, unsigned char* salt); + +SQLITE_PRIVATE int sqlite3mcConfigureFromUri(sqlite3* db, const char *zDbName, int configDefault); + +SQLITE_PRIVATE void sqlite3mcConfigureSQLCipherVersion(sqlite3* db, int configDefault, int legacyVersion); + +SQLITE_PRIVATE int sqlite3mcCodecAttach(sqlite3* db, int nDb, const char* zPath, const void* zKey, int nKey); + +SQLITE_PRIVATE void sqlite3mcCodecGetKey(sqlite3* db, int nDb, void** zKey, int* nKey); + +SQLITE_PRIVATE void sqlite3mcSecureZeroMemory(void* v, size_t n); + +/* Debugging */ + +#if 0 +#define SQLITE3MC_DEBUG +#define SQLITE3MC_DEBUG_DATA +#endif + +#ifdef SQLITE3MC_DEBUG +#define SQLITE3MC_DEBUG_LOG(...) { fprintf(stdout, __VA_ARGS__); fflush(stdout); } +#else +#define SQLITE3MC_DEBUG_LOG(...) +#endif + +#ifdef SQLITE3MC_DEBUG_DATA +#define SQLITE3MC_DEBUG_HEX(DESC,BUFFER,LEN) \ + { \ + int count; \ + printf(DESC); \ + for (count = 0; count < LEN; ++count) \ + { \ + if (count % 16 == 0) printf("\n%05x: ", count); \ + printf("%02x ", ((unsigned char*) BUFFER)[count]); \ + } \ + printf("\n"); \ + fflush(stdout); \ + } +#else +#define SQLITE3MC_DEBUG_HEX(DESC,BUFFER,LEN) +#endif + +/* +** If encryption was enabled and WAL journal mode was used, +** SQLite3 Multiple Ciphers encrypted the WAL journal frames up to version 1.2.5 +** within the VFS implementation. As a consequence the WAL journal file was not +** compatible with legacy encryption implementations (for example, System.Data.SQLite +** or SQLCipher). Additionally, the implementation of the WAL journal encryption +** was broken, because reading and writing of complete WAL frames was not handled +** correctly. Usually, operating in WAL journal mode worked nevertheless, but after +** crashes the WAL journal file could be corrupted leading to data loss. +** +** Version 1.3.0 introduced a new way to handle WAL journal encryption. The advantage +** is that the WAL journal file is now compatible with legacy encryption implementations. +** Unfortunately the new implementation is not compatible with that used up to version +** 1.2.5. To be able to access WAL journals created by prior versions, the configuration +** parameter 'mc_legacy_wal' was introduced. If the parameter is set to 1, then the +** prior WAL journal encryption mode is used. The default of this parameter can be set +** at compile time by setting the symbol SQLITE3MC_LEGACY_WAL accordingly, but the actual +** value can also be set at runtime using the pragma or the URI parameter 'mc_legacy_wal'. +** +** In principle, operating generally in WAL legacy mode is possible, but it is strongly +** recommended to use the WAL legacy mode only to recover WAL journals left behind by +** prior versions without data loss. +*/ +#ifndef SQLITE3MC_LEGACY_WAL +#define SQLITE3MC_LEGACY_WAL 0 +#endif + +#endif +/*** End of #include "cipher_common.h" ***/ + +#if HAVE_CIPHER_AES_128_CBC || HAVE_CIPHER_AES_256_CBC || HAVE_CIPHER_SQLCIPHER +/* #include "rijndael.h" */ + +#endif + +/* +** RC4 implementation +*/ + +SQLITE_PRIVATE void +sqlite3mcRC4(unsigned char* key, int keylen, + unsigned char* textin, int textlen, + unsigned char* textout) +{ + int i; + int j; + int t; + unsigned char rc4[256]; + + int a = 0; + int b = 0; + unsigned char k; + + for (i = 0; i < 256; i++) + { + rc4[i] = i; + } + j = 0; + for (i = 0; i < 256; i++) + { + t = rc4[i]; + j = (j + t + key[i % keylen]) % 256; + rc4[i] = rc4[j]; + rc4[j] = t; + } + + for (i = 0; i < textlen; i++) + { + a = (a + 1) % 256; + t = rc4[a]; + b = (b + t) % 256; + rc4[a] = rc4[b]; + rc4[b] = t; + k = rc4[(rc4[a] + rc4[b]) % 256]; + textout[i] = textin[i] ^ k; + } +} + +SQLITE_PRIVATE void +sqlite3mcGetMD5Binary(unsigned char* data, int length, unsigned char* digest) +{ + MD5_CTX ctx; + MD5_Init(&ctx); + MD5_Update(&ctx, data, length); + MD5_Final(digest,&ctx); +} + +SQLITE_PRIVATE void +sqlite3mcGetSHABinary(unsigned char* data, int length, unsigned char* digest) +{ + sha256(data, (unsigned int) length, digest); +} + +#define MODMULT(a, b, c, m, s) q = s / a; s = b * (s - a * q) - c * q; if (s < 0) s += m + +SQLITE_PRIVATE void +sqlite3mcGenerateInitialVector(int seed, unsigned char iv[16]) +{ + unsigned char initkey[16]; + int j, q; + int z = seed + 1; + for (j = 0; j < 4; j++) + { + MODMULT(52774, 40692, 3791, 2147483399L, z); + initkey[4*j+0] = 0xff & z; + initkey[4*j+1] = 0xff & (z >> 8); + initkey[4*j+2] = 0xff & (z >> 16); + initkey[4*j+3] = 0xff & (z >> 24); + } + sqlite3mcGetMD5Binary((unsigned char*) initkey, 16, iv); +} + +#if HAVE_CIPHER_AES_128_CBC + +SQLITE_PRIVATE int +sqlite3mcAES128(Rijndael* aesCtx, int page, int encrypt, unsigned char encryptionKey[KEYLENGTH_AES128], + unsigned char* datain, int datalen, unsigned char* dataout) +{ + int rc = SQLITE_OK; + unsigned char initial[16]; + unsigned char pagekey[KEYLENGTH_AES128]; + unsigned char nkey[KEYLENGTH_AES128+4+4]; + int keyLength = KEYLENGTH_AES128; + int nkeylen = keyLength + 4 + 4; + int j; + int direction = (encrypt) ? RIJNDAEL_Direction_Encrypt : RIJNDAEL_Direction_Decrypt; + int len = 0; + + for (j = 0; j < keyLength; j++) + { + nkey[j] = encryptionKey[j]; + } + nkey[keyLength+0] = 0xff & page; + nkey[keyLength+1] = 0xff & (page >> 8); + nkey[keyLength+2] = 0xff & (page >> 16); + nkey[keyLength+3] = 0xff & (page >> 24); + + /* AES encryption needs some 'salt' */ + nkey[keyLength+4] = 0x73; + nkey[keyLength+5] = 0x41; + nkey[keyLength+6] = 0x6c; + nkey[keyLength+7] = 0x54; + + sqlite3mcGetMD5Binary(nkey, nkeylen, pagekey); + sqlite3mcGenerateInitialVector(page, initial); + RijndaelInit(aesCtx, RIJNDAEL_Direction_Mode_CBC, direction, pagekey, RIJNDAEL_Direction_KeyLength_Key16Bytes, initial); + if (encrypt) + { + len = RijndaelBlockEncrypt(aesCtx, datain, datalen*8, dataout); + } + else + { + len = RijndaelBlockDecrypt(aesCtx, datain, datalen*8, dataout); + } + + /* It is a good idea to check the error code */ + if (len < 0) + { + /* AES: Error on encrypting. */ + rc = SQLITE_ERROR; + } + return rc; +} + +#endif + +#if HAVE_CIPHER_AES_256_CBC + +SQLITE_PRIVATE int +sqlite3mcAES256(Rijndael* aesCtx, int page, int encrypt, unsigned char encryptionKey[KEYLENGTH_AES256], + unsigned char* datain, int datalen, unsigned char* dataout) +{ + int rc = SQLITE_OK; + unsigned char initial[16]; + unsigned char pagekey[KEYLENGTH_AES256]; + unsigned char nkey[KEYLENGTH_AES256+4+4]; + int keyLength = KEYLENGTH_AES256; + int nkeylen = keyLength + 4 + 4; + int j; + int direction = (encrypt) ? RIJNDAEL_Direction_Encrypt : RIJNDAEL_Direction_Decrypt; + int len = 0; + + for (j = 0; j < keyLength; j++) + { + nkey[j] = encryptionKey[j]; + } + nkey[keyLength+0] = 0xff & page; + nkey[keyLength+1] = 0xff & (page >> 8); + nkey[keyLength+2] = 0xff & (page >> 16); + nkey[keyLength+3] = 0xff & (page >> 24); + + /* AES encryption needs some 'salt' */ + nkey[keyLength+4] = 0x73; + nkey[keyLength+5] = 0x41; + nkey[keyLength+6] = 0x6c; + nkey[keyLength+7] = 0x54; + + sqlite3mcGetSHABinary(nkey, nkeylen, pagekey); + sqlite3mcGenerateInitialVector(page, initial); + RijndaelInit(aesCtx, RIJNDAEL_Direction_Mode_CBC, direction, pagekey, RIJNDAEL_Direction_KeyLength_Key32Bytes, initial); + if (encrypt) + { + len = RijndaelBlockEncrypt(aesCtx, datain, datalen*8, dataout); + } + else + { + len = RijndaelBlockDecrypt(aesCtx, datain, datalen*8, dataout); + } + + /* It is a good idea to check the error code */ + if (len < 0) + { + /* AES: Error on encrypting. */ + rc = SQLITE_ERROR; + } + return rc; +} + +#endif + +/* Check hex encoding */ +SQLITE_PRIVATE int +sqlite3mcIsHexKey(const unsigned char* hex, int len) +{ + int j; + for (j = 0; j < len; ++j) + { + unsigned char c = hex[j]; + if ((c < '0' || c > '9') && (c < 'A' || c > 'F') && (c < 'a' || c > 'f')) + { + return 0; + } + } + return 1; +} + +/* Convert single hex digit */ +SQLITE_PRIVATE int +sqlite3mcConvertHex2Int(char c) +{ + return (c >= '0' && c <= '9') ? (c)-'0' : + (c >= 'A' && c <= 'F') ? (c)-'A' + 10 : + (c >= 'a' && c <= 'f') ? (c)-'a' + 10 : 0; +} + +/* Convert hex encoded string to binary */ +SQLITE_PRIVATE void +sqlite3mcConvertHex2Bin(const unsigned char* hex, int len, unsigned char* bin) +{ + int j; + for (j = 0; j < len; j += 2) + { + bin[j / 2] = (sqlite3mcConvertHex2Int(hex[j]) << 4) | sqlite3mcConvertHex2Int(hex[j + 1]); + } +} + +/* Extract raw key (and optionally salt) */ +SQLITE_PRIVATE int +sqlite3mcExtractRawKey(const char* password, int passwordLength, + int keyOnly, int keyLength, int saltLength, + unsigned char* key, unsigned char* salt) +{ + /* Bypass key derivation if the key string starts with "raw:" */ + int bypass = 0; + if (passwordLength > 4 && !memcmp(password, "raw:", 4)) + { + const int nRaw = passwordLength - 4; + const unsigned char* zRaw = (const unsigned char*) password + 4; + + if (nRaw == keyLength + saltLength) + { + /* Binary key and salt */ + if (!keyOnly) + { + memcpy(salt, zRaw + keyLength, saltLength); + } + memcpy(key, zRaw, keyLength); + bypass = 1; + } + else if (nRaw == keyLength) + { + /* Binary key */ + memcpy(key, zRaw, keyLength); + bypass = 1; + } + else if (nRaw == 2 * keyLength) + { + /* Hex-encoded key */ + if (sqlite3mcIsHexKey(zRaw, nRaw) != 0) + { + sqlite3mcConvertHex2Bin(zRaw, nRaw, key); + bypass = 1; + } + } + else if (nRaw == 2 * (keyLength + saltLength)) + { + /* Hex-encoded key and salt */ + if (sqlite3mcIsHexKey(zRaw, nRaw) != 0) + { + sqlite3mcConvertHex2Bin(zRaw, 2 * keyLength, key); + if (!keyOnly) + { + sqlite3mcConvertHex2Bin(zRaw + 2 * keyLength, 2 * saltLength, salt); + } + bypass = 1; + } + } + } + else + { + /* SQLCipher syntax for raw key (and optionally salt) */ + if (passwordLength == ((keyLength * 2) + 3) && + sqlite3_strnicmp(password, "x'", 2) == 0 && + sqlite3mcIsHexKey((unsigned char*)(password + 2), keyLength * 2) != 0) + { + sqlite3mcConvertHex2Bin((unsigned char*)(password + 2), passwordLength - 3, key); + bypass = 1; + } + else if (passwordLength == (((keyLength + saltLength) * 2) + 3) && + sqlite3_strnicmp(password, "x'", 2) == 0 && + sqlite3mcIsHexKey((unsigned char*)(password + 2), (keyLength + saltLength) * 2) != 0) + { + sqlite3mcConvertHex2Bin((unsigned char*)(password + 2), keyLength * 2, key); + if (!keyOnly) + { + sqlite3mcConvertHex2Bin((unsigned char*)(password + 2 + keyLength * 2), saltLength * 2, salt); + } + bypass = 1; + } + } + return bypass; +} +/*** End of #include "codec_algos.c" ***/ + + +/* #include "cipher_wxaes128.c" */ +/*** Begin of #include "cipher_wxaes128.c" ***/ +/* +** Name: cipher_wxaes128.c +** Purpose: Implementation of cipher wxSQLite3 AES 128-bit +** Author: Ulrich Telle +** Created: 2020-02-02 +** Copyright: (c) 2006-2024 Ulrich Telle +** License: MIT +*/ + +/* #include "cipher_common.h" */ + + +/* --- AES 128-bit cipher (wxSQLite3) --- */ +#if HAVE_CIPHER_AES_128_CBC + +#define CIPHER_NAME_AES128 "aes128cbc" + +/* +** Configuration parameters for "aes128cbc" +** +** - legacy mode : compatibility with first version (page 1 encrypted) +** possible values: 1 = yes, 0 = no (default) +*/ + +#ifdef WXSQLITE3_USE_OLD_ENCRYPTION_SCHEME +#define AES128_LEGACY_DEFAULT 1 +#else +#define AES128_LEGACY_DEFAULT 0 +#endif + +SQLITE_PRIVATE CipherParams mcAES128Params[] = +{ + { "legacy", AES128_LEGACY_DEFAULT, AES128_LEGACY_DEFAULT, 0, 1 }, + { "legacy_page_size", 0, 0, 0, SQLITE_MAX_PAGE_SIZE }, + CIPHER_PARAMS_SENTINEL +}; + +typedef struct _AES128Cipher +{ + int m_legacy; + int m_legacyPageSize; + int m_keyLength; + uint8_t m_key[KEYLENGTH_AES128]; + Rijndael* m_aes; +} AES128Cipher; + +static void* +AllocateAES128Cipher(sqlite3* db) +{ + AES128Cipher* aesCipher = (AES128Cipher*) sqlite3_malloc(sizeof(AES128Cipher)); + if (aesCipher != NULL) + { + aesCipher->m_aes = (Rijndael*) sqlite3_malloc(sizeof(Rijndael)); + if (aesCipher->m_aes != NULL) + { + aesCipher->m_keyLength = KEYLENGTH_AES128; + memset(aesCipher->m_key, 0, KEYLENGTH_AES128); + RijndaelCreate(aesCipher->m_aes); + } + else + { + sqlite3_free(aesCipher); + aesCipher = NULL; + } + } + if (aesCipher != NULL) + { + CipherParams* cipherParams = sqlite3mcGetCipherParams(db, CIPHER_NAME_AES128); + aesCipher->m_legacy = sqlite3mcGetCipherParameter(cipherParams, "legacy"); + aesCipher->m_legacyPageSize = sqlite3mcGetCipherParameter(cipherParams, "legacy_page_size"); + } + return aesCipher; +} + +static void +FreeAES128Cipher(void* cipher) +{ + AES128Cipher* localCipher = (AES128Cipher*) cipher; + sqlite3mcSecureZeroMemory(localCipher->m_aes, sizeof(Rijndael)); + sqlite3_free(localCipher->m_aes); + sqlite3mcSecureZeroMemory(localCipher, sizeof(AES128Cipher)); + sqlite3_free(localCipher); +} + +static void +CloneAES128Cipher(void* cipherTo, void* cipherFrom) +{ + AES128Cipher* aesCipherTo = (AES128Cipher*) cipherTo; + AES128Cipher* aesCipherFrom = (AES128Cipher*) cipherFrom; + aesCipherTo->m_legacy = aesCipherFrom->m_legacy; + aesCipherTo->m_legacyPageSize = aesCipherFrom->m_legacyPageSize; + aesCipherTo->m_keyLength = aesCipherFrom->m_keyLength; + memcpy(aesCipherTo->m_key, aesCipherFrom->m_key, KEYLENGTH_AES128); + RijndaelInvalidate(aesCipherTo->m_aes); + RijndaelInvalidate(aesCipherFrom->m_aes); +} + +static int +GetLegacyAES128Cipher(void* cipher) +{ + AES128Cipher* aesCipher = (AES128Cipher*)cipher; + return aesCipher->m_legacy; +} + +static int +GetPageSizeAES128Cipher(void* cipher) +{ + AES128Cipher* aesCipher = (AES128Cipher*) cipher; + int pageSize = 0; + if (aesCipher->m_legacy != 0) + { + pageSize = aesCipher->m_legacyPageSize; + if ((pageSize < 512) || (pageSize > SQLITE_MAX_PAGE_SIZE) || (((pageSize - 1) & pageSize) != 0)) + { + pageSize = 0; + } + } + return pageSize; +} + +static int +GetReservedAES128Cipher(void* cipher) +{ + return 0; +} + +static unsigned char* +GetSaltAES128Cipher(void* cipher) +{ + return NULL; +} + +static void +GenerateKeyAES128Cipher(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt) +{ + AES128Cipher* aesCipher = (AES128Cipher*) cipher; + unsigned char userPad[32]; + unsigned char ownerPad[32]; + unsigned char ownerKey[32]; + + unsigned char mkey[MD5_HASHBYTES]; + unsigned char digest[MD5_HASHBYTES]; + int keyLength = MD5_HASHBYTES; + int i, j, k; + MD5_CTX ctx; + + /* Pad passwords */ + sqlite3mcPadPassword(userPassword, passwordLength, userPad); + sqlite3mcPadPassword("", 0, ownerPad); + + /* Compute owner key */ + + MD5_Init(&ctx); + MD5_Update(&ctx, ownerPad, 32); + MD5_Final(digest, &ctx); + + /* only use for the input as many bit as the key consists of */ + for (k = 0; k < 50; ++k) + { + MD5_Init(&ctx); + MD5_Update(&ctx, digest, keyLength); + MD5_Final(digest, &ctx); + } + memcpy(ownerKey, userPad, 32); + for (i = 0; i < 20; ++i) + { + for (j = 0; j < keyLength; ++j) + { + mkey[j] = (digest[j] ^ i); + } + sqlite3mcRC4(mkey, keyLength, ownerKey, 32, ownerKey); + } + + /* Compute encryption key */ + + MD5_Init(&ctx); + MD5_Update(&ctx, userPad, 32); + MD5_Update(&ctx, ownerKey, 32); + MD5_Final(digest, &ctx); + + /* only use the really needed bits as input for the hash */ + for (k = 0; k < 50; ++k) + { + MD5_Init(&ctx); + MD5_Update(&ctx, digest, keyLength); + MD5_Final(digest, &ctx); + } + memcpy(aesCipher->m_key, digest, aesCipher->m_keyLength); +} + +static int +EncryptPageAES128Cipher(void* cipher, int page, unsigned char* data, int len, int reserved) +{ + AES128Cipher* aesCipher = (AES128Cipher*) cipher; + int rc = SQLITE_OK; + if (aesCipher->m_legacy != 0) + { + /* Use the legacy encryption scheme */ + unsigned char* key = aesCipher->m_key; + rc = sqlite3mcAES128(aesCipher->m_aes, page, 1, key, data, len, data); + } + else + { + unsigned char dbHeader[8]; + int offset = 0; + unsigned char* key = aesCipher->m_key; + if (page == 1) + { + /* Save the header bytes remaining unencrypted */ + memcpy(dbHeader, data + 16, 8); + offset = 16; + sqlite3mcAES128(aesCipher->m_aes, page, 1, key, data, 16, data); + } + rc = sqlite3mcAES128(aesCipher->m_aes, page, 1, key, data + offset, len - offset, data + offset); + if (page == 1) + { + /* Move the encrypted header bytes 16..23 to a safe position */ + memcpy(data + 8, data + 16, 8); + /* Restore the unencrypted header bytes 16..23 */ + memcpy(data + 16, dbHeader, 8); + } + } + return rc; +} + +static int +DecryptPageAES128Cipher(void* cipher, int page, unsigned char* data, int len, int reserved, int hmacCheck) +{ + AES128Cipher* aesCipher = (AES128Cipher*) cipher; + int rc = SQLITE_OK; + if (aesCipher->m_legacy != 0) + { + /* Use the legacy encryption scheme */ + rc = sqlite3mcAES128(aesCipher->m_aes, page, 0, aesCipher->m_key, data, len, data); + } + else + { + unsigned char dbHeader[8]; + int dbPageSize; + int offset = 0; + if (page == 1) + { + /* Save (unencrypted) header bytes 16..23 */ + memcpy(dbHeader, data + 16, 8); + /* Determine page size */ + dbPageSize = (dbHeader[0] << 8) | (dbHeader[1] << 16); + /* Check whether the database header is valid */ + /* If yes, the database follows the new encryption scheme, otherwise use the previous encryption scheme */ + if ((dbPageSize >= 512) && (dbPageSize <= SQLITE_MAX_PAGE_SIZE) && (((dbPageSize - 1) & dbPageSize) == 0) && + (dbHeader[5] == 0x40) && (dbHeader[6] == 0x20) && (dbHeader[7] == 0x20)) + { + /* Restore encrypted bytes 16..23 for new encryption scheme */ + memcpy(data + 16, data + 8, 8); + offset = 16; + } + } + rc = sqlite3mcAES128(aesCipher->m_aes, page, 0, aesCipher->m_key, data + offset, len - offset, data + offset); + if (page == 1 && offset != 0) + { + /* Verify the database header */ + if (memcmp(dbHeader, data + 16, 8) == 0) + { + memcpy(data, SQLITE_FILE_HEADER, 16); + } + } + } + return rc; +} + +SQLITE_PRIVATE const CipherDescriptor mcAES128Descriptor = +{ + CIPHER_NAME_AES128, + AllocateAES128Cipher, + FreeAES128Cipher, + CloneAES128Cipher, + GetLegacyAES128Cipher, + GetPageSizeAES128Cipher, + GetReservedAES128Cipher, + GetSaltAES128Cipher, + GenerateKeyAES128Cipher, + EncryptPageAES128Cipher, + DecryptPageAES128Cipher +}; +#endif +/*** End of #include "cipher_wxaes128.c" ***/ + +/* #include "cipher_wxaes256.c" */ +/*** Begin of #include "cipher_wxaes256.c" ***/ +/* +** Name: cipher_wxaes256.c +** Purpose: Implementation of cipher wxSQLite3 AES 256-bit +** Author: Ulrich Telle +** Created: 2020-02-02 +** Copyright: (c) 2006-2024 Ulrich Telle +** License: MIT +*/ + +/* #include "cipher_common.h" */ + + +/* --- AES 256-bit cipher (wxSQLite3) --- */ +#if HAVE_CIPHER_AES_256_CBC + +#define CIPHER_NAME_AES256 "aes256cbc" + +/* +** Configuration parameters for "aes256cbc" ** ** - legacy mode : compatibility with first version (page 1 encrypted) ** possible values: 1 = yes, 0 = no (default) @@ -281708,9 +334367,9 @@ static void FreeAES256Cipher(void* cipher) { AES256Cipher* aesCipher = (AES256Cipher*) cipher; - memset(aesCipher->m_aes, 0, sizeof(Rijndael)); + sqlite3mcSecureZeroMemory(aesCipher->m_aes, sizeof(Rijndael)); sqlite3_free(aesCipher->m_aes); - memset(aesCipher, 0, sizeof(AES256Cipher)); + sqlite3mcSecureZeroMemory(aesCipher, sizeof(AES256Cipher)); sqlite3_free(aesCipher); } @@ -281886,7 +334545,7 @@ SQLITE_PRIVATE const CipherDescriptor mcAES256Descriptor = ** Purpose: Implementation of cipher ChaCha20 - Poly1305 ** Author: Ulrich Telle ** Created: 2020-02-02 -** Copyright: (c) 2006-2024 Ulrich Telle +** Copyright: (c) 2006-2026 Ulrich Telle ** License: MIT */ @@ -281919,9 +334578,10 @@ SQLITE_PRIVATE const CipherDescriptor mcAES256Descriptor = SQLITE_PRIVATE CipherParams mcChaCha20Params[] = { - { "legacy", CHACHA20_LEGACY_DEFAULT, CHACHA20_LEGACY_DEFAULT, 0, 1 }, - { "legacy_page_size", CHACHA20_LEGACY_PAGE_SIZE, CHACHA20_LEGACY_PAGE_SIZE, 0, SQLITE_MAX_PAGE_SIZE }, - { "kdf_iter", CHACHA20_KDF_ITER_DEFAULT, CHACHA20_KDF_ITER_DEFAULT, 1, 0x7fffffff }, + { "legacy", CHACHA20_LEGACY_DEFAULT, CHACHA20_LEGACY_DEFAULT, 0, 1 }, + { "legacy_page_size", CHACHA20_LEGACY_PAGE_SIZE, CHACHA20_LEGACY_PAGE_SIZE, 0, SQLITE_MAX_PAGE_SIZE }, + { "kdf_iter", CHACHA20_KDF_ITER_DEFAULT, CHACHA20_KDF_ITER_DEFAULT, 1, 0x7fffffff }, + { "plaintext_header_size", 0, 0, 0, 100 /* restrict to db header size */ }, CIPHER_PARAMS_SENTINEL }; @@ -281930,12 +334590,14 @@ SQLITE_PRIVATE CipherParams mcChaCha20Params[] = #define PAGE_NONCE_LEN_CHACHA20 16 #define PAGE_TAG_LEN_CHACHA20 16 #define PAGE_RESERVED_CHACHA20 (PAGE_NONCE_LEN_CHACHA20 + PAGE_TAG_LEN_CHACHA20) +#define OTK_LEN_CHACHA20 64 typedef struct _chacha20Cipher { int m_legacy; int m_legacyPageSize; int m_kdfIter; + int m_plaintextHeaderSize; int m_keyLength; uint8_t m_key[KEYLENGTH_CHACHA20]; uint8_t m_salt[SALTLENGTH_CHACHA20]; @@ -281962,6 +334624,7 @@ AllocateChaCha20Cipher(sqlite3* db) { chacha20Cipher->m_kdfIter = SQLEET_KDF_ITER; } + chacha20Cipher->m_plaintextHeaderSize = sqlite3mcGetCipherParameter(cipherParams, "plaintext_header_size"); } return chacha20Cipher; } @@ -281970,7 +334633,7 @@ static void FreeChaCha20Cipher(void* cipher) { ChaCha20Cipher* chacha20Cipher = (ChaCha20Cipher*) cipher; - memset(chacha20Cipher, 0, sizeof(ChaCha20Cipher)); + sqlite3mcSecureZeroMemory(chacha20Cipher, sizeof(ChaCha20Cipher)); sqlite3_free(chacha20Cipher); } @@ -281982,6 +334645,7 @@ CloneChaCha20Cipher(void* cipherTo, void* cipherFrom) chacha20CipherTo->m_legacy = chacha20CipherFrom->m_legacy; chacha20CipherTo->m_legacyPageSize = chacha20CipherFrom->m_legacyPageSize; chacha20CipherTo->m_kdfIter = chacha20CipherFrom->m_kdfIter; + chacha20CipherTo->m_plaintextHeaderSize = chacha20CipherFrom->m_plaintextHeaderSize; chacha20CipherTo->m_keyLength = chacha20CipherFrom->m_keyLength; memcpy(chacha20CipherTo->m_key, chacha20CipherFrom->m_key, KEYLENGTH_CHACHA20); memcpy(chacha20CipherTo->m_salt, chacha20CipherFrom->m_salt, SALTLENGTH_CHACHA20); @@ -282027,9 +334691,13 @@ static void GenerateKeyChaCha20Cipher(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt) { ChaCha20Cipher* chacha20Cipher = (ChaCha20Cipher*) cipher; - int bypass = 0; int keyOnly = 1; + if (rekey == 2) + { + /* (rekey == 2) means database is in WAL mode, thus don't change the cipher salt */ + rekey = (cipherSalt != NULL) ? 0 : 1; + } if (rekey || cipherSalt == NULL) { chacha20_rng(chacha20Cipher->m_salt, SALTLENGTH_CHACHA20); @@ -282038,54 +334706,14 @@ GenerateKeyChaCha20Cipher(void* cipher, char* userPassword, int passwordLength, else { memcpy(chacha20Cipher->m_salt, cipherSalt, SALTLENGTH_CHACHA20); + if (chacha20Cipher->m_plaintextHeaderSize > 0) + keyOnly = 0; } - /* Bypass key derivation if the key string starts with "raw:" */ - if (passwordLength > 4 && !memcmp(userPassword, "raw:", 4)) - { - const int nRaw = passwordLength - 4; - const unsigned char* zRaw = (const unsigned char*) userPassword + 4; - switch (nRaw) - { - /* Binary key (and salt) */ - case KEYLENGTH_CHACHA20 + SALTLENGTH_CHACHA20: - if (!keyOnly) - { - memcpy(chacha20Cipher->m_salt, zRaw + KEYLENGTH_CHACHA20, SALTLENGTH_CHACHA20); - } - /* fall-through */ - case KEYLENGTH_CHACHA20: - memcpy(chacha20Cipher->m_key, zRaw, KEYLENGTH_CHACHA20); - bypass = 1; - break; - - /* Hex-encoded key */ - case 2 * KEYLENGTH_CHACHA20: - if (sqlite3mcIsHexKey(zRaw, nRaw) != 0) - { - sqlite3mcConvertHex2Bin(zRaw, nRaw, chacha20Cipher->m_key); - bypass = 1; - } - break; - - /* Hex-encoded key and salt */ - case 2 * (KEYLENGTH_CHACHA20 + SALTLENGTH_CHACHA20): - if (sqlite3mcIsHexKey(zRaw, nRaw) != 0) - { - sqlite3mcConvertHex2Bin(zRaw, 2 * KEYLENGTH_CHACHA20, chacha20Cipher->m_key); - if (!keyOnly) - { - sqlite3mcConvertHex2Bin(zRaw + 2 * KEYLENGTH_CHACHA20, 2 * SALTLENGTH_CHACHA20, chacha20Cipher->m_salt); - } - bypass = 1; - } - break; - - default: - break; - } - } - + /* Bypass key derivation, if raw key (and optionally salt) are given */ + int bypass = sqlite3mcExtractRawKey(userPassword, passwordLength, + keyOnly, KEYLENGTH_CHACHA20, SALTLENGTH_CHACHA20, + chacha20Cipher->m_key, chacha20Cipher->m_salt); if (!bypass) { fastpbkdf2_hmac_sha256((unsigned char*)userPassword, passwordLength, @@ -282106,11 +334734,28 @@ EncryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, int legacy = chacha20Cipher->m_legacy; int nReserved = (reserved == 0 && legacy == 0) ? 0 : GetReservedChaCha20Cipher(cipher); int n = len - nReserved; + int usePlaintextHeader = 0; /* Generate one-time keys */ - uint8_t otk[64]; + uint8_t otk[OTK_LEN_CHACHA20]; uint32_t counter; - int offset; + int offset = 0; + + /* Check whether a plaintext header should be used */ + if (page == 1) + { + int plaintextHeaderSize = chacha20Cipher->m_plaintextHeaderSize; + if (plaintextHeaderSize > 0) + { + usePlaintextHeader = 1; + offset = (chacha20Cipher->m_legacy != 0) ? plaintextHeaderSize : + (plaintextHeaderSize > CIPHER_PAGE1_OFFSET) ? plaintextHeaderSize : CIPHER_PAGE1_OFFSET; + } + else + { + offset = (chacha20Cipher->m_legacy != 0) ? 0 : CIPHER_PAGE1_OFFSET; + } + } /* Check whether number of required reserved bytes and actually reserved bytes match */ if ((legacy == 0 && nReserved > reserved) || ((legacy != 0 && nReserved != reserved))) @@ -282121,14 +334766,13 @@ EncryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, if (nReserved > 0) { /* Encrypt and authenticate */ - memset(otk, 0, 64); + memset(otk, 0, OTK_LEN_CHACHA20); chacha20_rng(data + n, PAGE_NONCE_LEN_CHACHA20); counter = LOAD32_LE(data + n + PAGE_NONCE_LEN_CHACHA20 - 4) ^ page; - chacha20_xor(otk, 64, chacha20Cipher->m_key, data + n, counter); + chacha20_xor(otk, OTK_LEN_CHACHA20, chacha20Cipher->m_key, data + n, counter); - offset = (page == 1) ? (chacha20Cipher->m_legacy != 0) ? 0 : CIPHER_PAGE1_OFFSET : 0; chacha20_xor(data + offset, n - offset, otk + 32, data + n, counter + 1); - if (page == 1) + if (page == 1 && usePlaintextHeader == 0) { memcpy(data, chacha20Cipher->m_salt, SALTLENGTH_CHACHA20); } @@ -282138,20 +334782,22 @@ EncryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, { /* Encrypt only */ uint8_t nonce[PAGE_NONCE_LEN_CHACHA20]; - memset(otk, 0, 64); + memset(otk, 0, OTK_LEN_CHACHA20); sqlite3mcGenerateInitialVector(page, nonce); counter = LOAD32_LE(&nonce[PAGE_NONCE_LEN_CHACHA20 - 4]) ^ page; - chacha20_xor(otk, 64, chacha20Cipher->m_key, nonce, counter); + chacha20_xor(otk, OTK_LEN_CHACHA20, chacha20Cipher->m_key, nonce, counter); /* Encrypt */ - offset = (page == 1) ? (chacha20Cipher->m_legacy != 0) ? 0 : CIPHER_PAGE1_OFFSET : 0; chacha20_xor(data + offset, n - offset, otk + 32, nonce, counter + 1); - if (page == 1) + if (page == 1 && usePlaintextHeader == 0) { memcpy(data, chacha20Cipher->m_salt, SALTLENGTH_CHACHA20); } } + /* Zero out otk array */ + sqlite3mcSecureZeroMemory(otk, OTK_LEN_CHACHA20); + return rc; } @@ -282176,12 +334822,29 @@ DecryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, int legacy = chacha20Cipher->m_legacy; int nReserved = (reserved == 0 && legacy == 0) ? 0 : GetReservedChaCha20Cipher(cipher); int n = len - nReserved; + int usePlaintextHeader = 0; /* Generate one-time keys */ - uint8_t otk[64]; + uint8_t otk[OTK_LEN_CHACHA20]; uint32_t counter; uint8_t tag[16]; - int offset; + int offset = 0; + + /* Check whether a plaintext header should be used */ + if (page == 1) + { + int plaintextHeaderSize = chacha20Cipher->m_plaintextHeaderSize; + if (plaintextHeaderSize > 0) + { + usePlaintextHeader = 1; + offset = (chacha20Cipher->m_legacy != 0) ? plaintextHeaderSize : + (plaintextHeaderSize > CIPHER_PAGE1_OFFSET) ? plaintextHeaderSize : CIPHER_PAGE1_OFFSET; + } + else + { + offset = (chacha20Cipher->m_legacy != 0) ? 0 : CIPHER_PAGE1_OFFSET; + } + } /* Check whether number of required reserved bytes and actually reserved bytes match */ if ((legacy == 0 && nReserved > reserved) || ((legacy != 0 && nReserved != reserved))) @@ -282193,14 +334856,13 @@ DecryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, { int allzero = 0; /* Decrypt and verify MAC */ - memset(otk, 0, 64); + memset(otk, 0, OTK_LEN_CHACHA20); counter = LOAD32_LE(data + n + PAGE_NONCE_LEN_CHACHA20 - 4) ^ page; - chacha20_xor(otk, 64, chacha20Cipher->m_key, data + n, counter); + chacha20_xor(otk, OTK_LEN_CHACHA20, chacha20Cipher->m_key, data + n, counter); /* Determine MAC and decrypt */ allzero = chacha20_ismemset(data, 0, n); poly1305(data, n + PAGE_NONCE_LEN_CHACHA20, otk, tag); - offset = (page == 1) ? (chacha20Cipher->m_legacy != 0) ? 0 : CIPHER_PAGE1_OFFSET : 0; chacha20_xor(data + offset, n - offset, otk + 32, data + n, counter + 1); if (hmacCheck != 0) @@ -282210,7 +334872,7 @@ DecryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, { SQLITE3MC_DEBUG_LOG("decrypt: codec=%p page=%d\n", chacha20Cipher, page); SQLITE3MC_DEBUG_HEX("decrypt key:", chacha20Cipher->m_key, 32); - SQLITE3MC_DEBUG_HEX("decrypt otk:", otk, 64); + SQLITE3MC_DEBUG_HEX("decrypt otk:", otk, OTK_LEN_CHACHA20); SQLITE3MC_DEBUG_HEX("decrypt data+00:", data, 16); SQLITE3MC_DEBUG_HEX("decrypt data+24:", data + 24, 16); SQLITE3MC_DEBUG_HEX("decrypt data+n:", data + n, 16); @@ -282220,7 +334882,7 @@ DecryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, rc = (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; } } - if (page == 1 && rc == SQLITE_OK) + if (page == 1 && usePlaintextHeader == 0 && rc == SQLITE_OK) { memcpy(data, SQLITE_FILE_HEADER, 16); } @@ -282229,20 +334891,22 @@ DecryptPageChaCha20Cipher(void* cipher, int page, unsigned char* data, int len, { /* Decrypt only */ uint8_t nonce[PAGE_NONCE_LEN_CHACHA20]; - memset(otk, 0, 64); + memset(otk, 0, OTK_LEN_CHACHA20); sqlite3mcGenerateInitialVector(page, nonce); counter = LOAD32_LE(&nonce[PAGE_NONCE_LEN_CHACHA20 - 4]) ^ page; - chacha20_xor(otk, 64, chacha20Cipher->m_key, nonce, counter); + chacha20_xor(otk, OTK_LEN_CHACHA20, chacha20Cipher->m_key, nonce, counter); /* Decrypt */ - offset = (page == 1) ? (chacha20Cipher->m_legacy != 0) ? 0 : CIPHER_PAGE1_OFFSET : 0; chacha20_xor(data + offset, n - offset, otk + 32, nonce, counter + 1); - if (page == 1) + if (page == 1 && usePlaintextHeader == 0) { memcpy(data, SQLITE_FILE_HEADER, 16); } } + /* Zero out otk array */ + sqlite3mcSecureZeroMemory(otk, OTK_LEN_CHACHA20); + return rc; } @@ -282270,7 +334934,7 @@ SQLITE_PRIVATE const CipherDescriptor mcChaCha20Descriptor = ** Purpose: Implementation of cipher SQLCipher (version 1 to 4) ** Author: Ulrich Telle ** Created: 2020-02-02 -** Copyright: (c) 2006-2024 Ulrich Telle +** Copyright: (c) 2006-2026 Ulrich Telle ** License: MIT */ @@ -282408,10 +335072,9 @@ AllocateSQLCipherCipher(sqlite3* db) sqlCipherCipher->m_kdfAlgorithm = sqlite3mcGetCipherParameter(cipherParams, "kdf_algorithm"); sqlCipherCipher->m_hmacAlgorithm = sqlite3mcGetCipherParameter(cipherParams, "hmac_algorithm"); sqlCipherCipher->m_hmacAlgorithmCompat = sqlite3mcGetCipherParameter(cipherParams, "hmac_algorithm_compat"); - if (sqlCipherCipher->m_legacy >= SQLCIPHER_VERSION_4) + if (sqlCipherCipher->m_legacy == 0 || sqlCipherCipher->m_legacy >= SQLCIPHER_VERSION_4) { - int plaintextHeaderSize = sqlite3mcGetCipherParameter(cipherParams, "plaintext_header_size"); - sqlCipherCipher->m_plaintextHeaderSize = (plaintextHeaderSize >=0 && plaintextHeaderSize <= 100 && plaintextHeaderSize % 16 == 0) ? plaintextHeaderSize : 0; + sqlCipherCipher->m_plaintextHeaderSize = sqlite3mcGetCipherParameter(cipherParams, "plaintext_header_size"); } else { @@ -282425,9 +335088,9 @@ static void FreeSQLCipherCipher(void* cipher) { SQLCipherCipher* sqlCipherCipher = (SQLCipherCipher*) cipher; - memset(sqlCipherCipher->m_aes, 0, sizeof(Rijndael)); + sqlite3mcSecureZeroMemory(sqlCipherCipher->m_aes, sizeof(Rijndael)); sqlite3_free(sqlCipherCipher->m_aes); - memset(sqlCipherCipher, 0, sizeof(SQLCipherCipher)); + sqlite3mcSecureZeroMemory(sqlCipherCipher, sizeof(SQLCipherCipher)); sqlite3_free(sqlCipherCipher); } @@ -282512,29 +335175,29 @@ GenerateKeySQLCipherCipher(void* cipher, char* userPassword, int passwordLength, { SQLCipherCipher* sqlCipherCipher = (SQLCipherCipher*) cipher; + int keyOnly = 1; + if (rekey == 2) + { + /* (rekey == 2) means database is in WAL mode, thus don't change the cipher salt */ + rekey = (cipherSalt != NULL) ? 0 : 1; + } if (rekey || cipherSalt == NULL) { chacha20_rng(sqlCipherCipher->m_salt, SALTLENGTH_SQLCIPHER); + keyOnly = 0; } else { memcpy(sqlCipherCipher->m_salt, cipherSalt, SALTLENGTH_SQLCIPHER); + if (sqlCipherCipher->m_plaintextHeaderSize > 0) + keyOnly = 0; } - if (passwordLength == ((KEYLENGTH_SQLCIPHER * 2) + 3) && - sqlite3_strnicmp(userPassword, "x'", 2) == 0 && - sqlite3mcIsHexKey((unsigned char*) (userPassword + 2), KEYLENGTH_SQLCIPHER * 2) != 0) - { - sqlite3mcConvertHex2Bin((unsigned char*) (userPassword + 2), passwordLength - 3, sqlCipherCipher->m_key); - } - else if (passwordLength == (((KEYLENGTH_SQLCIPHER + SALTLENGTH_SQLCIPHER) * 2) + 3) && - sqlite3_strnicmp(userPassword, "x'", 2) == 0 && - sqlite3mcIsHexKey((unsigned char*) (userPassword + 2), (KEYLENGTH_SQLCIPHER + SALTLENGTH_SQLCIPHER) * 2) != 0) - { - sqlite3mcConvertHex2Bin((unsigned char*) (userPassword + 2), KEYLENGTH_SQLCIPHER * 2, sqlCipherCipher->m_key); - sqlite3mcConvertHex2Bin((unsigned char*) (userPassword + 2 + KEYLENGTH_SQLCIPHER * 2), SALTLENGTH_SQLCIPHER * 2, sqlCipherCipher->m_salt); - } - else + /* Bypass key derivation, if raw key (and optionally salt) are given */ + int bypass = sqlite3mcExtractRawKey(userPassword, passwordLength, + keyOnly, KEYLENGTH_SQLCIPHER, SALTLENGTH_SQLCIPHER, + sqlCipherCipher->m_key, sqlCipherCipher->m_salt); + if (!bypass) { switch (sqlCipherCipher->m_kdfAlgorithm) { @@ -282624,16 +335287,27 @@ EncryptPageSQLCipherCipher(void* cipher, int page, unsigned char* data, int len, int legacy = sqlCipherCipher->m_legacy; int nReserved = (reserved == 0 && legacy == 0) ? 0 : GetReservedSQLCipherCipher(cipher); int n = len - nReserved; - int offset = (page == 1) ? (sqlCipherCipher->m_legacy != 0) ? 16 : 24 : 0; + int offset = 0; int blen; unsigned char iv[128]; int usePlaintextHeader = 0; /* Check whether a plaintext header should be used */ - if (page == 1 && sqlCipherCipher->m_legacy >= SQLCIPHER_VERSION_4 && sqlCipherCipher->m_plaintextHeaderSize > 0) + if (page == 1) { - usePlaintextHeader = 1; - offset = sqlCipherCipher->m_plaintextHeaderSize; + int plaintextHeaderSize = sqlCipherCipher->m_plaintextHeaderSize; + offset = (sqlCipherCipher->m_legacy != 0) ? 16 : 24; + if (plaintextHeaderSize > 0) + { + usePlaintextHeader = 1; + if (sqlCipherCipher->m_legacy == 0 || sqlCipherCipher->m_legacy >= SQLCIPHER_VERSION_4) + { + if (plaintextHeaderSize > offset) + { + offset = plaintextHeaderSize; + } + } + } } /* Check whether number of required reserved bytes and actually reserved bytes match */ @@ -282698,17 +335372,28 @@ DecryptPageSQLCipherCipher(void* cipher, int page, unsigned char* data, int len, int legacy = sqlCipherCipher->m_legacy; int nReserved = (reserved == 0 && legacy == 0) ? 0 : GetReservedSQLCipherCipher(cipher); int n = len - nReserved; - int offset = (page == 1) ? (sqlCipherCipher->m_legacy != 0) ? 16 : 24 : 0; + int offset = 0; int hmacOk = 1; int blen; unsigned char iv[128]; int usePlaintextHeader = 0; /* Check whether a plaintext header should be used */ - if (page == 1 && sqlCipherCipher->m_legacy >= SQLCIPHER_VERSION_4 && sqlCipherCipher->m_plaintextHeaderSize > 0) + if (page == 1) { - usePlaintextHeader = 1; - offset = sqlCipherCipher->m_plaintextHeaderSize; + int plaintextHeaderSize = sqlCipherCipher->m_plaintextHeaderSize; + offset = (sqlCipherCipher->m_legacy != 0) ? 16 : 24; + if (plaintextHeaderSize > 0) + { + usePlaintextHeader = 1; + if (sqlCipherCipher->m_legacy == 0 || sqlCipherCipher->m_legacy >= SQLCIPHER_VERSION_4) + { + if (plaintextHeaderSize > offset) + { + offset = plaintextHeaderSize; + } + } + } } /* Check whether number of required reserved bytes and actually reserved bytes match */ @@ -282857,7 +335542,7 @@ static void FreeRC4Cipher(void* cipher) { RC4Cipher* localCipher = (RC4Cipher*) cipher; - memset(localCipher, 0, sizeof(RC4Cipher)); + sqlite3mcSecureZeroMemory(localCipher, sizeof(RC4Cipher)); sqlite3_free(localCipher); } @@ -282971,7 +335656,7 @@ SQLITE_PRIVATE const CipherDescriptor mcRC4Descriptor = ** Purpose: Implementation of cipher Ascon ** Author: Ulrich Telle ** Created: 2023-11-13 -** Copyright: (c) 2023-2024 Ulrich Telle +** Copyright: (c) 2023-2026 Ulrich Telle ** License: MIT */ @@ -282991,6 +335676,11 @@ SQLITE_PRIVATE const CipherDescriptor mcRC4Descriptor = #define ASCON128_KDF_ITER_DEFAULT 64007 +/* Make ASCON code static unless told otherwise */ +#ifndef ASCON_API +#define ASCON_API static +#endif + /* #include "ascon/prolog.h" */ /*** Begin of #include "ascon/prolog.h" ***/ /* @@ -283016,6 +335706,43 @@ SQLITE_PRIVATE const CipherDescriptor mcRC4Descriptor = #include #include +/* #include "api.h" */ +/*** Begin of #include "api.h" ***/ +/* +** Name: api.h +** Purpose: Definition of preprocessor symbols +** Based on: Public domain Ascon reference implementation +** and optimized variants for 32- and 64-bit +** (see https://github.com/ascon/ascon-c) +** Remarks: API functions adapted for use in SQLite3 Multiple Ciphers +** Combined symbols from AEAD and HASH +** Modified by: Ulrich Telle +** Copyright: (c) 2023-2026 Ulrich Telle +** License: MIT +*/ + +#define CRYPTO_VERSION "1.2.7" +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 16 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 +#define ASCON_AEAD_RATE 8 + +#define CRYPTO_BYTES 32 +#define ASCON_HASH_BYTES 32 /* HASH */ +#define ASCON_HASH_ROUNDS 12 + +#define ASCON_AEAD_KEY_LEN CRYPTO_KEYBYTES +#define ASCON_AEAD_NONCE_LEN CRYPTO_NPUBBYTES +#define ASCON_AEAD_TAG_LEN CRYPTO_ABYTES +#define ASCON_SALT_LEN CRYPTO_NPUBBYTES + +#ifndef ASCON_API +#define ASCON_API +#endif +/*** End of #include "api.h" ***/ + /* #include "bendian.h" */ /*** Begin of #include "bendian.h" ***/ #ifndef ENDIAN_H_ @@ -283098,12 +335825,15 @@ typedef union { #define ASCON_LOAD(b, n) ASCON_LOADBYTES(b, n) #define ASCON_STORE(b, w, n) ASCON_STOREBYTES(b, w, n) +ASCON_API forceinline uint64_t ASCON_ROR(uint64_t x, int n) { return x >> n | x << (-n & 63); } +ASCON_API forceinline uint64_t ASCON_KEYROT(uint64_t lo2hi, uint64_t hi2lo) { return lo2hi << 32 | hi2lo >> 32; } +ASCON_API forceinline int ASCON_NOTZERO(uint64_t a, uint64_t b) { uint64_t result = a | b; result |= result >> 32; @@ -283112,29 +335842,36 @@ forceinline int ASCON_NOTZERO(uint64_t a, uint64_t b) { return ((((int)(result & 0xff) - 1) >> 8) & 1) - 1; } +ASCON_API forceinline uint64_t ASCON_PAD(int i) { return 0x80ull << (56 - 8 * i); } +ASCON_API forceinline uint64_t ASCON_DSEP() { return 0x01; } +ASCON_API forceinline uint64_t ASCON_PRFS_MLEN(uint64_t len) { return len << 51; } +ASCON_API forceinline uint64_t ASCON_CLEAR(uint64_t w, int n) { /* undefined for n == 0 */ uint64_t mask = ~0ull >> (8 * n); return w & mask; } +ASCON_API forceinline uint64_t ASCON_MASK(int n) { /* undefined for n == 0 */ return ~0ull >> (64 - 8 * n); } +ASCON_API forceinline uint64_t ASCON_LOADBYTES(const uint8_t* bytes, int n) { uint64_t x = 0; memcpy(&x, bytes, n); return ASCON_U64TOWORD(x); } +ASCON_API forceinline void ASCON_STOREBYTES(uint8_t* bytes, uint64_t w, int n) { uint64_t x = ASCON_WORDTOU64(w); memcpy(bytes, &x, n); @@ -283162,37 +335899,6 @@ forceinline void ASCON_STOREBYTES(uint8_t* bytes, uint64_t w, int n) { */ /* #include "api.h" */ -/*** Begin of #include "api.h" ***/ -/* -** Name: api.h -** Purpose: Definition of preprocessor symbols -** Based on: Public domain Ascon reference implementation -** and optimized variants for 32- and 64-bit -** (see https://github.com/ascon/ascon-c) -** Remarks: API functions adapted for use in SQLite3 Multiple Ciphers -** Combined symbols from AEAD and HASH -** Modified by: Ulrich Telle -** Copyright: (c) 2023-2023 Ulrich Telle -** License: MIT -*/ - -#define CRYPTO_VERSION "1.2.7" -#define CRYPTO_KEYBYTES 16 -#define CRYPTO_NSECBYTES 0 -#define CRYPTO_NPUBBYTES 16 -#define CRYPTO_ABYTES 16 -#define CRYPTO_NOOVERLAP 1 -#define ASCON_AEAD_RATE 8 - -#define CRYPTO_BYTES 32 -#define ASCON_HASH_BYTES 32 /* HASH */ -#define ASCON_HASH_ROUNDS 12 - -#define ASCON_AEAD_KEY_LEN CRYPTO_KEYBYTES -#define ASCON_AEAD_NONCE_LEN CRYPTO_NPUBBYTES -#define ASCON_AEAD_TAG_LEN CRYPTO_ABYTES -#define ASCON_SALT_LEN CRYPTO_NPUBBYTES -/*** End of #include "api.h" ***/ /* #include "ascon.h" */ /*** Begin of #include "ascon.h" ***/ @@ -283245,14 +335951,20 @@ typedef union { #if !ASCON_INLINE_MODE +ASCON_API void ascon_loadkey(ascon_key_t* key, const uint8_t* k); +ASCON_API void ascon_initaead(ascon_state_t* s, const ascon_key_t* key, const uint8_t* npub); +ASCON_API void ascon_adata(ascon_state_t* s, const uint8_t* ad, uint64_t adlen); +ASCON_API void ascon_encrypt(ascon_state_t* s, uint8_t* c, const uint8_t* m, uint64_t mlen); +ASCON_API void ascon_decrypt(ascon_state_t* s, uint8_t* m, const uint8_t* c, uint64_t clen); +ASCON_API void ascon_final(ascon_state_t* s, const ascon_key_t* k); #endif @@ -283263,8 +335975,11 @@ void ascon_final(ascon_state_t* s, const ascon_key_t* k); #if !ASCON_INLINE_MODE +ASCON_API void ascon_inithash(ascon_state_t* s); +ASCON_API void ascon_absorb(ascon_state_t* s, const uint8_t* in, uint64_t inlen); +ASCON_API void ascon_squeeze(ascon_state_t* s, uint8_t* out, uint64_t outlen); #endif @@ -283457,7 +336172,9 @@ int ascon_aead_decrypt(uint8_t* mtext, const uint8_t* ctext, uint64_t clen, /* #include "word.h" */ +ASCON_API void ascon_printword(const char* text, const uint64_t x); +ASCON_API void ascon_printstate(const char* text, const ascon_state_t* s); #else @@ -283513,6 +336230,7 @@ void ascon_printstate(const char* text, const ascon_state_t* s); /* #include "word.h" */ +ASCON_API forceinline void ASCON_ROUND(ascon_state_t* s, uint8_t C) { ascon_state_t t; /* round constant */ @@ -283544,6 +336262,7 @@ forceinline void ASCON_ROUND(ascon_state_t* s, uint8_t C) { ascon_printstate(" round output", s); } +ASCON_API forceinline void ASCON_PROUNDS(ascon_state_t* s, int nr) { int i = ASCON_START(nr); do { @@ -283573,6 +336292,7 @@ forceinline void ASCON_PROUNDS(ascon_state_t* s, int nr) { /* #include "word.h" */ +ASCON_API forceinline void ASCON_ROUND(ascon_state_t* s, uint8_t C) { uint64_t xtemp; /* round constant */ @@ -283605,6 +336325,7 @@ forceinline void ASCON_ROUND(ascon_state_t* s, uint8_t C) { ascon_printstate(" round output", s); } +ASCON_API forceinline void ASCON_PROUNDS(ascon_state_t* s, int nr) { int i = ASCON_START(nr); do { @@ -283622,6 +336343,7 @@ forceinline void ASCON_PROUNDS(ascon_state_t* s, int nr) { /*** End of #include "round.h" ***/ +ASCON_API forceinline void ASCON_P12ROUNDS(ascon_state_t* s) { ASCON_ROUND(s, ASCON_RC0); ASCON_ROUND(s, ASCON_RC1); @@ -283637,6 +336359,7 @@ forceinline void ASCON_P12ROUNDS(ascon_state_t* s) { ASCON_ROUND(s, ASCON_RCb); } +ASCON_API forceinline void ASCON_P8ROUNDS(ascon_state_t* s) { ASCON_ROUND(s, ASCON_RC4); ASCON_ROUND(s, ASCON_RC5); @@ -283648,6 +336371,7 @@ forceinline void ASCON_P8ROUNDS(ascon_state_t* s) { ASCON_ROUND(s, ASCON_RCb); } +ASCON_API forceinline void ASCON_P6ROUNDS(ascon_state_t* s) { ASCON_ROUND(s, ASCON_RC6); ASCON_ROUND(s, ASCON_RC7); @@ -283659,6 +336383,7 @@ forceinline void ASCON_P6ROUNDS(ascon_state_t* s) { #if ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS +ASCON_API forceinline void ASCON_P(ascon_state_t* s, int nr) { if (nr == 12) ASCON_P12ROUNDS(s); if (nr == 8) ASCON_P8ROUNDS(s); @@ -283667,10 +336392,14 @@ forceinline void ASCON_P(ascon_state_t* s, int nr) { #elif !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS +ASCON_API void ASCON_P12(ascon_state_t* s); +ASCON_API void ASCON_P8(ascon_state_t* s); +ASCON_API void ASCON_P6(ascon_state_t* s); +ASCON_API forceinline void ASCON_P(ascon_state_t* s, int nr) { if (nr == 12) ASCON_P12(s); if (nr == 8) ASCON_P8(s); @@ -283679,10 +336408,12 @@ forceinline void ASCON_P(ascon_state_t* s, int nr) { #elif ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS +ASCON_API forceinline void ASCON_P(ascon_state_t* s, int nr) { ASCON_PROUNDS(s, nr); } #else /* !ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS */ +ASCON_API void ASCON_P(ascon_state_t* s, int nr); #endif @@ -283700,6 +336431,7 @@ void ASCON_P(ascon_state_t* s, int nr); #ifdef ASCON_AEAD_RATE +ASCON_API forceinline void ascon_loadkey(ascon_key_t* key, const uint8_t* k) { #if CRYPTO_KEYBYTES == 16 key->x[0] = ASCON_LOAD(k, 8); @@ -283711,6 +336443,7 @@ forceinline void ascon_loadkey(ascon_key_t* key, const uint8_t* k) { #endif } +ASCON_API forceinline void ascon_initaead(ascon_state_t* s, const ascon_key_t* key, const uint8_t* npub) { #if CRYPTO_KEYBYTES == 16 @@ -283738,6 +336471,7 @@ forceinline void ascon_initaead(ascon_state_t* s, const ascon_key_t* key, ascon_printstate("init 2nd key xor", s); } +ASCON_API forceinline void ascon_adata(ascon_state_t* s, const uint8_t* ad, uint64_t adlen) { const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8; @@ -283769,6 +336503,7 @@ forceinline void ascon_adata(ascon_state_t* s, const uint8_t* ad, ascon_printstate("domain separation", s); } +ASCON_API forceinline void ascon_encrypt(ascon_state_t* s, uint8_t* c, const uint8_t* m, uint64_t mlen) { const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8; @@ -283804,6 +336539,7 @@ forceinline void ascon_encrypt(ascon_state_t* s, uint8_t* c, const uint8_t* m, ascon_printstate("pad plaintext", s); } +ASCON_API forceinline void ascon_decrypt(ascon_state_t* s, uint8_t* m, const uint8_t* c, uint64_t clen) { const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8; @@ -283848,6 +336584,7 @@ forceinline void ascon_decrypt(ascon_state_t* s, uint8_t* m, const uint8_t* c, ascon_printstate("pad ciphertext", s); } +ASCON_API forceinline void ascon_final(ascon_state_t* s, const ascon_key_t* key) { #if CRYPTO_KEYBYTES == 16 if (ASCON_AEAD_RATE == 8) { @@ -283908,7 +336645,6 @@ int ascon_aead_decrypt(uint8_t* mtext, { int rc = 0; ascon_state_t s; - if (clen < CRYPTO_ABYTES) return -1; /* perform ascon computation */ ascon_key_t key; ascon_loadkey(&key, k); @@ -283994,6 +336730,7 @@ int ascon_hash(uint8_t* out, const uint8_t* in, uint64_t inlen); #ifdef ASCON_HASH_BYTES +ASCON_API forceinline void ascon_inithash(ascon_state_t* s) { int i; /* initialize */ @@ -284028,6 +336765,7 @@ forceinline void ascon_inithash(ascon_state_t* s) { ascon_printstate("initialization", s); } +ASCON_API forceinline void ascon_absorb(ascon_state_t* s, const uint8_t* in, uint64_t inlen) { /* absorb full plaintext blocks */ @@ -284044,6 +336782,7 @@ forceinline void ascon_absorb(ascon_state_t* s, const uint8_t* in, ascon_printstate("pad plaintext", s); } +ASCON_API forceinline void ascon_squeeze(ascon_state_t* s, uint8_t* out, uint64_t outlen) { /* squeeze full output blocks */ @@ -284221,7 +336960,8 @@ void ascon_pbkdf2(uint8_t* out, uint32_t outlen, SQLITE_PRIVATE CipherParams mcAscon128Params[] = { - { "kdf_iter", ASCON128_KDF_ITER_DEFAULT, ASCON128_KDF_ITER_DEFAULT, 1, 0x7fffffff }, + { "kdf_iter", ASCON128_KDF_ITER_DEFAULT, ASCON128_KDF_ITER_DEFAULT, 1, 0x7fffffff }, + { "plaintext_header_size", 0, 0, 0, 100 /* restrict to db header size */ }, CIPHER_PARAMS_SENTINEL }; @@ -284234,6 +336974,7 @@ SQLITE_PRIVATE CipherParams mcAscon128Params[] = typedef struct _ascon128Cipher { int m_kdfIter; + int m_plaintextHeaderSize; int m_keyLength; uint8_t m_key[KEYLENGTH_ASCON128]; uint8_t m_salt[SALTLENGTH_ASCON128]; @@ -284254,6 +336995,7 @@ AllocateAscon128Cipher(sqlite3* db) { CipherParams* cipherParams = sqlite3mcGetCipherParams(db, CIPHER_NAME_ASCON128); ascon128Cipher->m_kdfIter = sqlite3mcGetCipherParameter(cipherParams, "kdf_iter"); + ascon128Cipher->m_plaintextHeaderSize = sqlite3mcGetCipherParameter(cipherParams, "plaintext_header_size"); } return ascon128Cipher; } @@ -284262,7 +337004,7 @@ static void FreeAscon128Cipher(void* cipher) { Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) cipher; - memset(ascon128Cipher, 0, sizeof(Ascon128Cipher)); + sqlite3mcSecureZeroMemory(ascon128Cipher, sizeof(Ascon128Cipher)); sqlite3_free(ascon128Cipher); } @@ -284272,6 +337014,7 @@ CloneAscon128Cipher(void* cipherTo, void* cipherFrom) Ascon128Cipher* ascon128CipherTo = (Ascon128Cipher*) cipherTo; Ascon128Cipher* ascon128CipherFrom = (Ascon128Cipher*) cipherFrom; ascon128CipherTo->m_kdfIter = ascon128CipherFrom->m_kdfIter; + ascon128CipherTo->m_plaintextHeaderSize = ascon128CipherFrom->m_plaintextHeaderSize; ascon128CipherTo->m_keyLength = ascon128CipherFrom->m_keyLength; memcpy(ascon128CipherTo->m_key, ascon128CipherFrom->m_key, KEYLENGTH_ASCON128); memcpy(ascon128CipherTo->m_salt, ascon128CipherFrom->m_salt, SALTLENGTH_ASCON128); @@ -284309,9 +337052,13 @@ static void GenerateKeyAscon128Cipher(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt) { Ascon128Cipher* ascon128Cipher = (Ascon128Cipher*) cipher; - int bypass = 0; int keyOnly = 1; + if (rekey == 2) + { + /* (rekey == 2) means database is in WAL mode, thus don't change the cipher salt */ + rekey = (cipherSalt != NULL) ? 0 : 1; + } if (rekey || cipherSalt == NULL) { chacha20_rng(ascon128Cipher->m_salt, SALTLENGTH_ASCON128); @@ -284320,54 +337067,14 @@ GenerateKeyAscon128Cipher(void* cipher, char* userPassword, int passwordLength, else { memcpy(ascon128Cipher->m_salt, cipherSalt, SALTLENGTH_ASCON128); + if (ascon128Cipher->m_plaintextHeaderSize > 0) + keyOnly = 0; } - /* Bypass key derivation if the key string starts with "raw:" */ - if (passwordLength > 4 && !memcmp(userPassword, "raw:", 4)) - { - const int nRaw = passwordLength - 4; - const unsigned char* zRaw = (const unsigned char*) userPassword + 4; - switch (nRaw) - { - /* Binary key (and salt) */ - case KEYLENGTH_ASCON128 + SALTLENGTH_ASCON128: - if (!keyOnly) - { - memcpy(ascon128Cipher->m_salt, zRaw + KEYLENGTH_ASCON128, SALTLENGTH_ASCON128); - } - /* fall-through */ - case KEYLENGTH_ASCON128: - memcpy(ascon128Cipher->m_key, zRaw, KEYLENGTH_ASCON128); - bypass = 1; - break; - - /* Hex-encoded key */ - case 2 * KEYLENGTH_ASCON128: - if (sqlite3mcIsHexKey(zRaw, nRaw) != 0) - { - sqlite3mcConvertHex2Bin(zRaw, nRaw, ascon128Cipher->m_key); - bypass = 1; - } - break; - - /* Hex-encoded key and salt */ - case 2 * (KEYLENGTH_ASCON128 + SALTLENGTH_ASCON128): - if (sqlite3mcIsHexKey(zRaw, nRaw) != 0) - { - sqlite3mcConvertHex2Bin(zRaw, 2 * KEYLENGTH_ASCON128, ascon128Cipher->m_key); - if (!keyOnly) - { - sqlite3mcConvertHex2Bin(zRaw + 2 * KEYLENGTH_ASCON128, 2 * SALTLENGTH_ASCON128, ascon128Cipher->m_salt); - } - bypass = 1; - } - break; - - default: - break; - } - } - + /* Bypass key derivation, if raw key (and optionally salt) are given */ + int bypass = sqlite3mcExtractRawKey(userPassword, passwordLength, + keyOnly, KEYLENGTH_ASCON128, SALTLENGTH_ASCON128, + ascon128Cipher->m_key, ascon128Cipher->m_salt); if (!bypass) { ascon_pbkdf2(ascon128Cipher->m_key, KEYLENGTH_ASCON128, @@ -284402,10 +337109,26 @@ EncryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, int nReserved = (reserved == 0) ? 0 : GetReservedAscon128Cipher(cipher); int n = len - nReserved; uint64_t mlen = n; + int usePlaintextHeader = 0; /* Generate one-time keys */ uint8_t otk[ASCON_HASH_BYTES]; - int offset; + int offset = 0; + + /* Check whether a plaintext header should be used */ + if (page == 1) + { + int plaintextHeaderSize = ascon128Cipher->m_plaintextHeaderSize; + if (plaintextHeaderSize > 0) + { + usePlaintextHeader = 1; + offset = (plaintextHeaderSize > CIPHER_PAGE1_OFFSET) ? plaintextHeaderSize : CIPHER_PAGE1_OFFSET; + } + else + { + offset = CIPHER_PAGE1_OFFSET; + } + } /* Check whether number of required reserved bytes and actually reserved bytes match */ if (nReserved > reserved) @@ -284421,11 +337144,10 @@ EncryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, chacha20_rng(data + n + PAGE_TAG_LEN_ASCON128, PAGE_NONCE_LEN_ASCON128); AsconGenOtk(otk, ascon128Cipher->m_key, data + n + PAGE_TAG_LEN_ASCON128, page); - offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0; ascon_aead_encrypt(data + offset, data + n, data + offset, mlen - offset, NULL /* ad */, 0 /* adlen*/, data + n + PAGE_TAG_LEN_ASCON128, otk); - if (page == 1) + if (page == 1 && usePlaintextHeader == 0) { memcpy(data, ascon128Cipher->m_salt, SALTLENGTH_ASCON128); } @@ -284441,16 +337163,18 @@ EncryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, AsconGenOtk(otk, ascon128Cipher->m_key, nonce, page); /* Encrypt */ - offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0; ascon_aead_encrypt(data + offset, dummyTag, data + offset, mlen - offset, NULL /* ad */, 0 /* adlen*/, nonce, otk); - if (page == 1) + if (page == 1 && usePlaintextHeader == 0) { memcpy(data, ascon128Cipher->m_salt, SALTLENGTH_ASCON128); } } + /* Zero out otk array */ + sqlite3mcSecureZeroMemory(otk, ASCON_HASH_BYTES); + return rc; } @@ -284463,10 +337187,26 @@ DecryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, int n = len - nReserved; uint64_t clen = n; int tagOk; + int usePlaintextHeader = 0; /* Generate one-time keys */ uint8_t otk[ASCON_HASH_BYTES]; - int offset; + int offset = 0; + + /* Check whether a plaintext header should be used */ + if (page == 1) + { + int plaintextHeaderSize = ascon128Cipher->m_plaintextHeaderSize; + if (plaintextHeaderSize > 0) + { + usePlaintextHeader = 1; + offset = (plaintextHeaderSize > CIPHER_PAGE1_OFFSET) ? plaintextHeaderSize : CIPHER_PAGE1_OFFSET; + } + else + { + offset = CIPHER_PAGE1_OFFSET; + } + } /* Check whether number of required reserved bytes and actually reserved bytes match */ if (nReserved > reserved) @@ -284481,7 +337221,6 @@ DecryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, AsconGenOtk(otk, ascon128Cipher->m_key, data + n + PAGE_TAG_LEN_ASCON128, page); /* Determine MAC and decrypt */ - offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0; tagOk = ascon_aead_decrypt(data + offset, data + offset, clen - offset, NULL /* ad */, 0 /* adlen */, data + n, data + n + PAGE_TAG_LEN_ASCON128, otk); @@ -284502,7 +337241,7 @@ DecryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, rc = (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; } } - if (page == 1 && rc == SQLITE_OK) + if (page == 1 && usePlaintextHeader == 0 && rc == SQLITE_OK) { memcpy(data, SQLITE_FILE_HEADER, 16); } @@ -284518,16 +337257,18 @@ DecryptPageAscon128Cipher(void* cipher, int page, unsigned char* data, int len, AsconGenOtk(otk, ascon128Cipher->m_key, nonce, page); /* Decrypt */ - offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0; tagOk = ascon_aead_decrypt(data + offset, data + offset, clen - offset, NULL /* ad */, 0 /* adlen */, dummyTag, nonce, otk); - if (page == 1) + if (page == 1 && usePlaintextHeader == 0) { memcpy(data, SQLITE_FILE_HEADER, 16); } } + /* Zero out otk array */ + sqlite3mcSecureZeroMemory(otk, ASCON_HASH_BYTES); + return rc; } @@ -284548,6 +337289,520 @@ SQLITE_PRIVATE const CipherDescriptor mcAscon128Descriptor = #endif /*** End of #include "cipher_ascon.c" ***/ +/* #include "cipher_aegis.c" */ +/*** Begin of #include "cipher_aegis.c" ***/ +/* +** Name: cipher_aegis.c +** Purpose: Implementation of cipher AEGIS +** Author: Ulrich Telle +** Created: 2024-12-10 +** Copyright: (c) 2024-2026 Ulrich Telle +** License: MIT +*/ + +/* #include "cipher_common.h" */ + + +/* --- Aegis --- */ +#if HAVE_CIPHER_AEGIS + +#define CIPHER_NAME_AEGIS "aegis" + +/* +** Configuration parameters for "aegis" +** +** - tcost : number of iterations for key derivation with Argon2 +** - mcost : amount of memory in kB for key derivation with Argon2 +** - pcost : parallelism, number of threads for key derivation with Argon2 +** - algorithm : AEGIS variant to be used for page encryption +*/ + +#define AEGIS_ALGORITHM_128L 1 +#define AEGIS_ALGORITHM_128X2 2 +#define AEGIS_ALGORITHM_128X4 3 +#define AEGIS_ALGORITHM_256 4 +#define AEGIS_ALGORITHM_256X2 5 +#define AEGIS_ALGORITHM_256X4 6 + +#define AEGIS_ALGORITHM_MIN AEGIS_ALGORITHM_128L +#define AEGIS_ALGORITHM_MAX AEGIS_ALGORITHM_256X4 +#define AEGIS_ALGORITHM_DEFAULT AEGIS_ALGORITHM_256 + +#define AEGIS_TCOST_DEFAULT 2 +#define AEGIS_MCOST_DEFAULT (19*1024) +#define AEGIS_PCOST_DEFAULT 1 + +SQLITE_PRIVATE const char* mcAegisAlgorithmNames[AEGIS_ALGORITHM_MAX+1] = +{ "", "aegis-128l", "aegis-128x2", "aegis-128x4", "aegis-256", "aegis-256x2", "aegis-256x4" }; + +SQLITE_PRIVATE int sqlite3mcAegisAlgorithmToIndex(const char* algorithmName) +{ + int j = 0; + for (j = AEGIS_ALGORITHM_MIN; j <= AEGIS_ALGORITHM_MAX; j++) + { + if (sqlite3_stricmp(algorithmName, mcAegisAlgorithmNames[j]) == 0) + break; + } + if (j <= AEGIS_ALGORITHM_MAX) + return j; + else + return -1; +} + +SQLITE_PRIVATE const char* sqlite3mcAegisAlgorithmToString(int algorithmIndex) +{ + if (algorithmIndex >= AEGIS_ALGORITHM_MIN && algorithmIndex <= AEGIS_ALGORITHM_MAX) + return mcAegisAlgorithmNames[algorithmIndex]; + else + return "unknown"; +} + +typedef int (*AegisEncryptDetached_t)(uint8_t* c, uint8_t* mac, size_t maclen, + const uint8_t* m, size_t mlen, + const uint8_t* ad, size_t adlen, + const uint8_t* npub, const uint8_t* k); + +typedef int (*AegisDecryptDetached_t)(uint8_t* m, const uint8_t* c, size_t clen, + const uint8_t* mac, size_t maclen, + const uint8_t* ad, size_t adlen, + const uint8_t* npub, const uint8_t* k); + +typedef void (*AegisEncryptUnauthenticated_t)(uint8_t* c, const uint8_t* m, size_t mlen, + const uint8_t* npub, const uint8_t* k); + +typedef void (*AegisDecryptUnauthenticated_t)(uint8_t* m, const uint8_t* c, size_t clen, + const uint8_t* npub, const uint8_t* k); + +typedef void (*AegisStream_t)(uint8_t* out, size_t len, const uint8_t* npub, const uint8_t* k); + +typedef struct _AegisCryptFunctions +{ + AegisEncryptDetached_t encrypt; + AegisDecryptDetached_t decrypt; + AegisEncryptUnauthenticated_t encryptNoTag; + AegisEncryptUnauthenticated_t decryptNoTag; + AegisStream_t stream; +} AegisCryptFunctions; + +SQLITE_PRIVATE const AegisCryptFunctions mcAegisCryptFunctions[] = +{ + { NULL, NULL }, /* Dummy entry */ + { aegis128l_encrypt_detached, aegis128l_decrypt_detached, + aegis128l_encrypt_unauthenticated, aegis128l_decrypt_unauthenticated, + aegis128l_stream }, + { aegis128x2_encrypt_detached, aegis128x2_decrypt_detached, + aegis128x2_encrypt_unauthenticated, aegis128x2_decrypt_unauthenticated, + aegis128x2_stream }, + { aegis128x4_encrypt_detached, aegis128x4_decrypt_detached, + aegis128x4_encrypt_unauthenticated, aegis128x4_decrypt_unauthenticated, + aegis128x4_stream }, + { aegis256_encrypt_detached, aegis256_decrypt_detached, + aegis256_encrypt_unauthenticated, aegis256_decrypt_unauthenticated, + aegis256_stream }, + { aegis256x2_encrypt_detached, aegis256x2_decrypt_detached, + aegis256x2_encrypt_unauthenticated, aegis256x2_decrypt_unauthenticated, + aegis256x2_stream }, + { aegis256x4_encrypt_detached, aegis256x4_decrypt_detached, + aegis256x4_encrypt_unauthenticated, aegis256x4_decrypt_unauthenticated, + aegis256x4_stream } +}; + +SQLITE_PRIVATE CipherParams mcAegisParams[] = +{ + { "tcost", AEGIS_TCOST_DEFAULT, AEGIS_TCOST_DEFAULT, 1, 0x7fffffff }, + { "mcost", AEGIS_MCOST_DEFAULT, AEGIS_MCOST_DEFAULT, 1, 0x7fffffff }, + { "pcost", AEGIS_PCOST_DEFAULT, AEGIS_PCOST_DEFAULT, 1, 0x7fffffff }, + { "algorithm", AEGIS_ALGORITHM_DEFAULT, AEGIS_ALGORITHM_DEFAULT, AEGIS_ALGORITHM_MIN, AEGIS_ALGORITHM_MAX }, + { "plaintext_header_size", 0, 0, 0, 100 /* restrict to db header size */ }, + CIPHER_PARAMS_SENTINEL +}; + +#define KEYLENGTH_AEGIS_128 16 +#define KEYLENGTH_AEGIS_256 32 +#define KEYLENGTH_AEGIS_MAX 32 + +#define PAGE_NONCE_LEN_AEGIS_128 16 +#define PAGE_NONCE_LEN_AEGIS_256 32 +#define PAGE_NONCE_LEN_AEGIS_MAX 32 + +#if AEGIS_ALGORITHM_DEFAULT < AEGIS_ALGORITHM_256 +#define KEYLENGTH_AEGIS_DEFAULT KEYLENGTH_AEGIS_128 +#define PAGE_NONCE_LEN_AEGIS_DEFAULT PAGE_NONCE_LEN_AEGIS_128 +#else +#define KEYLENGTH_AEGIS_DEFAULT KEYLENGTH_AEGIS_256 +#define PAGE_NONCE_LEN_AEGIS_DEFAULT PAGE_NONCE_LEN_AEGIS_256 +#endif + +#define SALTLENGTH_AEGIS 16 + +#define PAGE_TAG_LEN_AEGIS 32 +#define PAGE_RESERVED_AEGIS (PAGE_NONCE_LEN_AEGIS + PAGE_TAG_LEN_AEGIS) + +#define OTK_LEN_MAX_AEGIS (PAGE_TAG_LEN_AEGIS + PAGE_NONCE_LEN_AEGIS_MAX + 4) + +typedef struct _aegisCipher +{ + int m_argon2Tcost; + int m_argon2Mcost; + int m_argon2Pcost; + int m_aegisAlgorithm; + int m_plaintextHeaderSize; + int m_keyLength; + int m_nonceLength; + uint8_t m_key[KEYLENGTH_AEGIS_MAX]; + uint8_t m_salt[SALTLENGTH_AEGIS]; +} AegisCipher; + +static void* +AllocateAegisCipher(sqlite3* db) +{ + AegisCipher* aegisCipher = (AegisCipher*) sqlite3_malloc(sizeof(AegisCipher)); + if (aegisCipher != NULL) + { + memset(aegisCipher, 0, sizeof(AegisCipher)); + aegisCipher->m_keyLength = 0; + memset(aegisCipher->m_key, 0, KEYLENGTH_AEGIS_MAX); + memset(aegisCipher->m_salt, 0, SALTLENGTH_AEGIS); + } + if (aegisCipher != NULL) + { + CipherParams* cipherParams = sqlite3mcGetCipherParams(db, CIPHER_NAME_AEGIS); + aegisCipher->m_argon2Tcost = sqlite3mcGetCipherParameter(cipherParams, "tcost"); + aegisCipher->m_argon2Mcost = sqlite3mcGetCipherParameter(cipherParams, "mcost"); + aegisCipher->m_argon2Pcost = sqlite3mcGetCipherParameter(cipherParams, "pcost"); + aegisCipher->m_aegisAlgorithm = sqlite3mcGetCipherParameter(cipherParams, "algorithm"); + if (aegisCipher->m_aegisAlgorithm < AEGIS_ALGORITHM_256) + { + aegisCipher->m_keyLength = KEYLENGTH_AEGIS_128; + aegisCipher->m_nonceLength = PAGE_NONCE_LEN_AEGIS_128; + } + else + { + aegisCipher->m_keyLength = KEYLENGTH_AEGIS_256; + aegisCipher->m_nonceLength = PAGE_NONCE_LEN_AEGIS_256; + } + aegisCipher->m_plaintextHeaderSize = sqlite3mcGetCipherParameter(cipherParams, "plaintext_header_size"); + } + return aegisCipher; +} + +static void +FreeAegisCipher(void* cipher) +{ + AegisCipher* aegisCipher = (AegisCipher*) cipher; + sqlite3mcSecureZeroMemory(aegisCipher, sizeof(AegisCipher)); + sqlite3_free(aegisCipher); +} + +static void +CloneAegisCipher(void* cipherTo, void* cipherFrom) +{ + AegisCipher* aegisCipherTo = (AegisCipher*) cipherTo; + AegisCipher* aegisCipherFrom = (AegisCipher*) cipherFrom; + + aegisCipherTo->m_argon2Tcost = aegisCipherFrom->m_argon2Tcost; + aegisCipherTo->m_argon2Mcost = aegisCipherFrom->m_argon2Mcost; + aegisCipherTo->m_argon2Pcost = aegisCipherFrom->m_argon2Pcost; + + aegisCipherTo->m_aegisAlgorithm = aegisCipherFrom->m_aegisAlgorithm; + aegisCipherTo->m_plaintextHeaderSize = aegisCipherFrom->m_plaintextHeaderSize; + aegisCipherTo->m_keyLength = aegisCipherFrom->m_keyLength; + aegisCipherTo->m_nonceLength = aegisCipherFrom->m_nonceLength; + + memcpy(aegisCipherTo->m_key, aegisCipherFrom->m_key, aegisCipherFrom->m_keyLength); + memcpy(aegisCipherTo->m_salt, aegisCipherFrom->m_salt, SALTLENGTH_AEGIS); +} + +static int +GetLegacyAegisCipher(void* cipher) +{ + AegisCipher* aegisCipher = (AegisCipher*) cipher; + return 0; +} + +static int +GetPageSizeAegisCipher(void* cipher) +{ + AegisCipher* aegisCipher = (AegisCipher*) cipher; + int pageSize = 0; + return pageSize; +} + +static int +GetReservedAegisCipher(void* cipher) +{ + AegisCipher* aegisCipher = (AegisCipher*) cipher; + return (aegisCipher->m_nonceLength + PAGE_TAG_LEN_AEGIS); +} + +static unsigned char* +GetSaltAegisCipher(void* cipher) +{ + AegisCipher* aegisCipher = (AegisCipher*) cipher; + return aegisCipher->m_salt; +} + +static void +GenerateKeyAegisCipher(void* cipher, char* userPassword, int passwordLength, int rekey, unsigned char* cipherSalt) +{ + AegisCipher* aegisCipher = (AegisCipher*) cipher; + + int keyOnly = 1; + if (rekey == 2) + { + /* (rekey == 2) means database is in WAL mode, thus don't change the cipher salt */ + rekey = (cipherSalt != NULL) ? 0 : 1; + } + if (rekey || cipherSalt == NULL) + { + chacha20_rng(aegisCipher->m_salt, SALTLENGTH_AEGIS); + keyOnly = 0; + } + else + { + memcpy(aegisCipher->m_salt, cipherSalt, SALTLENGTH_AEGIS); + if (aegisCipher->m_plaintextHeaderSize > 0) + keyOnly = 0; + } + + /* Bypass key derivation, if raw key (and optionally salt) are given */ + int bypass = sqlite3mcExtractRawKey(userPassword, passwordLength, + keyOnly, aegisCipher->m_keyLength, SALTLENGTH_AEGIS, + aegisCipher->m_key, aegisCipher->m_salt); + if (!bypass) + { + int rc = argon2id_hash_raw((uint32_t) aegisCipher->m_argon2Tcost, + (uint32_t) aegisCipher->m_argon2Mcost, + (uint32_t) aegisCipher->m_argon2Pcost, + userPassword, passwordLength, + aegisCipher->m_salt, SALTLENGTH_AEGIS, + aegisCipher->m_key, aegisCipher->m_keyLength); + } + SQLITE3MC_DEBUG_LOG("generate: codec=%p pFile=%p\n", aegisCipher, fd); + SQLITE3MC_DEBUG_HEX("generate key:", aegisCipher->m_key, aegisCipher->m_keyLength); + SQLITE3MC_DEBUG_HEX("generate salt:", aegisCipher->m_salt, SALTLENGTH_AEGIS); +} + +static int +AegisGenNonce(AegisCipher* aegisCipher, uint8_t* out, int outLength, int page) +{ + uint8_t nonce[PAGE_NONCE_LEN_AEGIS_MAX]; + memset(nonce, 0, PAGE_NONCE_LEN_AEGIS_MAX); + STORE32_LE(out, page); + STORE32_LE(out + 4, page); + mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].stream(out, outLength, nonce, aegisCipher->m_key); + return 0; +} + +static int +AegisGenOtk(AegisCipher* aegisCipher, uint8_t* out, int outLength, uint8_t* nonce, int nonceLength, int page) +{ + mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].stream(out, outLength, nonce, aegisCipher->m_key); + STORE32_BE(out + (outLength - 4), page); + return 0; +} + +static int +EncryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int reserved) +{ + AegisCipher* aegisCipher = (AegisCipher*) cipher; + int rc = SQLITE_OK; + int nReserved = (reserved == 0) ? 0 : GetReservedAegisCipher(cipher); + int n = len - nReserved; + uint64_t mlen = n; + int usePlaintextHeader = 0; + + /* Generate one-time keys */ + uint8_t otk[OTK_LEN_MAX_AEGIS]; + int offset = 0; + memset(otk, 0, OTK_LEN_MAX_AEGIS); + + /* Check whether a plaintext header should be used */ + if (page == 1) + { + int plaintextHeaderSize = aegisCipher->m_plaintextHeaderSize; + if (plaintextHeaderSize > 0) + { + usePlaintextHeader = 1; + offset = (plaintextHeaderSize > CIPHER_PAGE1_OFFSET) ? plaintextHeaderSize : CIPHER_PAGE1_OFFSET; + } + else + { + offset = CIPHER_PAGE1_OFFSET; + } + } + + /* Check whether number of required reserved bytes and actually reserved bytes match */ + if (nReserved > reserved) + { + return SQLITE_CORRUPT; + } + + if (nReserved > 0) + { + /* Encrypt and authenticate */ + + /* Generate nonce */ + chacha20_rng(data + n + PAGE_TAG_LEN_AEGIS, aegisCipher->m_nonceLength); + AegisGenOtk(aegisCipher, otk, aegisCipher->m_keyLength + aegisCipher->m_nonceLength, + data + n + PAGE_TAG_LEN_AEGIS, aegisCipher->m_nonceLength, page); + + mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].encrypt( + data + offset, data + n, PAGE_TAG_LEN_AEGIS, + data + offset, mlen - offset, + NULL, 0, otk + aegisCipher->m_keyLength, otk); + + if (page == 1 && usePlaintextHeader == 0) + { + memcpy(data, aegisCipher->m_salt, SALTLENGTH_AEGIS); + } + } + else + { + /* Encrypt only */ + uint8_t nonce[PAGE_NONCE_LEN_AEGIS_MAX]; + AegisGenNonce(aegisCipher, nonce, aegisCipher->m_nonceLength, page); + AegisGenOtk(aegisCipher, otk, aegisCipher->m_keyLength + aegisCipher->m_nonceLength, + nonce, aegisCipher->m_nonceLength, page); + + /* Encrypt */ + mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].encryptNoTag( + data + offset, + data + offset, mlen - offset, + otk + aegisCipher->m_keyLength, otk); + + if (page == 1 && usePlaintextHeader == 0) + { + memcpy(data, aegisCipher->m_salt, SALTLENGTH_AEGIS); + } + } + + /* Zero out otk array */ + sqlite3mcSecureZeroMemory(otk, OTK_LEN_MAX_AEGIS); + + return rc; +} + +static int +DecryptPageAegisCipher(void* cipher, int page, unsigned char* data, int len, int reserved, int hmacCheck) +{ + AegisCipher* aegisCipher = (AegisCipher*) cipher; + int rc = SQLITE_OK; + int nReserved = (reserved == 0) ? 0 : GetReservedAegisCipher(cipher); + int n = len - nReserved; + uint64_t clen = n; + int tagOk; + int usePlaintextHeader = 0; + + /* Generate one-time keys */ + uint8_t otk[OTK_LEN_MAX_AEGIS]; + int offset = 0; + memset(otk, 0, OTK_LEN_MAX_AEGIS); + + /* Check whether a plaintext header should be used */ + if (page == 1) + { + int plaintextHeaderSize = aegisCipher->m_plaintextHeaderSize; + if (plaintextHeaderSize > 0) + { + usePlaintextHeader = 1; + offset = (plaintextHeaderSize > CIPHER_PAGE1_OFFSET) ? plaintextHeaderSize : CIPHER_PAGE1_OFFSET; + } + else + { + offset = CIPHER_PAGE1_OFFSET; + } + } + + /* Check whether number of required reserved bytes and actually reserved bytes match */ + if (nReserved > reserved) + { + return (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; + } + + if (nReserved > 0) + { + /* Decrypt and verify MAC */ + AegisGenOtk(aegisCipher, otk, aegisCipher->m_keyLength + aegisCipher->m_nonceLength, + data + n + PAGE_TAG_LEN_AEGIS, aegisCipher->m_nonceLength, page); + + /* Determine MAC and decrypt */ + if (hmacCheck != 0) + { + /* Verify the MAC */ + tagOk = mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].decrypt( + data + offset, + data + offset, clen - offset, + data + n, PAGE_TAG_LEN_AEGIS, + NULL, 0, otk + aegisCipher->m_keyLength, otk); + if (tagOk != 0) + { + SQLITE3MC_DEBUG_LOG("decrypt: codec=%p page=%d\n", aegisCipher, page); + SQLITE3MC_DEBUG_HEX("decrypt key:", aegisCipher->m_key, aegisCipher->m_keyLength); + SQLITE3MC_DEBUG_HEX("decrypt otk:", otk, 64); + SQLITE3MC_DEBUG_HEX("decrypt data+00:", data, 16); + SQLITE3MC_DEBUG_HEX("decrypt data+24:", data + 24, 16); + SQLITE3MC_DEBUG_HEX("decrypt data+n:", data + n, PAGE_TAG_LEN_AEGIS); + /* Bad MAC */ + rc = (page == 1) ? SQLITE_NOTADB : SQLITE_CORRUPT; + } + } + else + { + mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].decryptNoTag( + data + offset, + data + offset, clen - offset, + otk + aegisCipher->m_keyLength, otk); + } + + if (page == 1 && usePlaintextHeader == 0 && rc == SQLITE_OK) + { + memcpy(data, SQLITE_FILE_HEADER, 16); + } + } + else + { + /* Decrypt only */ + uint8_t nonce[PAGE_NONCE_LEN_AEGIS_MAX]; + AegisGenNonce(aegisCipher, nonce, aegisCipher->m_nonceLength, page); + AegisGenOtk(aegisCipher, otk, aegisCipher->m_keyLength + aegisCipher->m_nonceLength, + nonce, aegisCipher->m_nonceLength, page); + + /* Decrypt */ + mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].decryptNoTag( + data + offset, + data + offset, clen - offset, + otk + aegisCipher->m_keyLength, otk); + + if (page == 1 && usePlaintextHeader == 0) + { + memcpy(data, SQLITE_FILE_HEADER, 16); + } + } + + /* Zero out otk array */ + sqlite3mcSecureZeroMemory(otk, OTK_LEN_MAX_AEGIS); + + return rc; +} + +SQLITE_PRIVATE const CipherDescriptor mcAegisDescriptor = +{ + CIPHER_NAME_AEGIS, + AllocateAegisCipher, + FreeAegisCipher, + CloneAegisCipher, + GetLegacyAegisCipher, + GetPageSizeAegisCipher, + GetReservedAegisCipher, + GetSaltAegisCipher, + GenerateKeyAegisCipher, + EncryptPageAegisCipher, + DecryptPageAegisCipher +}; +#endif +/*** End of #include "cipher_aegis.c" ***/ + /* #include "cipher_common.c" */ /*** Begin of #include "cipher_common.c" ***/ /* @@ -284555,7 +337810,7 @@ SQLITE_PRIVATE const CipherDescriptor mcAscon128Descriptor = ** Purpose: Implementation of SQLite codecs ** Author: Ulrich Telle ** Created: 2020-02-02 -** Copyright: (c) 2006-2024 Ulrich Telle +** Copyright: (c) 2006-2026 Ulrich Telle ** License: MIT */ @@ -284576,9 +337831,9 @@ static unsigned char padding[] = static CipherParams commonParams[] = { - { "cipher", CODEC_TYPE_UNKNOWN, CODEC_TYPE_UNKNOWN, 1, CODEC_COUNT_MAX }, - { "hmac_check", 1, 1, 0, 1 }, - { "mc_legacy_wal", SQLITE3MC_LEGACY_WAL, SQLITE3MC_LEGACY_WAL, 0, 1 }, + { "cipher", CODEC_TYPE_UNKNOWN, CODEC_TYPE_UNKNOWN, 1, CODEC_COUNT_MAX }, + { "hmac_check", 1, 1, 0, 1 }, + { "mc_legacy_wal", SQLITE3MC_LEGACY_WAL, SQLITE3MC_LEGACY_WAL, 0, 1 }, CIPHER_PARAMS_SENTINEL }; @@ -284608,6 +337863,7 @@ typedef struct _CipherName char m_name[CIPHER_NAME_MAXLEN]; } CipherName; +static char globalConfigTableName[CIPHER_NAME_MAXLEN] = ""; static int globalCipherCount = 0; static char* globalSentinelName = ""; static CipherName globalCipherNameTable[CODEC_COUNT_LIMIT + 2] = { 0 }; @@ -284669,20 +337925,21 @@ sqlite3mcCloneCodecParameterTable() } SQLITE_PRIVATE void -sqlite3mcFreeCodecParameterTable(CodecParameter* codecParams) +sqlite3mcFreeCodecParameterTable(void* ptr) { + CodecParameter* codecParams = (CodecParameter*)ptr; sqlite3_free(codecParams[0].m_params); sqlite3_free(codecParams); } static const CipherDescriptor mcSentinelDescriptor = { - "", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + "", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static const CipherDescriptor mcDummyDescriptor = { - "@dummy@", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + "@dummy@", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static CipherDescriptor globalCodecDescriptorTable[CODEC_COUNT_MAX + 1]; @@ -284824,7 +338081,7 @@ sqlite3mcCodecSetup(Codec* codec, int cipherType, char* userPassword, int passwo } SQLITE_PRIVATE int -sqlite3mcSetupWriteCipher(Codec* codec, int cipherType, char* userPassword, int passwordLength) +sqlite3mcSetupWriteCipher(Codec* codec, int cipherType, char* userPassword, int passwordLength, int usesWal) { int rc = SQLITE_OK; CipherParams* globalParams = sqlite3mcGetCipherParams(codec->m_db, CIPHER_NAME_GLOBAL); @@ -284845,7 +338102,7 @@ sqlite3mcSetupWriteCipher(Codec* codec, int cipherType, char* userPassword, int if (codec->m_writeCipher != NULL) { unsigned char* keySalt = (codec->m_hasKeySalt != 0) ? codec->m_keySalt : NULL; - sqlite3mcGenerateWriteKey(codec, userPassword, passwordLength, keySalt); + sqlite3mcGenerateWriteKey(codec, userPassword, passwordLength, keySalt, usesWal); } else { @@ -285169,11 +338426,11 @@ sqlite3mcGenerateReadKey(Codec* codec, char* userPassword, int passwordLength, u } SQLITE_PRIVATE void -sqlite3mcGenerateWriteKey(Codec* codec, char* userPassword, int passwordLength, unsigned char* cipherSalt) +sqlite3mcGenerateWriteKey(Codec* codec, char* userPassword, int passwordLength, unsigned char* cipherSalt, int usesWal) { unsigned char dbHeader[KEYSALT_LENGTH]; unsigned char* pDbHeader = (cipherSalt == NULL) ? mcReadDatabaseHeader(codec, dbHeader) : cipherSalt; - globalCodecDescriptorTable[codec->m_writeCipherType-1].m_generateKey(codec->m_writeCipher, userPassword, passwordLength, 1, pDbHeader); + globalCodecDescriptorTable[codec->m_writeCipherType-1].m_generateKey(codec->m_writeCipher, userPassword, passwordLength, (usesWal) ? 2 : 1, pDbHeader); } SQLITE_PRIVATE int @@ -285231,7 +338488,7 @@ sqlite3mcConfigureSQLCipherVersion(sqlite3* db, int configDefault, int legacyVer ** Purpose: Configuration of SQLite codecs ** Author: Ulrich Telle ** Created: 2020-03-02 -** Copyright: (c) 2006-2024 Ulrich Telle +** Copyright: (c) 2006-2026 Ulrich Telle ** License: MIT */ @@ -285292,18 +338549,7 @@ sqlite3mcConfigTable(sqlite3_context* context, int argc, sqlite3_value** argv) SQLITE_PRIVATE CodecParameter* sqlite3mcGetCodecParams(sqlite3* db) { - CodecParameter* codecParams = NULL; - sqlite3_stmt* pStmt = 0; - int rc = sqlite3_prepare_v2(db, "SELECT sqlite3mc_config_table();", -1, &pStmt, 0); - if (rc == SQLITE_OK) - { - if (SQLITE_ROW == sqlite3_step(pStmt)) - { - sqlite3_value* ptrValue = sqlite3_column_value(pStmt, 0); - codecParams = (CodecParameter*) sqlite3_value_pointer(ptrValue, "sqlite3mc_codec_params"); - } - sqlite3_finalize(pStmt); - } + CodecParameter* codecParams = (CodecParameter*) sqlite3_get_clientdata(db, globalConfigTableName); return codecParams; } @@ -285424,18 +338670,17 @@ sqlite3mc_cipher_index(const char* cipherName) return (j < count && globalCodecDescriptorTable[j].m_name[0] != 0) ? j + 1 : -1; } -SQLITE_API const char* -sqlite3mc_cipher_name(int cipherIndex) +static const char* +sqlite3mcFindCipherName(int cipherIndex) { - static char cipherName[CIPHER_NAME_MAXLEN] = ""; + const char* cipherName = NULL; int count; int j; #ifndef SQLITE_OMIT_AUTOINIT - if( sqlite3_initialize() ) return cipherName; + if (sqlite3_initialize()) return NULL; #endif count = sqlite3mcGetGlobalCipherCount(); j = 0; - cipherName[0] = '\0'; if (cipherIndex > 0 && cipherIndex <= count) { for (j = 0; j < count && globalCodecDescriptorTable[j].m_name[0] != 0; ++j) @@ -285444,15 +338689,59 @@ sqlite3mc_cipher_name(int cipherIndex) } if (j < count && globalCodecDescriptorTable[j].m_name[0] != 0) { - strncpy(cipherName, globalCodecDescriptorTable[j].m_name, CIPHER_NAME_MAXLEN - 1); - cipherName[CIPHER_NAME_MAXLEN - 1] = '\0'; + cipherName = globalCodecDescriptorTable[j].m_name; } } return cipherName; } +SQLITE_API const char* +sqlite3mc_cipher_name(int cipherIndex) +{ + static char cipherName[CIPHER_NAME_MAXLEN] = ""; + const char* globalCipherName = sqlite3mcFindCipherName(cipherIndex); + if (globalCipherName) + { + strncpy(cipherName, globalCipherName, CIPHER_NAME_MAXLEN - 1); + cipherName[CIPHER_NAME_MAXLEN - 1] = '\0'; + } + else + { + cipherName[0] = '\0'; + } + return cipherName; +} + +SQLITE_API int +sqlite3mc_cipher_name_copy(int cipherIndex, char* cipherName, int maxCipherNameSize) +{ + int ok = 1; + const char* globalCipherName = sqlite3mcFindCipherName(cipherIndex); + if (globalCipherName) + { + int cipherNameLen = (int)strlen(globalCipherName) + 1; + if (maxCipherNameSize >= cipherNameLen) + { + strncpy(cipherName, globalCipherName, maxCipherNameSize - 1); + cipherName[maxCipherNameSize - 1] = '\0'; + } + else + { + /* Buffer too small, return negative value of minimum required buffer length */ + ok = -cipherNameLen; + } + } + else + { + /* Invalid index */ + cipherName[0] = '\0'; + ok = 0; + } + return ok; +} + static -int checkParameterValue(const char* paramName, int value) +int checkParameterValue(const char* paramName, int value, const char* cipherName) { int ok = 1; if (sqlite3_stricmp(paramName, "legacy_page_size") == 0 && value > 0) @@ -285461,7 +338750,10 @@ int checkParameterValue(const char* paramName, int value) } if (ok && sqlite3_stricmp(paramName, "plaintext_header_size") == 0 && value > 0) { - ok = value % 16 == 0; + if (sqlite3_stricmp(cipherName, "sqlcipher") == 0) + { + ok = value % 16 == 0; + } } return ok; } @@ -285573,7 +338865,7 @@ sqlite3mc_config_cipher(sqlite3* db, const char* cipherName, const char* paramNa if (!hasMinPrefix && !hasMaxPrefix) { if (newValue >= 0 && newValue >= param->m_minValue && newValue <= param->m_maxValue && - checkParameterValue(paramName, newValue)) + checkParameterValue(paramName, newValue, cipherName)) { if (hasDefaultPrefix) { @@ -285981,7 +339273,7 @@ sqlite3mcConfigParams(sqlite3_context* context, int argc, sqlite3_value** argv) } SQLITE_PRIVATE int -sqlite3mcConfigureFromUri(sqlite3* db, const char *zDbName, int configDefault) +sqlite3mcConfigureFromUri(sqlite3* db, const char* zDbName, int configDefault) { int rc = SQLITE_OK; @@ -285991,7 +339283,16 @@ sqlite3mcConfigureFromUri(sqlite3* db, const char *zDbName, int configDefault) { /* Check whether cipher is specified */ const char* cipherName = sqlite3_uri_parameter(dbFileName, "cipher"); - if (cipherName != NULL) + if (cipherName == NULL || cipherName[0] == 0) + { + int defaultCipherIndex = sqlite3mc_config(db, "cipher", -1); + if (defaultCipherIndex > 0) + { + cipherName = sqlite3mcFindCipherName(defaultCipherIndex); + sqlite3mc_config(db, "cipher", defaultCipherIndex); + } + } + if (cipherName != NULL && cipherName[0] != 0) { int j = 0; CipherParams* cipherParams = NULL; @@ -286042,12 +339343,45 @@ sqlite3mcConfigureFromUri(sqlite3* db, const char *zDbName, int configDefault) } #endif +#if HAVE_CIPHER_AEGIS + int hasAegisAlgorithm = 0; + int aegisAlgorithm = 0; + if (sqlite3_stricmp(cipherName, "aegis") == 0) + { + const char* algorithm = sqlite3_uri_parameter(dbFileName, "algorithm"); + if (algorithm != NULL && *algorithm != 0) + { + int intValue = -1; + int isIntValue = sqlite3GetInt32(algorithm, &intValue) != 0; + if (!isIntValue) + { + intValue = sqlite3mcAegisAlgorithmToIndex(algorithm); + } + if (intValue > 0) + { + hasAegisAlgorithm = 1; + aegisAlgorithm = intValue; + } + } + } +#endif + /* Check all cipher specific parameters */ for (j = 0; cipherParams[j].m_name[0] != 0; ++j) { + int value = -1; if (skipLegacy && sqlite3_stricmp(cipherParams[j].m_name, "legacy") == 0) continue; - int value = (int) sqlite3_uri_int64(dbFileName, cipherParams[j].m_name, -1); +#if HAVE_CIPHER_AEGIS + if (hasAegisAlgorithm && sqlite3_stricmp(cipherParams[j].m_name, "algorithm") == 0) + { + value = aegisAlgorithm; + } + else +#endif + { + value = (int)sqlite3_uri_int64(dbFileName, cipherParams[j].m_name, -1); + } if (value >= 0) { /* Configure cipher parameter if it was given in the URI */ @@ -286139,8 +339473,16 @@ sqlite3mcFileControlPragma(sqlite3* db, const char* zDbName, int op, void* pArg) { value = sqlite3mc_config(db, "cipher", cipherId); } - rc = SQLITE_OK; - ((char**)pArg)[0] = sqlite3_mprintf("%s", globalCodecDescriptorTable[value - 1].m_name); + if (value > 0) + { + ((char**)pArg)[0] = sqlite3_mprintf("%s", globalCodecDescriptorTable[value - 1].m_name); + rc = SQLITE_OK; + } + else + { + ((char**)pArg)[0] = sqlite3_mprintf("Cipher '%s' could not be located.", pragmaValue); + rc = SQLITE_ERROR; + } } else { @@ -286162,6 +339504,69 @@ sqlite3mcFileControlPragma(sqlite3* db, const char* zDbName, int op, void* pArg) ((char**)pArg)[0] = sqlite3_mprintf("%d", value); rc = SQLITE_OK; } + else if (sqlite3StrICmp(pragmaName, "cipher_salt") == 0) + { + Codec* codec = sqlite3mcGetCodec(db, (zDbName) ? zDbName : "main"); + if (codec == NULL) + { + /* Codec not yet set up */ + if (pragmaValue && *pragmaValue != 0) + { + /* Save given cipher salt */ + if (sqlite3Strlen30(pragmaValue) >= 2 * KEYSALT_LENGTH && + sqlite3mcIsHexKey((unsigned char*) pragmaValue, 2 * KEYSALT_LENGTH)) + { + char* cipherSalt = sqlite3_mprintf("%s", pragmaValue); + if (sqlite3_set_clientdata(db, "sqlite3mc_cipher_salt", cipherSalt, sqlite3_free) != SQLITE_OK) + { + ((char**)pArg)[0] = sqlite3_mprintf("Out of memory. Cipher salt not saved."); + rc = SQLITE_ERROR; + } + else + { + ((char**)pArg)[0] = sqlite3_mprintf("ok"); + rc = SQLITE_OK; + } + } + else + { + ((char**)pArg)[0] = sqlite3_mprintf("Invalid cipher salt. Length < %d or invalid hex digits.", 2 * KEYSALT_LENGTH); + rc = SQLITE_ERROR; + } + } + else + { + char* cipherSalt = sqlite3_get_clientdata(db, "sqlite3mc_cipher_salt"); + if (cipherSalt) + { + ((char**)pArg)[0] = sqlite3_mprintf("%s", cipherSalt); + } + } + } + else if (sqlite3mcIsEncrypted(codec) && sqlite3mcHasWriteCipher(codec)) + { + /* Database encrypted */ + if (pragmaValue && *pragmaValue != 0) + { + ((char**)pArg)[0] = sqlite3_mprintf("Cipher salt can't be changed."); + rc = SQLITE_ERROR; + } + else + { + char* cipherSalt = (char*) sqlite3mc_codec_data(db, (zDbName) ? zDbName : "main", "cipher_salt"); + if (cipherSalt) + { + ((char**)pArg)[0] = cipherSalt; + } + rc = SQLITE_OK; + } + } + else + { + ((char**)pArg)[0] = sqlite3_mprintf("Database not encrypted."); + rc = SQLITE_ERROR; + } + } else if (sqlite3StrICmp(pragmaName, "key") == 0) { rc = sqlite3_key_v2(db, zDbName, pragmaValue, -1); @@ -286331,6 +339736,19 @@ sqlite3mcFileControlPragma(sqlite3* db, const char* zDbName, int op, void* pArg) if (cipherParams != NULL) { const char* cipherName = globalCodecParameterTable[j].m_name; +#if HAVE_CIPHER_AEGIS + int isAegisAlgorithm = 0; + if (sqlite3_stricmp(cipherName, "aegis") == 0 && + sqlite3_stricmp(pragmaName, "algorithm") == 0) + { + if (!isIntValue) + { + intValue = sqlite3mcAegisAlgorithmToIndex(pragmaValue); + isIntValue = 1; + } + isAegisAlgorithm = 1; + } +#endif for (j = 0; cipherParams[j].m_name[0] != 0; ++j) { if (sqlite3_stricmp(pragmaName, cipherParams[j].m_name) == 0) break; @@ -286341,7 +339759,16 @@ sqlite3mcFileControlPragma(sqlite3* db, const char* zDbName, int op, void* pArg) if (isIntValue) { int value = sqlite3mc_config_cipher(db, cipherName, param, intValue); - ((char**)pArg)[0] = sqlite3_mprintf("%d", value); +#if HAVE_CIPHER_AEGIS + if (isAegisAlgorithm) + { + ((char**)pArg)[0] = sqlite3_mprintf("%s", sqlite3mcAegisAlgorithmToString(value)); + } + else +#endif + { + ((char**)pArg)[0] = sqlite3_mprintf("%d", value); + } rc = SQLITE_OK; } else @@ -286460,7 +339887,7 @@ sqlite3mcHandleMainKey(sqlite3* db, const char* zPath) ** Purpose: Implementation of SQLite codec API ** Author: Ulrich Telle ** Created: 2006-12-06 -** Copyright: (c) 2006-2022 Ulrich Telle +** Copyright: (c) 2006-2026 Ulrich Telle ** License: MIT */ @@ -286536,7 +339963,7 @@ sqlite3mcBtreeSetPageSize(Btree* p, int pageSize, int nReserve, int iFix) ** Change 4: Call sqlite3mcBtreeSetPageSize instead of sqlite3BtreeSetPageSize for main database ** (sqlite3mcBtreeSetPageSize allows to reduce the number of reserved bytes) ** -** This code is generated by the script rekeyvacuum.sh from SQLite version 3.47.0 amalgamation. +** This code is generated by the script rekeyvacuum.sh from SQLite version 3.53.4 amalgamation. */ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3mcRunVacuumForRekey( char **pzErrMsg, /* Write error message here */ @@ -286592,7 +340019,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3mcRunVacuumForRekey( saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; saved_mTrace = db->mTrace; - db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; + db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_Comments + | SQLITE_AttachCreate | SQLITE_AttachWrite; db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum; db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_Defensive | SQLITE_CountRows); @@ -286626,9 +340054,19 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3mcRunVacuumForRekey( pDb = &db->aDb[nDb]; assert( strcmp(pDb->zDbSName,zDbVacuum)==0 ); pTemp = pDb->pBt; + + /* A VACUUM cannot change the pagesize of an encrypted database. */ + if( db->nextPagesize ){ + extern void sqlite3mcCodecGetKey(sqlite3*, int, void**, int*); + int nKey; + char *zKey; + sqlite3mcCodecGetKey(db, iDb, (void**)&zKey, &nKey); + if( nKey ) db->nextPagesize = 0; + } if( pOut ){ sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp)); i64 sz = 0; + const char *zFilename; if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){ rc = SQLITE_ERROR; sqlite3SetString(pzErrMsg, db, "output file already exists"); @@ -286640,15 +340078,14 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3mcRunVacuumForRekey( ** they are for the database being vacuumed, except that PAGER_CACHESPILL ** is always set. */ pgflags = db->aDb[iDb].safety_level | (db->flags & PAGER_FLAGS_MASK); - } - /* A VACUUM cannot change the pagesize of an encrypted database. */ - if( db->nextPagesize ){ - extern void sqlite3mcCodecGetKey(sqlite3*, int, void**, int*); - int nKey; - char *zKey; - sqlite3mcCodecGetKey(db, iDb, (void**)&zKey, &nKey); - if( nKey ) db->nextPagesize = 0; + /* If the VACUUM INTO target file is a URI filename and if the + ** "reserve=N" query parameter is present, reset the reserve to the + ** amount specified, if the amount is within range */ + zFilename = sqlite3BtreeGetFilename(pTemp); + if( ALWAYS(zFilename) ){ + int nNew = (int)sqlite3_uri_int64(zFilename, "reserve", nRes); + } } sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); @@ -287043,8 +340480,12 @@ sqlite3mcCodecAttach(sqlite3* db, int nDb, const char* zPath, const void* zKey, { if (dbFileName != NULL) { - /* Check whether key salt is provided in URI */ - const unsigned char* cipherSalt = (const unsigned char*)sqlite3_uri_parameter(dbFileName, "cipher_salt"); + /* Check whether key salt is provided via pragma or via URI */ + const unsigned char* cipherSalt = (const unsigned char*) sqlite3_get_clientdata(db, "sqlite3mc_cipher_salt"); + if (cipherSalt == NULL) + { + cipherSalt = (const unsigned char*) sqlite3_uri_parameter(dbFileName, "cipher_salt"); + } if ((cipherSalt != NULL) && (strlen((const char*)cipherSalt) >= 2 * KEYSALT_LENGTH) && sqlite3mcIsHexKey(cipherSalt, 2 * KEYSALT_LENGTH)) { codec->m_hasKeySalt = 1; @@ -287132,7 +340573,8 @@ sqlite3_key_v2(sqlite3* db, const char* zDbName, const void* zKey, int nKey) return rc; } /* Configure cipher from URI parameters if requested */ - if (sqlite3FindFunction(db, "sqlite3mc_config_table", 0, SQLITE_UTF8, 0) == NULL) + void* codecParamTable = sqlite3_get_clientdata(db, globalConfigTableName); + if (codecParamTable == NULL) { /* ** Encryption extension of database connection not yet initialized; @@ -287168,6 +340610,7 @@ sqlite3_rekey_v2(sqlite3* db, const char* zDbName, const void* zKey, int nKey) int nReserved; Pager* pPager; Codec* codec; + int usesWal = 0; int codecAllocated = 0; int rc = SQLITE_ERROR; char* err = NULL; @@ -287203,10 +340646,11 @@ sqlite3_rekey_v2(sqlite3* db, const char* zDbName, const void* zKey, int nKey) pPager = sqlite3BtreePager(pBt); codec = sqlite3mcGetCodec(db, zDbName); + usesWal = pagerUseWal(pPager); - if (pagerUseWal(pPager)) + if (usesWal && (zKey != NULL) && (nKey > 0) && (codec == NULL || !sqlite3mcIsEncrypted(codec))) { - sqlite3ErrorWithMsg(db, rc, "Rekeying is not supported in WAL journal mode."); + sqlite3ErrorWithMsg(db, rc, "Rekeying an unencrypted database is not supported in WAL journal mode."); return rc; } @@ -287231,7 +340675,7 @@ sqlite3_rekey_v2(sqlite3* db, const char* zDbName, const void* zKey, int nKey) { sqlite3mcSetDb(codec, db); sqlite3mcSetBtree(codec, pBt); - rc = sqlite3mcSetupWriteCipher(codec, sqlite3mcGetCipherType(db), (char*) zKey, nKey); + rc = sqlite3mcSetupWriteCipher(codec, sqlite3mcGetCipherType(db), (char*) zKey, nKey, usesWal); } if (rc == SQLITE_OK) { @@ -287279,7 +340723,7 @@ sqlite3_rekey_v2(sqlite3* db, const char* zDbName, const void* zKey, int nKey) if (nReserved > 0) { /* Use VACUUM to change the number of reserved bytes */ - char* err = NULL; + err = NULL; sqlite3mcSetReadReserved(codec, nReserved); sqlite3mcSetWriteReserved(codec, 0); rc = sqlite3mcRunVacuumForRekey(&err, db, dbIndex, NULL, 0); @@ -287290,7 +340734,7 @@ sqlite3_rekey_v2(sqlite3* db, const char* zDbName, const void* zKey, int nKey) { /* Database encrypted and key specified, therefore re-encrypt database with new key */ /* Keep read key, change write key to new key */ - rc = sqlite3mcSetupWriteCipher(codec, sqlite3mcGetCipherType(db), (char*) zKey, nKey); + rc = sqlite3mcSetupWriteCipher(codec, sqlite3mcGetCipherType(db), (char*) zKey, nKey, usesWal); if (rc == SQLITE_OK) { int nPagesizeWriteCipher = sqlite3mcGetPageSizeWriteCipher(codec); @@ -287300,7 +340744,7 @@ sqlite3_rekey_v2(sqlite3* db, const char* zDbName, const void* zKey, int nKey) if (nReserved != nReservedWriteCipher) { /* Use VACUUM to change the number of reserved bytes */ - char* err = NULL; + err = NULL; sqlite3mcSetReadReserved(codec, nReserved); sqlite3mcSetWriteReserved(codec, nReservedWriteCipher); rc = sqlite3mcRunVacuumForRekey(&err, db, dbIndex, NULL, nReservedWriteCipher); @@ -287495,7 +340939,7 @@ static void mcMemoryFree(void* pPrior) if (mcSecureMemoryFlag) { int nSize = mcMemorySize(pPrior); - sqlite3mcSecureZeroMemory(pPrior, 0, nSize); + sqlite3mcSecureZeroMemory(pPrior, nSize); } mcDefaultMemoryMethods.xFree(pPrior); } @@ -287621,6 +341065,7 @@ SQLITE_PRIVATE void sqlite3mcInitMemoryMethods() */ #ifdef SQLITE_ENABLE_EXTFUNC /* Prototype for initialization function of EXTENSIONFUNCTIONS extension */ +SQLITE_API int RegisterExtensionFunctions(sqlite3* db); /* #include "extensionfunctions.c" */ /*** Begin of #include "extensionfunctions.c" ***/ @@ -287755,728 +341200,6 @@ Original code 2006 June 05 by relicoder. #ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE /* #include "sqlite3ext.h" */ -/*** Begin of #include "sqlite3ext.h" ***/ -/* -** 2006 June 7 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This header file defines the SQLite interface for use by -** shared libraries that want to be imported as extensions into -** an SQLite instance. Shared libraries that intend to be loaded -** as extensions by SQLite should #include this file instead of -** sqlite3.h. -*/ -#ifndef SQLITE3EXT_H -#define SQLITE3EXT_H -/* #include "sqlite3.h" */ - - -/* -** The following structure holds pointers to all of the SQLite API -** routines. -** -** WARNING: In order to maintain backwards compatibility, add new -** interfaces to the end of this structure only. If you insert new -** interfaces in the middle of this structure, then older different -** versions of SQLite will not be able to load each other's shared -** libraries! -*/ -struct sqlite3_api_routines { - void * (*aggregate_context)(sqlite3_context*,int nBytes); - int (*aggregate_count)(sqlite3_context*); - int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); - int (*bind_double)(sqlite3_stmt*,int,double); - int (*bind_int)(sqlite3_stmt*,int,int); - int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64); - int (*bind_null)(sqlite3_stmt*,int); - int (*bind_parameter_count)(sqlite3_stmt*); - int (*bind_parameter_index)(sqlite3_stmt*,const char*zName); - const char * (*bind_parameter_name)(sqlite3_stmt*,int); - int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); - int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*)); - int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*); - int (*busy_handler)(sqlite3*,int(*)(void*,int),void*); - int (*busy_timeout)(sqlite3*,int ms); - int (*changes)(sqlite3*); - int (*close)(sqlite3*); - int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*, - int eTextRep,const char*)); - int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*, - int eTextRep,const void*)); - const void * (*column_blob)(sqlite3_stmt*,int iCol); - int (*column_bytes)(sqlite3_stmt*,int iCol); - int (*column_bytes16)(sqlite3_stmt*,int iCol); - int (*column_count)(sqlite3_stmt*pStmt); - const char * (*column_database_name)(sqlite3_stmt*,int); - const void * (*column_database_name16)(sqlite3_stmt*,int); - const char * (*column_decltype)(sqlite3_stmt*,int i); - const void * (*column_decltype16)(sqlite3_stmt*,int); - double (*column_double)(sqlite3_stmt*,int iCol); - int (*column_int)(sqlite3_stmt*,int iCol); - sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol); - const char * (*column_name)(sqlite3_stmt*,int); - const void * (*column_name16)(sqlite3_stmt*,int); - const char * (*column_origin_name)(sqlite3_stmt*,int); - const void * (*column_origin_name16)(sqlite3_stmt*,int); - const char * (*column_table_name)(sqlite3_stmt*,int); - const void * (*column_table_name16)(sqlite3_stmt*,int); - const unsigned char * (*column_text)(sqlite3_stmt*,int iCol); - const void * (*column_text16)(sqlite3_stmt*,int iCol); - int (*column_type)(sqlite3_stmt*,int iCol); - sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol); - void * (*commit_hook)(sqlite3*,int(*)(void*),void*); - int (*complete)(const char*sql); - int (*complete16)(const void*sql); - int (*create_collation)(sqlite3*,const char*,int,void*, - int(*)(void*,int,const void*,int,const void*)); - int (*create_collation16)(sqlite3*,const void*,int,void*, - int(*)(void*,int,const void*,int,const void*)); - int (*create_function)(sqlite3*,const char*,int,int,void*, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*)); - int (*create_function16)(sqlite3*,const void*,int,int,void*, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*)); - int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); - int (*data_count)(sqlite3_stmt*pStmt); - sqlite3 * (*db_handle)(sqlite3_stmt*); - int (*declare_vtab)(sqlite3*,const char*); - int (*enable_shared_cache)(int); - int (*errcode)(sqlite3*db); - const char * (*errmsg)(sqlite3*); - const void * (*errmsg16)(sqlite3*); - int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); - int (*expired)(sqlite3_stmt*); - int (*finalize)(sqlite3_stmt*pStmt); - void (*free)(void*); - void (*free_table)(char**result); - int (*get_autocommit)(sqlite3*); - void * (*get_auxdata)(sqlite3_context*,int); - int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); - int (*global_recover)(void); - void (*interruptx)(sqlite3*); - sqlite_int64 (*last_insert_rowid)(sqlite3*); - const char * (*libversion)(void); - int (*libversion_number)(void); - void *(*malloc)(int); - char * (*mprintf)(const char*,...); - int (*open)(const char*,sqlite3**); - int (*open16)(const void*,sqlite3**); - int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); - int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); - void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*); - void (*progress_handler)(sqlite3*,int,int(*)(void*),void*); - void *(*realloc)(void*,int); - int (*reset)(sqlite3_stmt*pStmt); - void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); - void (*result_double)(sqlite3_context*,double); - void (*result_error)(sqlite3_context*,const char*,int); - void (*result_error16)(sqlite3_context*,const void*,int); - void (*result_int)(sqlite3_context*,int); - void (*result_int64)(sqlite3_context*,sqlite_int64); - void (*result_null)(sqlite3_context*); - void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*)); - void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*)); - void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); - void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); - void (*result_value)(sqlite3_context*,sqlite3_value*); - void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); - int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, - const char*,const char*),void*); - void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); - char * (*xsnprintf)(int,char*,const char*,...); - int (*step)(sqlite3_stmt*); - int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, - char const**,char const**,int*,int*,int*); - void (*thread_cleanup)(void); - int (*total_changes)(sqlite3*); - void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); - int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); - void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*, - sqlite_int64),void*); - void * (*user_data)(sqlite3_context*); - const void * (*value_blob)(sqlite3_value*); - int (*value_bytes)(sqlite3_value*); - int (*value_bytes16)(sqlite3_value*); - double (*value_double)(sqlite3_value*); - int (*value_int)(sqlite3_value*); - sqlite_int64 (*value_int64)(sqlite3_value*); - int (*value_numeric_type)(sqlite3_value*); - const unsigned char * (*value_text)(sqlite3_value*); - const void * (*value_text16)(sqlite3_value*); - const void * (*value_text16be)(sqlite3_value*); - const void * (*value_text16le)(sqlite3_value*); - int (*value_type)(sqlite3_value*); - char *(*vmprintf)(const char*,va_list); - /* Added ??? */ - int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); - /* Added by 3.3.13 */ - int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); - int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); - int (*clear_bindings)(sqlite3_stmt*); - /* Added by 3.4.1 */ - int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*, - void (*xDestroy)(void *)); - /* Added by 3.5.0 */ - int (*bind_zeroblob)(sqlite3_stmt*,int,int); - int (*blob_bytes)(sqlite3_blob*); - int (*blob_close)(sqlite3_blob*); - int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64, - int,sqlite3_blob**); - int (*blob_read)(sqlite3_blob*,void*,int,int); - int (*blob_write)(sqlite3_blob*,const void*,int,int); - int (*create_collation_v2)(sqlite3*,const char*,int,void*, - int(*)(void*,int,const void*,int,const void*), - void(*)(void*)); - int (*file_control)(sqlite3*,const char*,int,void*); - sqlite3_int64 (*memory_highwater)(int); - sqlite3_int64 (*memory_used)(void); - sqlite3_mutex *(*mutex_alloc)(int); - void (*mutex_enter)(sqlite3_mutex*); - void (*mutex_free)(sqlite3_mutex*); - void (*mutex_leave)(sqlite3_mutex*); - int (*mutex_try)(sqlite3_mutex*); - int (*open_v2)(const char*,sqlite3**,int,const char*); - int (*release_memory)(int); - void (*result_error_nomem)(sqlite3_context*); - void (*result_error_toobig)(sqlite3_context*); - int (*sleep)(int); - void (*soft_heap_limit)(int); - sqlite3_vfs *(*vfs_find)(const char*); - int (*vfs_register)(sqlite3_vfs*,int); - int (*vfs_unregister)(sqlite3_vfs*); - int (*xthreadsafe)(void); - void (*result_zeroblob)(sqlite3_context*,int); - void (*result_error_code)(sqlite3_context*,int); - int (*test_control)(int, ...); - void (*randomness)(int,void*); - sqlite3 *(*context_db_handle)(sqlite3_context*); - int (*extended_result_codes)(sqlite3*,int); - int (*limit)(sqlite3*,int,int); - sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*); - const char *(*sql)(sqlite3_stmt*); - int (*status)(int,int*,int*,int); - int (*backup_finish)(sqlite3_backup*); - sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*); - int (*backup_pagecount)(sqlite3_backup*); - int (*backup_remaining)(sqlite3_backup*); - int (*backup_step)(sqlite3_backup*,int); - const char *(*compileoption_get)(int); - int (*compileoption_used)(const char*); - int (*create_function_v2)(sqlite3*,const char*,int,int,void*, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*), - void(*xDestroy)(void*)); - int (*db_config)(sqlite3*,int,...); - sqlite3_mutex *(*db_mutex)(sqlite3*); - int (*db_status)(sqlite3*,int,int*,int*,int); - int (*extended_errcode)(sqlite3*); - void (*log)(int,const char*,...); - sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); - const char *(*sourceid)(void); - int (*stmt_status)(sqlite3_stmt*,int,int); - int (*strnicmp)(const char*,const char*,int); - int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); - int (*wal_autocheckpoint)(sqlite3*,int); - int (*wal_checkpoint)(sqlite3*,const char*); - void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); - int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); - int (*vtab_config)(sqlite3*,int op,...); - int (*vtab_on_conflict)(sqlite3*); - /* Version 3.7.16 and later */ - int (*close_v2)(sqlite3*); - const char *(*db_filename)(sqlite3*,const char*); - int (*db_readonly)(sqlite3*,const char*); - int (*db_release_memory)(sqlite3*); - const char *(*errstr)(int); - int (*stmt_busy)(sqlite3_stmt*); - int (*stmt_readonly)(sqlite3_stmt*); - int (*stricmp)(const char*,const char*); - int (*uri_boolean)(const char*,const char*,int); - sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); - const char *(*uri_parameter)(const char*,const char*); - char *(*xvsnprintf)(int,char*,const char*,va_list); - int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); - /* Version 3.8.7 and later */ - int (*auto_extension)(void(*)(void)); - int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, - void(*)(void*)); - int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, - void(*)(void*),unsigned char); - int (*cancel_auto_extension)(void(*)(void)); - int (*load_extension)(sqlite3*,const char*,const char*,char**); - void *(*malloc64)(sqlite3_uint64); - sqlite3_uint64 (*msize)(void*); - void *(*realloc64)(void*,sqlite3_uint64); - void (*reset_auto_extension)(void); - void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, - void(*)(void*)); - void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, - void(*)(void*), unsigned char); - int (*strglob)(const char*,const char*); - /* Version 3.8.11 and later */ - sqlite3_value *(*value_dup)(const sqlite3_value*); - void (*value_free)(sqlite3_value*); - int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64); - int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64); - /* Version 3.9.0 and later */ - unsigned int (*value_subtype)(sqlite3_value*); - void (*result_subtype)(sqlite3_context*,unsigned int); - /* Version 3.10.0 and later */ - int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); - int (*strlike)(const char*,const char*,unsigned int); - int (*db_cacheflush)(sqlite3*); - /* Version 3.12.0 and later */ - int (*system_errno)(sqlite3*); - /* Version 3.14.0 and later */ - int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); - char *(*expanded_sql)(sqlite3_stmt*); - /* Version 3.18.0 and later */ - void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); - /* Version 3.20.0 and later */ - int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, - sqlite3_stmt**,const char**); - int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, - sqlite3_stmt**,const void**); - int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); - void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); - void *(*value_pointer)(sqlite3_value*,const char*); - int (*vtab_nochange)(sqlite3_context*); - int (*value_nochange)(sqlite3_value*); - const char *(*vtab_collation)(sqlite3_index_info*,int); - /* Version 3.24.0 and later */ - int (*keyword_count)(void); - int (*keyword_name)(int,const char**,int*); - int (*keyword_check)(const char*,int); - sqlite3_str *(*str_new)(sqlite3*); - char *(*str_finish)(sqlite3_str*); - void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); - void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); - void (*str_append)(sqlite3_str*, const char *zIn, int N); - void (*str_appendall)(sqlite3_str*, const char *zIn); - void (*str_appendchar)(sqlite3_str*, int N, char C); - void (*str_reset)(sqlite3_str*); - int (*str_errcode)(sqlite3_str*); - int (*str_length)(sqlite3_str*); - char *(*str_value)(sqlite3_str*); - /* Version 3.25.0 and later */ - int (*create_window_function)(sqlite3*,const char*,int,int,void*, - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*), - void (*xValue)(sqlite3_context*), - void (*xInv)(sqlite3_context*,int,sqlite3_value**), - void(*xDestroy)(void*)); - /* Version 3.26.0 and later */ - const char *(*normalized_sql)(sqlite3_stmt*); - /* Version 3.28.0 and later */ - int (*stmt_isexplain)(sqlite3_stmt*); - int (*value_frombind)(sqlite3_value*); - /* Version 3.30.0 and later */ - int (*drop_modules)(sqlite3*,const char**); - /* Version 3.31.0 and later */ - sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64); - const char *(*uri_key)(const char*,int); - const char *(*filename_database)(const char*); - const char *(*filename_journal)(const char*); - const char *(*filename_wal)(const char*); - /* Version 3.32.0 and later */ - const char *(*create_filename)(const char*,const char*,const char*, - int,const char**); - void (*free_filename)(const char*); - sqlite3_file *(*database_file_object)(const char*); - /* Version 3.34.0 and later */ - int (*txn_state)(sqlite3*,const char*); - /* Version 3.36.1 and later */ - sqlite3_int64 (*changes64)(sqlite3*); - sqlite3_int64 (*total_changes64)(sqlite3*); - /* Version 3.37.0 and later */ - int (*autovacuum_pages)(sqlite3*, - unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), - void*, void(*)(void*)); - /* Version 3.38.0 and later */ - int (*error_offset)(sqlite3*); - int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**); - int (*vtab_distinct)(sqlite3_index_info*); - int (*vtab_in)(sqlite3_index_info*,int,int); - int (*vtab_in_first)(sqlite3_value*,sqlite3_value**); - int (*vtab_in_next)(sqlite3_value*,sqlite3_value**); - /* Version 3.39.0 and later */ - int (*deserialize)(sqlite3*,const char*,unsigned char*, - sqlite3_int64,sqlite3_int64,unsigned); - unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*, - unsigned int); - const char *(*db_name)(sqlite3*,int); - /* Version 3.40.0 and later */ - int (*value_encoding)(sqlite3_value*); - /* Version 3.41.0 and later */ - int (*is_interrupted)(sqlite3*); - /* Version 3.43.0 and later */ - int (*stmt_explain)(sqlite3_stmt*,int); - /* Version 3.44.0 and later */ - void *(*get_clientdata)(sqlite3*,const char*); - int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); -}; - -/* -** This is the function signature used for all extension entry points. It -** is also defined in the file "loadext.c". -*/ -typedef int (*sqlite3_loadext_entry)( - sqlite3 *db, /* Handle to the database. */ - char **pzErrMsg, /* Used to set error string on failure. */ - const sqlite3_api_routines *pThunk /* Extension API function pointers. */ -); - -/* -** The following macros redefine the API routines so that they are -** redirected through the global sqlite3_api structure. -** -** This header file is also used by the loadext.c source file -** (part of the main SQLite library - not an extension) so that -** it can get access to the sqlite3_api_routines structure -** definition. But the main library does not want to redefine -** the API. So the redefinition macros are only valid if the -** SQLITE_CORE macros is undefined. -*/ -#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) -#define sqlite3_aggregate_context sqlite3_api->aggregate_context -#ifndef SQLITE_OMIT_DEPRECATED -#define sqlite3_aggregate_count sqlite3_api->aggregate_count -#endif -#define sqlite3_bind_blob sqlite3_api->bind_blob -#define sqlite3_bind_double sqlite3_api->bind_double -#define sqlite3_bind_int sqlite3_api->bind_int -#define sqlite3_bind_int64 sqlite3_api->bind_int64 -#define sqlite3_bind_null sqlite3_api->bind_null -#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count -#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index -#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name -#define sqlite3_bind_text sqlite3_api->bind_text -#define sqlite3_bind_text16 sqlite3_api->bind_text16 -#define sqlite3_bind_value sqlite3_api->bind_value -#define sqlite3_busy_handler sqlite3_api->busy_handler -#define sqlite3_busy_timeout sqlite3_api->busy_timeout -#define sqlite3_changes sqlite3_api->changes -#define sqlite3_close sqlite3_api->close -#define sqlite3_collation_needed sqlite3_api->collation_needed -#define sqlite3_collation_needed16 sqlite3_api->collation_needed16 -#define sqlite3_column_blob sqlite3_api->column_blob -#define sqlite3_column_bytes sqlite3_api->column_bytes -#define sqlite3_column_bytes16 sqlite3_api->column_bytes16 -#define sqlite3_column_count sqlite3_api->column_count -#define sqlite3_column_database_name sqlite3_api->column_database_name -#define sqlite3_column_database_name16 sqlite3_api->column_database_name16 -#define sqlite3_column_decltype sqlite3_api->column_decltype -#define sqlite3_column_decltype16 sqlite3_api->column_decltype16 -#define sqlite3_column_double sqlite3_api->column_double -#define sqlite3_column_int sqlite3_api->column_int -#define sqlite3_column_int64 sqlite3_api->column_int64 -#define sqlite3_column_name sqlite3_api->column_name -#define sqlite3_column_name16 sqlite3_api->column_name16 -#define sqlite3_column_origin_name sqlite3_api->column_origin_name -#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16 -#define sqlite3_column_table_name sqlite3_api->column_table_name -#define sqlite3_column_table_name16 sqlite3_api->column_table_name16 -#define sqlite3_column_text sqlite3_api->column_text -#define sqlite3_column_text16 sqlite3_api->column_text16 -#define sqlite3_column_type sqlite3_api->column_type -#define sqlite3_column_value sqlite3_api->column_value -#define sqlite3_commit_hook sqlite3_api->commit_hook -#define sqlite3_complete sqlite3_api->complete -#define sqlite3_complete16 sqlite3_api->complete16 -#define sqlite3_create_collation sqlite3_api->create_collation -#define sqlite3_create_collation16 sqlite3_api->create_collation16 -#define sqlite3_create_function sqlite3_api->create_function -#define sqlite3_create_function16 sqlite3_api->create_function16 -#define sqlite3_create_module sqlite3_api->create_module -#define sqlite3_create_module_v2 sqlite3_api->create_module_v2 -#define sqlite3_data_count sqlite3_api->data_count -#define sqlite3_db_handle sqlite3_api->db_handle -#define sqlite3_declare_vtab sqlite3_api->declare_vtab -#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache -#define sqlite3_errcode sqlite3_api->errcode -#define sqlite3_errmsg sqlite3_api->errmsg -#define sqlite3_errmsg16 sqlite3_api->errmsg16 -#define sqlite3_exec sqlite3_api->exec -#ifndef SQLITE_OMIT_DEPRECATED -#define sqlite3_expired sqlite3_api->expired -#endif -#define sqlite3_finalize sqlite3_api->finalize -#define sqlite3_free sqlite3_api->free -#define sqlite3_free_table sqlite3_api->free_table -#define sqlite3_get_autocommit sqlite3_api->get_autocommit -#define sqlite3_get_auxdata sqlite3_api->get_auxdata -#define sqlite3_get_table sqlite3_api->get_table -#ifndef SQLITE_OMIT_DEPRECATED -#define sqlite3_global_recover sqlite3_api->global_recover -#endif -#define sqlite3_interrupt sqlite3_api->interruptx -#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid -#define sqlite3_libversion sqlite3_api->libversion -#define sqlite3_libversion_number sqlite3_api->libversion_number -#define sqlite3_malloc sqlite3_api->malloc -#define sqlite3_mprintf sqlite3_api->mprintf -#define sqlite3_open sqlite3_api->open -#define sqlite3_open16 sqlite3_api->open16 -#define sqlite3_prepare sqlite3_api->prepare -#define sqlite3_prepare16 sqlite3_api->prepare16 -#define sqlite3_prepare_v2 sqlite3_api->prepare_v2 -#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 -#define sqlite3_profile sqlite3_api->profile -#define sqlite3_progress_handler sqlite3_api->progress_handler -#define sqlite3_realloc sqlite3_api->realloc -#define sqlite3_reset sqlite3_api->reset -#define sqlite3_result_blob sqlite3_api->result_blob -#define sqlite3_result_double sqlite3_api->result_double -#define sqlite3_result_error sqlite3_api->result_error -#define sqlite3_result_error16 sqlite3_api->result_error16 -#define sqlite3_result_int sqlite3_api->result_int -#define sqlite3_result_int64 sqlite3_api->result_int64 -#define sqlite3_result_null sqlite3_api->result_null -#define sqlite3_result_text sqlite3_api->result_text -#define sqlite3_result_text16 sqlite3_api->result_text16 -#define sqlite3_result_text16be sqlite3_api->result_text16be -#define sqlite3_result_text16le sqlite3_api->result_text16le -#define sqlite3_result_value sqlite3_api->result_value -#define sqlite3_rollback_hook sqlite3_api->rollback_hook -#define sqlite3_set_authorizer sqlite3_api->set_authorizer -#define sqlite3_set_auxdata sqlite3_api->set_auxdata -#define sqlite3_snprintf sqlite3_api->xsnprintf -#define sqlite3_step sqlite3_api->step -#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata -#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup -#define sqlite3_total_changes sqlite3_api->total_changes -#define sqlite3_trace sqlite3_api->trace -#ifndef SQLITE_OMIT_DEPRECATED -#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings -#endif -#define sqlite3_update_hook sqlite3_api->update_hook -#define sqlite3_user_data sqlite3_api->user_data -#define sqlite3_value_blob sqlite3_api->value_blob -#define sqlite3_value_bytes sqlite3_api->value_bytes -#define sqlite3_value_bytes16 sqlite3_api->value_bytes16 -#define sqlite3_value_double sqlite3_api->value_double -#define sqlite3_value_int sqlite3_api->value_int -#define sqlite3_value_int64 sqlite3_api->value_int64 -#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type -#define sqlite3_value_text sqlite3_api->value_text -#define sqlite3_value_text16 sqlite3_api->value_text16 -#define sqlite3_value_text16be sqlite3_api->value_text16be -#define sqlite3_value_text16le sqlite3_api->value_text16le -#define sqlite3_value_type sqlite3_api->value_type -#define sqlite3_vmprintf sqlite3_api->vmprintf -#define sqlite3_vsnprintf sqlite3_api->xvsnprintf -#define sqlite3_overload_function sqlite3_api->overload_function -#define sqlite3_prepare_v2 sqlite3_api->prepare_v2 -#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 -#define sqlite3_clear_bindings sqlite3_api->clear_bindings -#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob -#define sqlite3_blob_bytes sqlite3_api->blob_bytes -#define sqlite3_blob_close sqlite3_api->blob_close -#define sqlite3_blob_open sqlite3_api->blob_open -#define sqlite3_blob_read sqlite3_api->blob_read -#define sqlite3_blob_write sqlite3_api->blob_write -#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2 -#define sqlite3_file_control sqlite3_api->file_control -#define sqlite3_memory_highwater sqlite3_api->memory_highwater -#define sqlite3_memory_used sqlite3_api->memory_used -#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc -#define sqlite3_mutex_enter sqlite3_api->mutex_enter -#define sqlite3_mutex_free sqlite3_api->mutex_free -#define sqlite3_mutex_leave sqlite3_api->mutex_leave -#define sqlite3_mutex_try sqlite3_api->mutex_try -#define sqlite3_open_v2 sqlite3_api->open_v2 -#define sqlite3_release_memory sqlite3_api->release_memory -#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem -#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig -#define sqlite3_sleep sqlite3_api->sleep -#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit -#define sqlite3_vfs_find sqlite3_api->vfs_find -#define sqlite3_vfs_register sqlite3_api->vfs_register -#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister -#define sqlite3_threadsafe sqlite3_api->xthreadsafe -#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob -#define sqlite3_result_error_code sqlite3_api->result_error_code -#define sqlite3_test_control sqlite3_api->test_control -#define sqlite3_randomness sqlite3_api->randomness -#define sqlite3_context_db_handle sqlite3_api->context_db_handle -#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes -#define sqlite3_limit sqlite3_api->limit -#define sqlite3_next_stmt sqlite3_api->next_stmt -#define sqlite3_sql sqlite3_api->sql -#define sqlite3_status sqlite3_api->status -#define sqlite3_backup_finish sqlite3_api->backup_finish -#define sqlite3_backup_init sqlite3_api->backup_init -#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount -#define sqlite3_backup_remaining sqlite3_api->backup_remaining -#define sqlite3_backup_step sqlite3_api->backup_step -#define sqlite3_compileoption_get sqlite3_api->compileoption_get -#define sqlite3_compileoption_used sqlite3_api->compileoption_used -#define sqlite3_create_function_v2 sqlite3_api->create_function_v2 -#define sqlite3_db_config sqlite3_api->db_config -#define sqlite3_db_mutex sqlite3_api->db_mutex -#define sqlite3_db_status sqlite3_api->db_status -#define sqlite3_extended_errcode sqlite3_api->extended_errcode -#define sqlite3_log sqlite3_api->log -#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64 -#define sqlite3_sourceid sqlite3_api->sourceid -#define sqlite3_stmt_status sqlite3_api->stmt_status -#define sqlite3_strnicmp sqlite3_api->strnicmp -#define sqlite3_unlock_notify sqlite3_api->unlock_notify -#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint -#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint -#define sqlite3_wal_hook sqlite3_api->wal_hook -#define sqlite3_blob_reopen sqlite3_api->blob_reopen -#define sqlite3_vtab_config sqlite3_api->vtab_config -#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict -/* Version 3.7.16 and later */ -#define sqlite3_close_v2 sqlite3_api->close_v2 -#define sqlite3_db_filename sqlite3_api->db_filename -#define sqlite3_db_readonly sqlite3_api->db_readonly -#define sqlite3_db_release_memory sqlite3_api->db_release_memory -#define sqlite3_errstr sqlite3_api->errstr -#define sqlite3_stmt_busy sqlite3_api->stmt_busy -#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly -#define sqlite3_stricmp sqlite3_api->stricmp -#define sqlite3_uri_boolean sqlite3_api->uri_boolean -#define sqlite3_uri_int64 sqlite3_api->uri_int64 -#define sqlite3_uri_parameter sqlite3_api->uri_parameter -#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf -#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 -/* Version 3.8.7 and later */ -#define sqlite3_auto_extension sqlite3_api->auto_extension -#define sqlite3_bind_blob64 sqlite3_api->bind_blob64 -#define sqlite3_bind_text64 sqlite3_api->bind_text64 -#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension -#define sqlite3_load_extension sqlite3_api->load_extension -#define sqlite3_malloc64 sqlite3_api->malloc64 -#define sqlite3_msize sqlite3_api->msize -#define sqlite3_realloc64 sqlite3_api->realloc64 -#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension -#define sqlite3_result_blob64 sqlite3_api->result_blob64 -#define sqlite3_result_text64 sqlite3_api->result_text64 -#define sqlite3_strglob sqlite3_api->strglob -/* Version 3.8.11 and later */ -#define sqlite3_value_dup sqlite3_api->value_dup -#define sqlite3_value_free sqlite3_api->value_free -#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64 -#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64 -/* Version 3.9.0 and later */ -#define sqlite3_value_subtype sqlite3_api->value_subtype -#define sqlite3_result_subtype sqlite3_api->result_subtype -/* Version 3.10.0 and later */ -#define sqlite3_status64 sqlite3_api->status64 -#define sqlite3_strlike sqlite3_api->strlike -#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush -/* Version 3.12.0 and later */ -#define sqlite3_system_errno sqlite3_api->system_errno -/* Version 3.14.0 and later */ -#define sqlite3_trace_v2 sqlite3_api->trace_v2 -#define sqlite3_expanded_sql sqlite3_api->expanded_sql -/* Version 3.18.0 and later */ -#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid -/* Version 3.20.0 and later */ -#define sqlite3_prepare_v3 sqlite3_api->prepare_v3 -#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3 -#define sqlite3_bind_pointer sqlite3_api->bind_pointer -#define sqlite3_result_pointer sqlite3_api->result_pointer -#define sqlite3_value_pointer sqlite3_api->value_pointer -/* Version 3.22.0 and later */ -#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange -#define sqlite3_value_nochange sqlite3_api->value_nochange -#define sqlite3_vtab_collation sqlite3_api->vtab_collation -/* Version 3.24.0 and later */ -#define sqlite3_keyword_count sqlite3_api->keyword_count -#define sqlite3_keyword_name sqlite3_api->keyword_name -#define sqlite3_keyword_check sqlite3_api->keyword_check -#define sqlite3_str_new sqlite3_api->str_new -#define sqlite3_str_finish sqlite3_api->str_finish -#define sqlite3_str_appendf sqlite3_api->str_appendf -#define sqlite3_str_vappendf sqlite3_api->str_vappendf -#define sqlite3_str_append sqlite3_api->str_append -#define sqlite3_str_appendall sqlite3_api->str_appendall -#define sqlite3_str_appendchar sqlite3_api->str_appendchar -#define sqlite3_str_reset sqlite3_api->str_reset -#define sqlite3_str_errcode sqlite3_api->str_errcode -#define sqlite3_str_length sqlite3_api->str_length -#define sqlite3_str_value sqlite3_api->str_value -/* Version 3.25.0 and later */ -#define sqlite3_create_window_function sqlite3_api->create_window_function -/* Version 3.26.0 and later */ -#define sqlite3_normalized_sql sqlite3_api->normalized_sql -/* Version 3.28.0 and later */ -#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain -#define sqlite3_value_frombind sqlite3_api->value_frombind -/* Version 3.30.0 and later */ -#define sqlite3_drop_modules sqlite3_api->drop_modules -/* Version 3.31.0 and later */ -#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64 -#define sqlite3_uri_key sqlite3_api->uri_key -#define sqlite3_filename_database sqlite3_api->filename_database -#define sqlite3_filename_journal sqlite3_api->filename_journal -#define sqlite3_filename_wal sqlite3_api->filename_wal -/* Version 3.32.0 and later */ -#define sqlite3_create_filename sqlite3_api->create_filename -#define sqlite3_free_filename sqlite3_api->free_filename -#define sqlite3_database_file_object sqlite3_api->database_file_object -/* Version 3.34.0 and later */ -#define sqlite3_txn_state sqlite3_api->txn_state -/* Version 3.36.1 and later */ -#define sqlite3_changes64 sqlite3_api->changes64 -#define sqlite3_total_changes64 sqlite3_api->total_changes64 -/* Version 3.37.0 and later */ -#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages -/* Version 3.38.0 and later */ -#define sqlite3_error_offset sqlite3_api->error_offset -#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value -#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct -#define sqlite3_vtab_in sqlite3_api->vtab_in -#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first -#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next -/* Version 3.39.0 and later */ -#ifndef SQLITE_OMIT_DESERIALIZE -#define sqlite3_deserialize sqlite3_api->deserialize -#define sqlite3_serialize sqlite3_api->serialize -#endif -#define sqlite3_db_name sqlite3_api->db_name -/* Version 3.40.0 and later */ -#define sqlite3_value_encoding sqlite3_api->value_encoding -/* Version 3.41.0 and later */ -#define sqlite3_is_interrupted sqlite3_api->is_interrupted -/* Version 3.43.0 and later */ -#define sqlite3_stmt_explain sqlite3_api->stmt_explain -/* Version 3.44.0 and later */ -#define sqlite3_get_clientdata sqlite3_api->get_clientdata -#define sqlite3_set_clientdata sqlite3_api->set_clientdata -#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ - -#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) - /* This case when the file really is being compiled as a loadable - ** extension */ -# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; -# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; -# define SQLITE_EXTENSION_INIT3 \ - extern const sqlite3_api_routines *sqlite3_api; -#else - /* This case when the file is being statically linked into the - ** application */ -# define SQLITE_EXTENSION_INIT1 /*no-op*/ -# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ -# define SQLITE_EXTENSION_INIT3 /*no-op*/ -#endif - -#endif /* SQLITE3EXT_H */ -/*** End of #include "sqlite3ext.h" ***/ SQLITE_EXTENSION_INIT1 #else @@ -288536,34 +341259,34 @@ typedef struct map{ /* ** creates a map given a comparison function */ -map map_make(cmp_func cmp); +static map map_make(cmp_func cmp); /* ** inserts the element e into map m */ -void map_insert(map *m, void *e); +static void map_insert(map *m, void *e); /* ** executes function iter over all elements in the map, in key increasing order */ -void map_iterate(map *m, map_iterator iter, void* p); +static void map_iterate(map *m, map_iterator iter, void* p); /* ** frees all memory used by a map */ -void map_destroy(map *m); +static void map_destroy(map *m); /* ** compares 2 integers ** to use with map_make */ -int int_cmp(const void *a, const void *b); +static int int_cmp(const void *a, const void *b); /* ** compares 2 doubles ** to use with map_make */ -int double_cmp(const void *a, const void *b); +static int double_cmp(const void *a, const void *b); #endif /* _MAP_H_ */ @@ -290105,6 +342828,7 @@ static void lastRowsFunc(sqlite3_context *context, int argc, sqlite3_value **arg ** functions. This should be the only routine in this file with ** external linkage. */ +SQLITE_API int RegisterExtensionFunctions(sqlite3 *db){ static const struct FuncDef { char *zName; @@ -290373,9 +343097,7 @@ void print_elem(void *e, i64 c, void* p){ */ #ifdef SQLITE_ENABLE_CSV /* Prototype for initialization function of CSV extension */ -#ifdef _WIN32 -__declspec(dllexport) -#endif +SQLITE_API int sqlite3_csv_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* pApi); /* #include "csv.c" */ /*** Begin of #include "csv.c" ***/ @@ -290405,8 +343127,8 @@ int sqlite3_csv_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* p ** schema= parameter, like this: ** ** CREATE VIRTUAL TABLE temp.csv2 USING csv( -** filename = "../http.log", -** schema = "CREATE TABLE x(date,ipaddr,url,referrer,userAgent)" +** filename = '../http.log', +** schema = 'CREATE TABLE x(date,ipaddr,url,referrer,userAgent)' ** ); ** ** Instead of specifying a file, the text of the CSV can be loaded using @@ -290444,6 +343166,10 @@ SQLITE_EXTENSION_INIT1 # define CSV_NOINLINE #endif +#ifndef SQLITEINT_H +typedef sqlite3_int64 i64; +typedef sqlite3_uint64 u64; +#endif /* Max size of the error message in a CsvReader */ #define CSV_MXERR 200 @@ -290456,9 +343182,9 @@ typedef struct CsvReader CsvReader; struct CsvReader { FILE *in; /* Read the CSV text from this input stream */ char *z; /* Accumulated text for a field */ - int n; /* Number of bytes in z */ - int nAlloc; /* Space allocated for z[] */ - int nLine; /* Current line number */ + i64 n; /* Number of bytes in z */ + i64 nAlloc; /* Space allocated for z[] */ + i64 nLine; /* Current line number */ int bNotFirst; /* True if prior text has been seen */ int cTerm; /* Character that terminated the most recent field */ size_t iIn; /* Next unread character in the input buffer */ @@ -290507,7 +343233,7 @@ static int csv_reader_open( const char *zData /* ... or use this data */ ){ if( zFilename ){ - p->zIn = sqlite3_malloc( CSV_INBUFSZ ); + p->zIn = sqlite3_malloc64( CSV_INBUFSZ ); if( p->zIn==0 ){ csv_errmsg(p, "out of memory"); return 1; @@ -290556,7 +343282,7 @@ static int csv_getc(CsvReader *p){ ** Return 0 on success and non-zero if there is an OOM error */ static CSV_NOINLINE int csv_resize_and_append(CsvReader *p, char c){ char *zNew; - int nNew = p->nAlloc*2 + 100; + i64 nNew = p->nAlloc*2 + 100; zNew = sqlite3_realloc64(p->z, nNew); if( zNew ){ p->z = zNew; @@ -290600,7 +343326,7 @@ static char *csv_read_one_field(CsvReader *p){ } if( c=='"' ){ int pc, ppc; - int startLine = p->nLine; + i64 startLine = p->nLine; pc = ppc = 0; while( 1 ){ c = csv_getc(p); @@ -290697,14 +343423,14 @@ typedef struct CsvTable { } CsvTable; /* Allowed values for tstFlags */ -#define CSVTEST_FIDX 0x0001 /* Pretend that constrained searchs cost less*/ +#define CSVTEST_FIDX 0x0001 /* Pretend that constrained search cost less*/ /* A cursor for the CSV virtual table */ typedef struct CsvCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ CsvReader rdr; /* The CsvReader object */ char **azVal; /* Value of the current row */ - int *aLen; /* Length of each entry */ + i64 *aLen; /* Length of each entry */ sqlite3_int64 iRowid; /* The current rowid. Negative for EOF */ } CsvCursor; @@ -290876,7 +343602,7 @@ static int csvtabConnect( CsvTable *pNew = 0; /* The CsvTable object to construct */ int bHeader = -1; /* header= flags. -1 means not seen yet */ int rc = SQLITE_OK; /* Result code from this routine */ - int i, j; /* Loop counters */ + u64 i, j; /* Loop counters */ #ifdef SQLITE_TEST int tstFlags = 0; /* Value for testflags=N parameter */ #endif @@ -290892,11 +343618,10 @@ static int csvtabConnect( # define CSV_DATA (azPValue[1]) # define CSV_SCHEMA (azPValue[2]) - assert( sizeof(azPValue)==sizeof(azParam) ); memset(&sRdr, 0, sizeof(sRdr)); memset(azPValue, 0, sizeof(azPValue)); - for(i=3; inCol; + nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(i64))*pTab->nCol; pCur = sqlite3_malloc64( nByte ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, nByte); pCur->azVal = (char**)&pCur[1]; - pCur->aLen = (int*)&pCur->azVal[pTab->nCol]; + pCur->aLen = (i64*)&pCur->azVal[pTab->nCol]; *ppCursor = &pCur->base; if( csv_reader_open(&pCur->rdr, pTab->zFilename, pTab->zData) ){ csv_xfer_error(pTab, &pCur->rdr); @@ -291327,14 +344052,15 @@ static sqlite3_module CsvModuleFauxWrite = { #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ -#ifdef _WIN32 -__declspec(dllexport) +#ifndef SQLITE_API +#define SQLITE_API #endif /* ** This routine is called when the extension is loaded. The new ** CSV virtual table module is registered with the calling database ** connection. */ +SQLITE_API int sqlite3_csv_init( sqlite3 *db, char **pzErrMsg, @@ -291363,9 +344089,7 @@ int sqlite3_csv_init( */ #ifdef SQLITE_ENABLE_VSV /* Prototype for initialization function of VSV extension */ -#ifdef _WIN32 -__declspec(dllexport) -#endif +SQLITE_API int sqlite3_vsv_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* pApi); /* #include "vsv.c" */ /*** Begin of #include "vsv.c" ***/ @@ -293375,11 +346099,10 @@ static sqlite3_module VsvModuleFauxWrite = { ** VSV virtual table module is registered with the calling database ** connection. */ -#ifndef SQLITE_CORE -#ifdef _WIN32 -__declspec(dllexport) -#endif +#ifndef SQLITE_API +#define SQLITE_API #endif +SQLITE_API int sqlite3_vsv_init( sqlite3 *db, char **pzErrMsg, @@ -293414,9 +346137,7 @@ int sqlite3_vsv_init( */ #ifdef SQLITE_ENABLE_SHA3 /* Prototype for initialization function of SHA3 extension */ -#ifdef _WIN32 -__declspec(dllexport) -#endif +SQLITE_API int sqlite3_shathree_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* pApi); /* #include "shathree.c" */ /*** Begin of #include "shathree.c" ***/ @@ -293434,7 +346155,7 @@ int sqlite3_shathree_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routin ** ** This SQLite extension implements functions that compute SHA3 hashes ** in the way described by the (U.S.) NIST FIPS 202 SHA-3 Standard. -** Two SQL functions are implemented: +** Three SQL functions are implemented: ** ** sha3(X,SIZE) ** sha3_agg(Y,SIZE) @@ -293486,7 +346207,7 @@ int sqlite3_shathree_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routin ** ** typeof(Y)='blob' The hash is taken over prefix "Bnnn:" followed ** by the binary content of the blob. The "nnn" -** in the prefix is the mimimum-length decimal +** in the prefix is the minimum-length decimal ** representation of the byte-length of the blob. ** ** According to the rules above, all of the following SELECT statements @@ -294232,11 +346953,10 @@ static void sha3AggFinal(sqlite3_context *context){ } } - - -#ifdef _WIN32 -__declspec(dllexport) +#ifndef SQLITE_API +#define SQLITE_API #endif +SQLITE_API int sqlite3_shathree_init( sqlite3 *db, char **pzErrMsg, @@ -294279,591 +346999,12 @@ int sqlite3_shathree_init( #endif -/* -** CARRAY -*/ -#ifdef SQLITE_ENABLE_CARRAY -/* Prototype for initialization function of CARRAY extension */ -#ifdef _WIN32 -__declspec(dllexport) -#endif -int sqlite3_carray_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* pApi); -/* #include "carray.c" */ -/*** Begin of #include "carray.c" ***/ -/* -** 2016-06-29 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This file demonstrates how to create a table-valued-function that -** returns the values in a C-language array. -** Examples: -** -** SELECT * FROM carray($ptr,5) -** -** The query above returns 5 integers contained in a C-language array -** at the address $ptr. $ptr is a pointer to the array of integers. -** The pointer value must be assigned to $ptr using the -** sqlite3_bind_pointer() interface with a pointer type of "carray". -** For example: -** -** static int aX[] = { 53, 9, 17, 2231, 4, 99 }; -** int i = sqlite3_bind_parameter_index(pStmt, "$ptr"); -** sqlite3_bind_pointer(pStmt, i, aX, "carray", 0); -** -** There is an optional third parameter to determine the datatype of -** the C-language array. Allowed values of the third parameter are -** 'int32', 'int64', 'double', 'char*', 'struct iovec'. Example: -** -** SELECT * FROM carray($ptr,10,'char*'); -** -** The default value of the third parameter is 'int32'. -** -** HOW IT WORKS -** -** The carray "function" is really a virtual table with the -** following schema: -** -** CREATE TABLE carray( -** value, -** pointer HIDDEN, -** count HIDDEN, -** ctype TEXT HIDDEN -** ); -** -** If the hidden columns "pointer" and "count" are unconstrained, then -** the virtual table has no rows. Otherwise, the virtual table interprets -** the integer value of "pointer" as a pointer to the array and "count" -** as the number of elements in the array. The virtual table steps through -** the array, element by element. -*/ -/* #include "sqlite3ext.h" */ - -SQLITE_EXTENSION_INIT1 -#include -#include -#ifdef _WIN32 - struct iovec { - void *iov_base; - size_t iov_len; - }; -#else -# include -#endif - -/* Allowed values for the mFlags parameter to sqlite3_carray_bind(). -** Must exactly match the definitions in carray.h. -*/ -#ifndef CARRAY_INT32 -# define CARRAY_INT32 0 /* Data is 32-bit signed integers */ -# define CARRAY_INT64 1 /* Data is 64-bit signed integers */ -# define CARRAY_DOUBLE 2 /* Data is doubles */ -# define CARRAY_TEXT 3 /* Data is char* */ -# define CARRAY_BLOB 4 /* Data is struct iovec* */ -#endif - -#ifndef SQLITE_API -# ifdef _WIN32 -# define SQLITE_API __declspec(dllexport) -# else -# define SQLITE_API -# endif -#endif - -#ifndef SQLITE_OMIT_VIRTUALTABLE - -/* -** Names of allowed datatypes -*/ -static const char *azType[] = { "int32", "int64", "double", "char*", - "struct iovec" }; - -/* -** Structure used to hold the sqlite3_carray_bind() information -*/ -typedef struct carray_bind carray_bind; -struct carray_bind { - void *aData; /* The data */ - int nData; /* Number of elements */ - int mFlags; /* Control flags */ - void (*xDel)(void*); /* Destructor for aData */ -}; - - -/* carray_cursor is a subclass of sqlite3_vtab_cursor which will -** serve as the underlying representation of a cursor that scans -** over rows of the result -*/ -typedef struct carray_cursor carray_cursor; -struct carray_cursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - sqlite3_int64 iRowid; /* The rowid */ - void *pPtr; /* Pointer to the array of values */ - sqlite3_int64 iCnt; /* Number of integers in the array */ - unsigned char eType; /* One of the CARRAY_type values */ -}; - -/* -** The carrayConnect() method is invoked to create a new -** carray_vtab that describes the carray virtual table. -** -** Think of this routine as the constructor for carray_vtab objects. -** -** All this routine needs to do is: -** -** (1) Allocate the carray_vtab object and initialize all fields. -** -** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the -** result set of queries against carray will look like. -*/ -static int carrayConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr -){ - sqlite3_vtab *pNew; - int rc; - -/* Column numbers */ -#define CARRAY_COLUMN_VALUE 0 -#define CARRAY_COLUMN_POINTER 1 -#define CARRAY_COLUMN_COUNT 2 -#define CARRAY_COLUMN_CTYPE 3 - - rc = sqlite3_declare_vtab(db, - "CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)"); - if( rc==SQLITE_OK ){ - pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); - if( pNew==0 ) return SQLITE_NOMEM; - memset(pNew, 0, sizeof(*pNew)); - } - return rc; -} - -/* -** This method is the destructor for carray_cursor objects. -*/ -static int carrayDisconnect(sqlite3_vtab *pVtab){ - sqlite3_free(pVtab); - return SQLITE_OK; -} - -/* -** Constructor for a new carray_cursor object. -*/ -static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - carray_cursor *pCur; - pCur = sqlite3_malloc( sizeof(*pCur) ); - if( pCur==0 ) return SQLITE_NOMEM; - memset(pCur, 0, sizeof(*pCur)); - *ppCursor = &pCur->base; - return SQLITE_OK; -} - -/* -** Destructor for a carray_cursor. -*/ -static int carrayClose(sqlite3_vtab_cursor *cur){ - sqlite3_free(cur); - return SQLITE_OK; -} - - -/* -** Advance a carray_cursor to its next row of output. -*/ -static int carrayNext(sqlite3_vtab_cursor *cur){ - carray_cursor *pCur = (carray_cursor*)cur; - pCur->iRowid++; - return SQLITE_OK; -} - -/* -** Return values of columns for the row at which the carray_cursor -** is currently pointing. -*/ -static int carrayColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ -){ - carray_cursor *pCur = (carray_cursor*)cur; - sqlite3_int64 x = 0; - switch( i ){ - case CARRAY_COLUMN_POINTER: return SQLITE_OK; - case CARRAY_COLUMN_COUNT: x = pCur->iCnt; break; - case CARRAY_COLUMN_CTYPE: { - sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC); - return SQLITE_OK; - } - default: { - switch( pCur->eType ){ - case CARRAY_INT32: { - int *p = (int*)pCur->pPtr; - sqlite3_result_int(ctx, p[pCur->iRowid-1]); - return SQLITE_OK; - } - case CARRAY_INT64: { - sqlite3_int64 *p = (sqlite3_int64*)pCur->pPtr; - sqlite3_result_int64(ctx, p[pCur->iRowid-1]); - return SQLITE_OK; - } - case CARRAY_DOUBLE: { - double *p = (double*)pCur->pPtr; - sqlite3_result_double(ctx, p[pCur->iRowid-1]); - return SQLITE_OK; - } - case CARRAY_TEXT: { - const char **p = (const char**)pCur->pPtr; - sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT); - return SQLITE_OK; - } - case CARRAY_BLOB: { - const struct iovec *p = (struct iovec*)pCur->pPtr; - sqlite3_result_blob(ctx, p[pCur->iRowid-1].iov_base, - (int)p[pCur->iRowid-1].iov_len, SQLITE_TRANSIENT); - return SQLITE_OK; - } - } - } - } - sqlite3_result_int64(ctx, x); - return SQLITE_OK; -} - -/* -** Return the rowid for the current row. In this implementation, the -** rowid is the same as the output value. -*/ -static int carrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - carray_cursor *pCur = (carray_cursor*)cur; - *pRowid = pCur->iRowid; - return SQLITE_OK; -} - -/* -** Return TRUE if the cursor has been moved off of the last -** row of output. -*/ -static int carrayEof(sqlite3_vtab_cursor *cur){ - carray_cursor *pCur = (carray_cursor*)cur; - return pCur->iRowid>pCur->iCnt; -} - -/* -** This method is called to "rewind" the carray_cursor object back -** to the first row of output. -*/ -static int carrayFilter( - sqlite3_vtab_cursor *pVtabCursor, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv -){ - carray_cursor *pCur = (carray_cursor *)pVtabCursor; - pCur->pPtr = 0; - pCur->iCnt = 0; - switch( idxNum ){ - case 1: { - carray_bind *pBind = sqlite3_value_pointer(argv[0], "carray-bind"); - if( pBind==0 ) break; - pCur->pPtr = pBind->aData; - pCur->iCnt = pBind->nData; - pCur->eType = pBind->mFlags & 0x07; - break; - } - case 2: - case 3: { - pCur->pPtr = sqlite3_value_pointer(argv[0], "carray"); - pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0; - if( idxNum<3 ){ - pCur->eType = CARRAY_INT32; - }else{ - unsigned char i; - const char *zType = (const char*)sqlite3_value_text(argv[2]); - for(i=0; i=sizeof(azType)/sizeof(azType[0]) ){ - pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf( - "unknown datatype: %Q", zType); - return SQLITE_ERROR; - }else{ - pCur->eType = i; - } - } - break; - } - } - pCur->iRowid = 1; - return SQLITE_OK; -} - -/* -** SQLite will invoke this method one or more times while planning a query -** that uses the carray virtual table. This routine needs to create -** a query plan for each invocation and compute an estimated cost for that -** plan. -** -** In this implementation idxNum is used to represent the -** query plan. idxStr is unused. -** -** idxNum is: -** -** 1 If only the pointer= constraint exists. In this case, the -** parameter must be bound using sqlite3_carray_bind(). -** -** 2 if the pointer= and count= constraints exist. -** -** 3 if the ctype= constraint also exists. -** -** idxNum is 0 otherwise and carray becomes an empty table. -*/ -static int carrayBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo -){ - int i; /* Loop over constraints */ - int ptrIdx = -1; /* Index of the pointer= constraint, or -1 if none */ - int cntIdx = -1; /* Index of the count= constraint, or -1 if none */ - int ctypeIdx = -1; /* Index of the ctype= constraint, or -1 if none */ - - const struct sqlite3_index_constraint *pConstraint; - pConstraint = pIdxInfo->aConstraint; - for(i=0; inConstraint; i++, pConstraint++){ - if( pConstraint->usable==0 ) continue; - if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - switch( pConstraint->iColumn ){ - case CARRAY_COLUMN_POINTER: - ptrIdx = i; - break; - case CARRAY_COLUMN_COUNT: - cntIdx = i; - break; - case CARRAY_COLUMN_CTYPE: - ctypeIdx = i; - break; - } - } - if( ptrIdx>=0 ){ - pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1; - pIdxInfo->aConstraintUsage[ptrIdx].omit = 1; - pIdxInfo->estimatedCost = (double)1; - pIdxInfo->estimatedRows = 100; - pIdxInfo->idxNum = 1; - if( cntIdx>=0 ){ - pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2; - pIdxInfo->aConstraintUsage[cntIdx].omit = 1; - pIdxInfo->idxNum = 2; - if( ctypeIdx>=0 ){ - pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3; - pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1; - pIdxInfo->idxNum = 3; - } - } - }else{ - pIdxInfo->estimatedCost = (double)2147483647; - pIdxInfo->estimatedRows = 2147483647; - pIdxInfo->idxNum = 0; - } - return SQLITE_OK; -} - -/* -** This following structure defines all the methods for the -** carray virtual table. -*/ -static sqlite3_module carrayModule = { - 0, /* iVersion */ - 0, /* xCreate */ - carrayConnect, /* xConnect */ - carrayBestIndex, /* xBestIndex */ - carrayDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - carrayOpen, /* xOpen - open a cursor */ - carrayClose, /* xClose - close a cursor */ - carrayFilter, /* xFilter - configure scan constraints */ - carrayNext, /* xNext - advance a cursor */ - carrayEof, /* xEof - check for end of scan */ - carrayColumn, /* xColumn - read data */ - carrayRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0, /* xRollbackTo */ - 0, /* xShadow */ - 0 /* xIntegrity */ -}; - -/* -** Destructor for the carray_bind object -*/ -static void carrayBindDel(void *pPtr){ - carray_bind *p = (carray_bind*)pPtr; - if( p->xDel!=SQLITE_STATIC ){ - p->xDel(p->aData); - } - sqlite3_free(p); -} - -/* -** Invoke this interface in order to bind to the single-argument -** version of CARRAY(). -*/ -SQLITE_API int sqlite3_carray_bind( - sqlite3_stmt *pStmt, - int idx, - void *aData, - int nData, - int mFlags, - void (*xDestroy)(void*) -){ - carray_bind *pNew; - int i; - pNew = sqlite3_malloc64(sizeof(*pNew)); - if( pNew==0 ){ - if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){ - xDestroy(aData); - } - return SQLITE_NOMEM; - } - pNew->nData = nData; - pNew->mFlags = mFlags; - if( xDestroy==SQLITE_TRANSIENT ){ - sqlite3_int64 sz = nData; - switch( mFlags & 0x07 ){ - case CARRAY_INT32: sz *= 4; break; - case CARRAY_INT64: sz *= 8; break; - case CARRAY_DOUBLE: sz *= 8; break; - case CARRAY_TEXT: sz *= sizeof(char*); break; - case CARRAY_BLOB: sz *= sizeof(struct iovec); break; - } - if( (mFlags & 0x07)==CARRAY_TEXT ){ - for(i=0; iaData = sqlite3_malloc64( sz ); - if( pNew->aData==0 ){ - sqlite3_free(pNew); - return SQLITE_NOMEM; - } - if( (mFlags & 0x07)==CARRAY_TEXT ){ - char **az = (char**)pNew->aData; - char *z = (char*)&az[nData]; - for(i=0; iaData; - unsigned char *z = (unsigned char*)&p[nData]; - for(i=0; iaData, aData, sz); - } - pNew->xDel = sqlite3_free; - }else{ - pNew->aData = aData; - pNew->xDel = xDestroy; - } - return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel); -} - - -/* -** For testing purpose in the TCL test harness, we need a method for -** setting the pointer value. The inttoptr(X) SQL function accomplishes -** this. Tcl script will bind an integer to X and the inttoptr() SQL -** function will use sqlite3_result_pointer() to convert that integer into -** a pointer. -** -** This is for testing on TCL only. -*/ -#ifdef SQLITE_TEST -static void inttoptrFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - void *p; - sqlite3_int64 i64; - i64 = sqlite3_value_int64(argv[0]); - if( sizeof(i64)==sizeof(p) ){ - memcpy(&p, &i64, sizeof(p)); - }else{ - int i32 = i64 & 0xffffffff; - memcpy(&p, &i32, sizeof(p)); - } - sqlite3_result_pointer(context, p, "carray", 0); -} -#endif /* SQLITE_TEST */ - -#endif /* SQLITE_OMIT_VIRTUALTABLE */ - -SQLITE_API int sqlite3_carray_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); -#ifndef SQLITE_OMIT_VIRTUALTABLE - rc = sqlite3_create_module(db, "carray", &carrayModule, 0); -#ifdef SQLITE_TEST - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0, - inttoptrFunc, 0, 0); - } -#endif /* SQLITE_TEST */ -#endif /* SQLITE_OMIT_VIRTUALTABLE */ - return rc; -} -/*** End of #include "carray.c" ***/ - -#endif - /* ** FILEIO */ #ifdef SQLITE_ENABLE_FILEIO /* Prototype for initialization function of FILEIO extension */ -#ifdef _WIN32 -__declspec(dllexport) -#endif +SQLITE_API int sqlite3_fileio_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* pApi); /* MinGW specifics */ @@ -294878,364 +347019,6 @@ int sqlite3_fileio_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines # endif #endif -/* #include "test_windirent.c" */ -/*** Begin of #include "test_windirent.c" ***/ -/* -** 2015 November 30 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file contains code to implement most of the opendir() family of -** POSIX functions on Win32 using the MSVCRT. -*/ - -#if defined(_WIN32) && defined(_MSC_VER) -/* #include "test_windirent.h" */ -/*** Begin of #include "test_windirent.h" ***/ -/* -** 2015 November 30 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file contains declarations for most of the opendir() family of -** POSIX functions on Win32 using the MSVCRT. -*/ - -#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H) -#define SQLITE_WINDIRENT_H - -/* -** We need several data types from the Windows SDK header. -*/ - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#include "windows.h" - -/* -** We need several support functions from the SQLite core. -*/ - -/* #include "sqlite3.h" */ - - -/* -** We need several things from the ANSI and MSVCRT headers. -*/ - -#include -#include -#include -#include -#include -#include -#include - -/* -** We may need several defines that should have been in "sys/stat.h". -*/ - -#ifndef S_ISREG -#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) -#endif - -#ifndef S_ISDIR -#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) -#endif - -#ifndef S_ISLNK -#define S_ISLNK(mode) (0) -#endif - -/* -** We may need to provide the "mode_t" type. -*/ - -#ifndef MODE_T_DEFINED - #define MODE_T_DEFINED - typedef unsigned short mode_t; -#endif - -/* -** We may need to provide the "ino_t" type. -*/ - -#ifndef INO_T_DEFINED - #define INO_T_DEFINED - typedef unsigned short ino_t; -#endif - -/* -** We need to define "NAME_MAX" if it was not present in "limits.h". -*/ - -#ifndef NAME_MAX -# ifdef FILENAME_MAX -# define NAME_MAX (FILENAME_MAX) -# else -# define NAME_MAX (260) -# endif -#endif - -/* -** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T". -*/ - -#ifndef NULL_INTPTR_T -# define NULL_INTPTR_T ((intptr_t)(0)) -#endif - -#ifndef BAD_INTPTR_T -# define BAD_INTPTR_T ((intptr_t)(-1)) -#endif - -/* -** We need to provide the necessary structures and related types. -*/ - -#ifndef DIRENT_DEFINED -#define DIRENT_DEFINED -typedef struct DIRENT DIRENT; -typedef DIRENT *LPDIRENT; -struct DIRENT { - ino_t d_ino; /* Sequence number, do not use. */ - unsigned d_attributes; /* Win32 file attributes. */ - char d_name[NAME_MAX + 1]; /* Name within the directory. */ -}; -#endif - -#ifndef DIR_DEFINED -#define DIR_DEFINED -typedef struct DIR DIR; -typedef DIR *LPDIR; -struct DIR { - intptr_t d_handle; /* Value returned by "_findfirst". */ - DIRENT d_first; /* DIRENT constructed based on "_findfirst". */ - DIRENT d_next; /* DIRENT constructed based on "_findnext". */ -}; -#endif - -/* -** Provide a macro, for use by the implementation, to determine if a -** particular directory entry should be skipped over when searching for -** the next directory entry that should be returned by the readdir() or -** readdir_r() functions. -*/ - -#ifndef is_filtered -# define is_filtered(a) ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM)) -#endif - -/* -** Provide the function prototype for the POSIX compatible getenv() -** function. This function is not thread-safe. -*/ - -extern const char *windirent_getenv(const char *name); - -/* -** Finally, we can provide the function prototypes for the opendir(), -** readdir(), readdir_r(), and closedir() POSIX functions. -*/ - -extern LPDIR opendir(const char *dirname); -extern LPDIRENT readdir(LPDIR dirp); -extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result); -extern INT closedir(LPDIR dirp); - -#endif /* defined(WIN32) && defined(_MSC_VER) */ -/*** End of #include "test_windirent.h" ***/ - - -/* -** Implementation of the POSIX getenv() function using the Win32 API. -** This function is not thread-safe. -*/ -const char *windirent_getenv( - const char *name -){ - static char value[32768]; /* Maximum length, per MSDN */ - DWORD dwSize = sizeof(value) / sizeof(char); /* Size in chars */ - DWORD dwRet; /* Value returned by GetEnvironmentVariableA() */ - - memset(value, 0, sizeof(value)); - dwRet = GetEnvironmentVariableA(name, value, dwSize); - if( dwRet==0 || dwRet>dwSize ){ - /* - ** The function call to GetEnvironmentVariableA() failed -OR- - ** the buffer is not large enough. Either way, return NULL. - */ - return 0; - }else{ - /* - ** The function call to GetEnvironmentVariableA() succeeded - ** -AND- the buffer contains the entire value. - */ - return value; - } -} - -/* -** Implementation of the POSIX opendir() function using the MSVCRT. -*/ -LPDIR opendir( - const char *dirname -){ - struct _finddata_t data; - LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR)); - SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]); - - if( dirp==NULL ) return NULL; - memset(dirp, 0, sizeof(DIR)); - - /* TODO: Remove this if Unix-style root paths are not used. */ - if( sqlite3_stricmp(dirname, "/")==0 ){ - dirname = windirent_getenv("SystemDrive"); - } - - memset(&data, 0, sizeof(struct _finddata_t)); - _snprintf(data.name, namesize, "%s\\*", dirname); - dirp->d_handle = _findfirst(data.name, &data); - - if( dirp->d_handle==BAD_INTPTR_T ){ - closedir(dirp); - return NULL; - } - - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ){ -next: - - memset(&data, 0, sizeof(struct _finddata_t)); - if( _findnext(dirp->d_handle, &data)==-1 ){ - closedir(dirp); - return NULL; - } - - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ) goto next; - } - - dirp->d_first.d_attributes = data.attrib; - strncpy(dirp->d_first.d_name, data.name, NAME_MAX); - dirp->d_first.d_name[NAME_MAX] = '\0'; - - return dirp; -} - -/* -** Implementation of the POSIX readdir() function using the MSVCRT. -*/ -LPDIRENT readdir( - LPDIR dirp -){ - struct _finddata_t data; - - if( dirp==NULL ) return NULL; - - if( dirp->d_first.d_ino==0 ){ - dirp->d_first.d_ino++; - dirp->d_next.d_ino++; - - return &dirp->d_first; - } - -next: - - memset(&data, 0, sizeof(struct _finddata_t)); - if( _findnext(dirp->d_handle, &data)==-1 ) return NULL; - - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ) goto next; - - dirp->d_next.d_ino++; - dirp->d_next.d_attributes = data.attrib; - strncpy(dirp->d_next.d_name, data.name, NAME_MAX); - dirp->d_next.d_name[NAME_MAX] = '\0'; - - return &dirp->d_next; -} - -/* -** Implementation of the POSIX readdir_r() function using the MSVCRT. -*/ -INT readdir_r( - LPDIR dirp, - LPDIRENT entry, - LPDIRENT *result -){ - struct _finddata_t data; - - if( dirp==NULL ) return EBADF; - - if( dirp->d_first.d_ino==0 ){ - dirp->d_first.d_ino++; - dirp->d_next.d_ino++; - - entry->d_ino = dirp->d_first.d_ino; - entry->d_attributes = dirp->d_first.d_attributes; - strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX); - entry->d_name[NAME_MAX] = '\0'; - - *result = entry; - return 0; - } - -next: - - memset(&data, 0, sizeof(struct _finddata_t)); - if( _findnext(dirp->d_handle, &data)==-1 ){ - *result = NULL; - return ENOENT; - } - - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ) goto next; - - entry->d_ino = (ino_t)-1; /* not available */ - entry->d_attributes = data.attrib; - strncpy(entry->d_name, data.name, NAME_MAX); - entry->d_name[NAME_MAX] = '\0'; - - *result = entry; - return 0; -} - -/* -** Implementation of the POSIX closedir() function using the MSVCRT. -*/ -INT closedir( - LPDIR dirp -){ - INT result = 0; - - if( dirp==NULL ) return EINVAL; - - if( dirp->d_handle!=NULL_INTPTR_T && dirp->d_handle!=BAD_INTPTR_T ){ - result = _findclose(dirp->d_handle); - } - - sqlite3_free(dirp); - return result; -} - -#endif /* defined(WIN32) && defined(_MSC_VER) */ -/*** End of #include "test_windirent.c" ***/ - /* #include "fileio.c" */ /*** Begin of #include "fileio.c" ***/ /* @@ -295307,16 +347090,12 @@ INT closedir( ** data: For a regular file, a blob containing the file data. For a ** symlink, a text value containing the text of the link. For a ** directory, NULL. +** level: Directory hierarchy level. Topmost is 1. ** ** If a non-NULL value is specified for the optional $dir parameter and ** $path is a relative path, then $path is interpreted relative to $dir. ** And the paths returned in the "name" column of the table are also ** relative to directory $dir. -** -** Notes on building this extension for Windows: -** Unless linked statically with the SQLite library, a preprocessor -** symbol, FILEIO_WIN32_DLL, must be #define'd to create a stand-alone -** DLL form of this extension for WIN32. See its use below for details. */ /* #include "sqlite3ext.h" */ @@ -295333,21 +347112,183 @@ SQLITE_EXTENSION_INIT1 # include # include # include +# define STRUCT_STAT struct stat +# include +# include #else -# include "windows.h" -# include -# include -/* # include "test_windirent.h" */ +/* # include "windirent.h" */ +/*** Begin of # include "windirent.h" ***/ +/* +** 2025-06-05 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** An implementation of opendir(), readdir(), and closedir() for Windows, +** based on the FindFirstFile(), FindNextFile(), and FindClose() APIs +** of Win32. +** +** #include this file inside any C-code module that needs to use +** opendir()/readdir()/closedir(). This file is a no-op on non-Windows +** machines. On Windows, static functions are defined that implement +** those standard interfaces. +*/ +#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H) +#define SQLITE_WINDIRENT_H -# define dirent DIRENT -# ifndef chmod -# define chmod _chmod -# endif -# ifndef stat -# define stat _stat -# endif -# define mkdir(path,mode) _mkdir(path) -# define lstat(path,buf) stat(path,buf) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef FILENAME_MAX +# define FILENAME_MAX (260) +#endif +#ifndef S_ISREG +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif +#ifndef S_ISDIR +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#ifndef S_ISLNK +#define S_ISLNK(m) (0) +#endif +typedef unsigned short mode_t; + +/* The dirent object for Windows is abbreviated. The only field really +** usable by applications is d_name[]. +*/ +struct dirent { + int d_ino; /* Inode number (synthesized) */ + unsigned d_attributes; /* File attributes */ + char d_name[FILENAME_MAX]; /* Null-terminated filename */ +}; + +/* The internals of DIR are opaque according to standards. So it +** does not matter what we put here. */ +typedef struct DIR DIR; +struct DIR { + intptr_t d_handle; /* Handle for findfirst()/findnext() */ + struct dirent cur; /* Current entry */ +}; + +/* Ignore hidden and system files */ +#define WindowsFileToIgnore(a) \ + ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM)) + +/* +** Close a previously opened directory +*/ +static int closedir(DIR *pDir){ + int rc = 0; + if( pDir==0 ){ + return EINVAL; + } + if( pDir->d_handle!=0 && pDir->d_handle!=(-1) ){ + rc = _findclose(pDir->d_handle); + } + sqlite3_free(pDir); + return rc; +} + +/* +** Open a new directory. The directory name should be UTF-8 encoded. +** appropriate translations happen automatically. +*/ +static DIR *opendir(const char *zDirName){ + DIR *pDir; + wchar_t *b1; + sqlite3_int64 sz; + struct _wfinddata_t data; + + pDir = sqlite3_malloc64( sizeof(DIR) ); + if( pDir==0 ) return 0; + memset(pDir, 0, sizeof(DIR)); + memset(&data, 0, sizeof(data)); + sz = strlen(zDirName); + b1 = sqlite3_malloc64( (sz+3)*sizeof(b1[0]) ); + if( b1==0 ){ + closedir(pDir); + return NULL; + } + sz = MultiByteToWideChar(CP_UTF8, 0, zDirName, sz, b1, sz); + b1[sz++] = '\\'; + b1[sz++] = '*'; + b1[sz] = 0; + if( sz+1>sizeof(data.name)/sizeof(data.name[0]) ){ + closedir(pDir); + sqlite3_free(b1); + return NULL; + } + memcpy(data.name, b1, (sz+1)*sizeof(b1[0])); + sqlite3_free(b1); + pDir->d_handle = _wfindfirst(data.name, &data); + if( pDir->d_handle<0 ){ + closedir(pDir); + return NULL; + } + while( WindowsFileToIgnore(data) ){ + memset(&data, 0, sizeof(data)); + if( _wfindnext(pDir->d_handle, &data)==-1 ){ + closedir(pDir); + return NULL; + } + } + pDir->cur.d_ino = 0; + pDir->cur.d_attributes = data.attrib; + WideCharToMultiByte(CP_UTF8, 0, data.name, -1, + pDir->cur.d_name, FILENAME_MAX, 0, 0); + return pDir; +} + +/* +** Read the next entry from a directory. +** +** The returned struct-dirent object is managed by DIR. It is only +** valid until the next readdir() or closedir() call. Only the +** d_name[] field is meaningful. The d_name[] value has been +** translated into UTF8. +*/ +static struct dirent *readdir(DIR *pDir){ + struct _wfinddata_t data; + if( pDir==0 ) return 0; + if( (pDir->cur.d_ino++)==0 ){ + return &pDir->cur; + } + do{ + memset(&data, 0, sizeof(data)); + if( _wfindnext(pDir->d_handle, &data)==-1 ){ + return NULL; + } + }while( WindowsFileToIgnore(data) ); + pDir->cur.d_attributes = data.attrib; + WideCharToMultiByte(CP_UTF8, 0, data.name, -1, + pDir->cur.d_name, FILENAME_MAX, 0, 0); + return &pDir->cur; +} + +#endif /* defined(_WIN32) && defined(_MSC_VER) */ +/*** End of # include "windirent.h" ***/ + +# include +# define STRUCT_STAT struct _stat +# define chmod(path,mode) fileio_chmod(path,mode) +# define mkdir(path,mode) fileio_mkdir(path) + extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); + extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR); #endif #include #include @@ -295363,14 +347304,44 @@ SQLITE_EXTENSION_INIT1 /* ** Structure of the fsdir() table-valued function */ - /* 0 1 2 3 4 5 */ -#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)" + /* 0 1 2 3 4 5 6 */ +#define FSDIR_SCHEMA "(name,mode,mtime,data,level,path HIDDEN,dir HIDDEN)" + #define FSDIR_COLUMN_NAME 0 /* Name of the file */ #define FSDIR_COLUMN_MODE 1 /* Access mode */ #define FSDIR_COLUMN_MTIME 2 /* Last modification time */ #define FSDIR_COLUMN_DATA 3 /* File content */ -#define FSDIR_COLUMN_PATH 4 /* Path to top of search */ -#define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */ +#define FSDIR_COLUMN_LEVEL 4 /* Level. Topmost is 1 */ +#define FSDIR_COLUMN_PATH 5 /* Path to top of search */ +#define FSDIR_COLUMN_DIR 6 /* Path is relative to this directory */ + +/* +** UTF8 chmod() function for Windows +*/ +#if defined(_WIN32) || defined(WIN32) +static int fileio_chmod(const char *zPath, int pmode){ + int rc; + wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath); + if( b1==0 ) return -1; + rc = _wchmod(b1, pmode); + sqlite3_free(b1); + return rc; +} +#endif + +/* +** UTF8 mkdir() function for Windows +*/ +#if defined(_WIN32) || defined(WIN32) +static int fileio_mkdir(const char *zPath){ + int rc; + wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath); + if( b1==0 ) return -1; + rc = _wmkdir(b1); + sqlite3_free(b1); + return rc; +} +#endif /* @@ -295478,63 +347449,35 @@ static sqlite3_uint64 fileTimeToUnixTime( return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000; } - - -#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32)) -# /* To allow a standalone DLL, use this next replacement function: */ -# undef sqlite3_win32_utf8_to_unicode -# define sqlite3_win32_utf8_to_unicode utf8_to_utf16 -# -LPWSTR utf8_to_utf16(const char *z){ - int nAllot = MultiByteToWideChar(CP_UTF8, 0, z, -1, NULL, 0); - LPWSTR rv = sqlite3_malloc(nAllot * sizeof(WCHAR)); - if( rv!=0 && 0 < MultiByteToWideChar(CP_UTF8, 0, z, -1, rv, nAllot) ) - return rv; - sqlite3_free(rv); - return 0; -} -#endif +#endif /* _WIN32 */ /* -** This function attempts to normalize the time values found in the stat() -** buffer to UTC. This is necessary on Win32, where the runtime library -** appears to return these values as local times. +** This function is used in place of stat(). On Windows, special handling +** is required in order for the included time to be returned as UTC. On all +** other systems, this function simply calls stat(). */ -static void statTimesToUtc( +static int fileStat( const char *zPath, - struct stat *pStatBuf -){ - HANDLE hFindFile; - WIN32_FIND_DATAW fd; - LPWSTR zUnicodeName; - extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); - zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath); - if( zUnicodeName ){ + STRUCT_STAT *pStatBuf +){ +#if defined(_WIN32) + int rc; + wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath); + if( b1==0 ) return 1; + rc = _wstat(b1, pStatBuf); + if( rc==0 ){ + HANDLE hFindFile; + WIN32_FIND_DATAW fd; memset(&fd, 0, sizeof(WIN32_FIND_DATAW)); - hFindFile = FindFirstFileW(zUnicodeName, &fd); + hFindFile = FindFirstFileW(b1, &fd); if( hFindFile!=NULL ){ pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime); pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime); pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime); FindClose(hFindFile); } - sqlite3_free(zUnicodeName); } -} -#endif - -/* -** This function is used in place of stat(). On Windows, special handling -** is required in order for the included time to be returned as UTC. On all -** other systems, this function simply calls stat(). -*/ -static int fileStat( - const char *zPath, - struct stat *pStatBuf -){ -#if defined(_WIN32) - int rc = stat(zPath, pStatBuf); - if( rc==0 ) statTimesToUtc(zPath, pStatBuf); + sqlite3_free(b1); return rc; #else return stat(zPath, pStatBuf); @@ -295548,12 +347491,10 @@ static int fileStat( */ static int fileLinkStat( const char *zPath, - struct stat *pStatBuf + STRUCT_STAT *pStatBuf ){ #if defined(_WIN32) - int rc = lstat(zPath, pStatBuf); - if( rc==0 ) statTimesToUtc(zPath, pStatBuf); - return rc; + return fileStat(zPath, pStatBuf); #else return lstat(zPath, pStatBuf); #endif @@ -295583,7 +347524,7 @@ static int makeDirectory( int i = 1; while( rc==SQLITE_OK ){ - struct stat sStat; + STRUCT_STAT sStat; int rc2; for(; zCopy[i]!='/' && i=0 ){ #if defined(_WIN32) -#if !SQLITE_OS_WINRT /* Windows */ FILETIME lastAccess; FILETIME lastWrite; @@ -295679,7 +347619,7 @@ static int writeFile( GetSystemTime(¤tTime); SystemTimeToFileTime(¤tTime, &lastAccess); - intervals = Int32x32To64(mtime, 10000000) + 116444736000000000; + intervals = (mtime*10000000) + 116444736000000000; lastWrite.dwLowDateTime = (DWORD)intervals; lastWrite.dwHighDateTime = intervals >> 32; zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile); @@ -295698,7 +347638,6 @@ static int writeFile( }else{ return 1; } -#endif #elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */ /* Recent unix */ struct timespec times[2]; @@ -295829,13 +347768,14 @@ struct fsdir_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ int nLvl; /* Number of entries in aLvl[] array */ + int mxLvl; /* Maximum level */ int iLvl; /* Index of current entry */ FsdirLevel *aLvl; /* Hierarchy of directories being traversed */ const char *zBase; int nBase; - struct stat sStat; /* Current lstat() results */ + STRUCT_STAT sStat; /* Current lstat() results */ char *zPath; /* Path to current entry */ sqlite3_int64 iRowid; /* Current rowid */ }; @@ -295863,7 +347803,7 @@ static int fsdirConnect( (void)pzErr; rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA); if( rc==SQLITE_OK ){ - pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) ); + pNew = (fsdir_tab*)sqlite3_malloc64( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); @@ -295886,7 +347826,7 @@ static int fsdirDisconnect(sqlite3_vtab *pVtab){ static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ fsdir_cursor *pCur; (void)p; - pCur = sqlite3_malloc( sizeof(*pCur) ); + pCur = sqlite3_malloc64( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); pCur->iLvl = -1; @@ -295947,7 +347887,7 @@ static int fsdirNext(sqlite3_vtab_cursor *cur){ mode_t m = pCur->sStat.st_mode; pCur->iRowid++; - if( S_ISDIR(m) ){ + if( S_ISDIR(m) && pCur->iLvl+3mxLvl ){ /* Descend into this directory */ int iNew = pCur->iLvl + 1; FsdirLevel *pLvl; @@ -295967,7 +347907,7 @@ static int fsdirNext(sqlite3_vtab_cursor *cur){ pCur->zPath = 0; pLvl->pDir = opendir(pLvl->zDir); if( pLvl->pDir==0 ){ - fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath); + fsdirSetErrmsg(pCur, "cannot read directory: %s", pLvl->zDir); return SQLITE_ERROR; } } @@ -296049,13 +347989,21 @@ static int fsdirColumn( } } - sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT); + if( n>0 ){ + sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT); + }else{ + sqlite3_result_null(ctx); + } if( aBuf!=aStatic ) sqlite3_free(aBuf); #endif }else{ readFileContents(ctx, pCur->zPath); } + break; } + case FSDIR_COLUMN_LEVEL: + sqlite3_result_int(ctx, pCur->iLvl+2); + break; case FSDIR_COLUMN_PATH: default: { /* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters. @@ -296089,8 +348037,11 @@ static int fsdirEof(sqlite3_vtab_cursor *cur){ /* ** xFilter callback. ** -** idxNum==1 PATH parameter only -** idxNum==2 Both PATH and DIR supplied +** idxNum bit Meaning +** 0x01 PATH=N +** 0x02 DIR=N +** 0x04 LEVEL0 ); zDir = (const char*)sqlite3_value_text(argv[0]); if( zDir==0 ){ fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument"); return SQLITE_ERROR; } - if( argc==2 ){ - pCur->zBase = (const char*)sqlite3_value_text(argv[1]); + i = 1; + if( (idxNum & 0x02)!=0 ){ + assert( argc>i ); + pCur->zBase = (const char*)sqlite3_value_text(argv[i++]); + } + if( (idxNum & 0x0c)!=0 ){ + assert( argc>i ); + pCur->mxLvl = sqlite3_value_int(argv[i++]); + if( idxNum & 0x08 ) pCur->mxLvl++; + if( pCur->mxLvl<=0 ) pCur->mxLvl = 1000000000; + }else{ + pCur->mxLvl = 1000000000; } if( pCur->zBase ){ pCur->nBase = (int)strlen(pCur->zBase)+1; @@ -296143,10 +348105,11 @@ static int fsdirFilter( ** In this implementation idxNum is used to represent the ** query plan. idxStr is unused. ** -** The query plan is represented by values of idxNum: +** The query plan is represented by bits in idxNum: ** -** (1) The path value is supplied by argv[0] -** (2) Path is in argv[0] and dir is in argv[1] +** 0x01 The path value is supplied by argv[0] +** 0x02 dir is in argv[1] +** 0x04 maxdepth is in argv[1] or [2] */ static int fsdirBestIndex( sqlite3_vtab *tab, @@ -296155,6 +348118,9 @@ static int fsdirBestIndex( int i; /* Loop over constraints */ int idxPath = -1; /* Index in pIdxInfo->aConstraint of PATH= */ int idxDir = -1; /* Index in pIdxInfo->aConstraint of DIR= */ + int idxLevel = -1; /* Index in pIdxInfo->aConstraint of LEVEL< or <= */ + int idxLevelEQ = 0; /* 0x08 for LEVEL<= or LEVEL=. 0x04 for LEVEL< */ + int omitLevel = 0; /* omit the LEVEL constraint */ int seenPath = 0; /* True if an unusable PATH= constraint is seen */ int seenDir = 0; /* True if an unusable DIR= constraint is seen */ const struct sqlite3_index_constraint *pConstraint; @@ -296162,25 +348128,48 @@ static int fsdirBestIndex( (void)tab; pConstraint = pIdxInfo->aConstraint; for(i=0; inConstraint; i++, pConstraint++){ - if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - switch( pConstraint->iColumn ){ - case FSDIR_COLUMN_PATH: { - if( pConstraint->usable ){ - idxPath = i; - seenPath = 0; - }else if( idxPath<0 ){ - seenPath = 1; + if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + switch( pConstraint->iColumn ){ + case FSDIR_COLUMN_PATH: { + if( pConstraint->usable ){ + idxPath = i; + seenPath = 0; + }else if( idxPath<0 ){ + seenPath = 1; + } + break; } - break; - } - case FSDIR_COLUMN_DIR: { - if( pConstraint->usable ){ - idxDir = i; - seenDir = 0; - }else if( idxDir<0 ){ - seenDir = 1; + case FSDIR_COLUMN_DIR: { + if( pConstraint->usable ){ + idxDir = i; + seenDir = 0; + }else if( idxDir<0 ){ + seenDir = 1; + } + break; + } + case FSDIR_COLUMN_LEVEL: { + if( pConstraint->usable && idxLevel<0 ){ + idxLevel = i; + idxLevelEQ = 0x08; + omitLevel = 0; + } + break; } - break; + } + }else + if( pConstraint->iColumn==FSDIR_COLUMN_LEVEL + && pConstraint->usable + && idxLevel<0 + ){ + if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE ){ + idxLevel = i; + idxLevelEQ = 0x08; + omitLevel = 1; + }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ){ + idxLevel = i; + idxLevelEQ = 0x04; + omitLevel = 1; } } } @@ -296197,14 +348186,20 @@ static int fsdirBestIndex( }else{ pIdxInfo->aConstraintUsage[idxPath].omit = 1; pIdxInfo->aConstraintUsage[idxPath].argvIndex = 1; + pIdxInfo->idxNum = 0x01; + pIdxInfo->estimatedCost = 1.0e9; + i = 2; if( idxDir>=0 ){ pIdxInfo->aConstraintUsage[idxDir].omit = 1; - pIdxInfo->aConstraintUsage[idxDir].argvIndex = 2; - pIdxInfo->idxNum = 2; - pIdxInfo->estimatedCost = 10.0; - }else{ - pIdxInfo->idxNum = 1; - pIdxInfo->estimatedCost = 100.0; + pIdxInfo->aConstraintUsage[idxDir].argvIndex = i++; + pIdxInfo->idxNum |= 0x02; + pIdxInfo->estimatedCost /= 1.0e4; + } + if( idxLevel>=0 ){ + pIdxInfo->aConstraintUsage[idxLevel].omit = omitLevel; + pIdxInfo->aConstraintUsage[idxLevel].argvIndex = i++; + pIdxInfo->idxNum |= idxLevelEQ; + pIdxInfo->estimatedCost /= 1.0e4; } } @@ -296250,9 +348245,158 @@ static int fsdirRegister(sqlite3 *db){ # define fsdirRegister(x) SQLITE_OK #endif +/* +** This version of realpath() works on any system. The string +** returned is held in memory allocated using sqlite3_malloc64(). +** The caller is responsible for calling sqlite3_free(). +*/ +static char *portable_realpath(const char *zPath){ +#if !defined(_WIN32) /* BEGIN unix */ + + char *zOut = 0; /* Result */ + char *z; /* Temporary buffer */ +#if defined(PATH_MAX) + char zBuf[PATH_MAX+1]; /* Space for the temporary buffer */ +#endif + + if( zPath==0 ) return 0; +#if defined(PATH_MAX) + z = realpath(zPath, zBuf); + if( z ){ + zOut = sqlite3_mprintf("%s", zBuf); + } +#endif /* defined(PATH_MAX) */ + if( zOut==0 ){ + /* Try POSIX.1-2008 malloc behavior */ + z = realpath(zPath, NULL); + if( z ){ + zOut = sqlite3_mprintf("%s", z); + free(z); + } + } + return zOut; + +#else /* End UNIX, Begin WINDOWS */ + + wchar_t *zPath16; /* UTF16 translation of zPath */ + char *zOut = 0; /* Result */ + wchar_t *z = 0; /* Temporary buffer */ + + if( zPath==0 ) return 0; + + zPath16 = sqlite3_win32_utf8_to_unicode(zPath); + if( zPath16==0 ) return 0; + z = _wfullpath(NULL, zPath16, 0); + sqlite3_free(zPath16); + if( z ){ + zOut = sqlite3_win32_unicode_to_utf8(z); + free(z); + } + return zOut; + +#endif /* End WINDOWS, Begin common code */ +} + +/* +** SQL function: realpath(X) +** +** Try to convert file or pathname X into its real, absolute pathname. +** Return NULL if unable. +** +** The file or directory X is not required to exist. The answer is formed +** by calling system realpath() on the prefix of X that does exist and +** appending the tail of X that does not (yet) exist. +*/ +static void realpathFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zPath; /* Original input path */ + char *zCopy; /* An editable copy of zPath */ + char *zOut; /* The result */ + char cSep = 0; /* Separator turned into \000 */ + size_t len; /* Prefix length before cSep */ #ifdef _WIN32 -__declspec(dllexport) + const int isWin = 1; +#else + const int isWin = 0; +#endif + + (void)argc; + zPath = (const char*)sqlite3_value_text(argv[0]); + if( zPath==0 ) return; + if( zPath[0]==0 ) zPath = "."; + zCopy = sqlite3_mprintf("%s",zPath); + len = strlen(zCopy); + while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){ + len--; + } + zCopy[len] = 0; + while( 1 /*exit-by-break*/ ){ + zOut = portable_realpath(zCopy); + zCopy[len] = cSep; + if( zOut ){ + if( cSep ){ + zOut = sqlite3_mprintf("%z%s",zOut,&zCopy[len]); + } + break; + }else{ + size_t i = len-1; + while( i>0 ){ + if( zCopy[i]=='/' || (isWin && zCopy[i]=='\\') ) break; + i--; + } + if( i<=0 ){ + if( zCopy[0]=='/' ){ + zOut = zCopy; + zCopy = 0; + }else if( (zOut = portable_realpath("."))!=0 ){ + zOut = sqlite3_mprintf("%z/%s", zOut, zCopy); + } + break; + } + cSep = zCopy[i]; + zCopy[i] = 0; + len = i; + } + } + sqlite3_free(zCopy); + if( zOut ){ + /* Simplify any "/./" or "/../" that might have snuck into the + ** pathname due to appending of zCopy. We only have to consider + ** unix "/" separators, because the _wfilepath() system call on + ** Windows will have already done this simplification for us. */ + size_t i, j, n; + n = strlen(zOut); + for(i=j=0; i0 && zOut[j-1]!='/' ){ j--; } + if( j>0 ){ j--; } + i += 2; + continue; + } + } + zOut[j++] = zOut[i]; + } + zOut[j] = 0; + + /* Return the result */ + sqlite3_result_text(context, zOut, -1, sqlite3_free); + } +} + + +#ifndef SQLITE_API +#define SQLITE_API #endif +SQLITE_API int sqlite3_fileio_init( sqlite3 *db, char **pzErrMsg, @@ -296276,17 +348420,13 @@ int sqlite3_fileio_init( if( rc==SQLITE_OK ){ rc = fsdirRegister(db); } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "realpath", 1, + SQLITE_UTF8, 0, + realpathFunc, 0, 0); + } return rc; } - -#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32)) -/* To allow a standalone DLL, make test_windirent.c use the same - * redefined SQLite API calls as the above extension code does. - * Just pull in this .c to accomplish this. As a beneficial side - * effect, this extension becomes a single translation unit. */ -/* # include "test_windirent.c" */ - -#endif /*** End of #include "fileio.c" ***/ #endif @@ -296296,9 +348436,7 @@ int sqlite3_fileio_init( */ #ifdef SQLITE_ENABLE_SERIES /* Prototype for initialization function of SERIES extension */ -#ifdef _WIN32 -__declspec(dllexport) -#endif +SQLITE_API int sqlite3_series_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* pApi); /* #include "series.c" */ /*** Begin of #include "series.c" ***/ @@ -296334,19 +348472,20 @@ int sqlite3_series_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines ** SELECT * FROM generate_series(0,100,5); ** ** The query above returns integers from 0 through 100 counting by steps -** of 5. +** of 5. In other words, 0, 5, 10, 15, ..., 90, 95, 100. There are a total +** of 21 rows. ** ** SELECT * FROM generate_series(0,100); ** -** Integers from 0 through 100 with a step size of 1. +** Integers from 0 through 100 with a step size of 1. 101 rows. ** ** SELECT * FROM generate_series(20) LIMIT 10; ** -** Integers 20 through 29. +** Integers 20 through 29. 10 rows. ** ** SELECT * FROM generate_series(0,-100,-5); ** -** Integers 0 -5 -10 ... -100. +** Integers 0 -5 -10 ... -100. 21 rows. ** ** SELECT * FROM generate_series(0,-1); ** @@ -296364,8 +348503,7 @@ int sqlite3_series_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines ** step HIDDEN ** ); ** -** The virtual table also has a rowid, logically equivalent to n+1 where -** "n" is the ascending integer in the aforesaid production definition. +** The virtual table also has a rowid which is an alias for the value. ** ** Function arguments in queries against this virtual table are translated ** into equality constraints against successive hidden columns. In other @@ -296421,142 +348559,92 @@ SQLITE_EXTENSION_INIT1 #include #include #include +#include #ifndef SQLITE_OMIT_VIRTUALTABLE -/* -** Return that member of a generate_series(...) sequence whose 0-based -** index is ix. The 0th member is given by smBase. The sequence members -** progress per ix increment by smStep. -*/ -static sqlite3_int64 genSeqMember( - sqlite3_int64 smBase, - sqlite3_int64 smStep, - sqlite3_uint64 ix -){ - static const sqlite3_uint64 mxI64 = - ((sqlite3_uint64)0x7fffffff)<<32 | 0xffffffff; - if( ix>=mxI64 ){ - /* Get ix into signed i64 range. */ - ix -= mxI64; - /* With 2's complement ALU, this next can be 1 step, but is split into - * 2 for UBSAN's satisfaction (and hypothetical 1's complement ALUs.) */ - smBase += (mxI64/2) * smStep; - smBase += (mxI64 - mxI64/2) * smStep; - } - /* Under UBSAN (or on 1's complement machines), must do this last term - * in steps to avoid the dreaded (and harmless) signed multiply overlow. */ - if( ix>=2 ){ - sqlite3_int64 ix2 = (sqlite3_int64)ix/2; - smBase += ix2*smStep; - ix -= ix2; - } - return smBase + ((sqlite3_int64)ix)*smStep; -} - -typedef unsigned char u8; - -typedef struct SequenceSpec { - sqlite3_int64 iOBase; /* Original starting value ("start") */ - sqlite3_int64 iOTerm; /* Original terminal value ("stop") */ - sqlite3_int64 iBase; /* Starting value to actually use */ - sqlite3_int64 iTerm; /* Terminal value to actually use */ - sqlite3_int64 iStep; /* Increment ("step") */ - sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */ - sqlite3_uint64 uSeqIndexNow; /* Current index during generation */ - sqlite3_int64 iValueNow; /* Current value during generation */ - u8 isNotEOF; /* Sequence generation not exhausted */ - u8 isReversing; /* Sequence is being reverse generated */ -} SequenceSpec; - -/* -** Prepare a SequenceSpec for use in generating an integer series -** given initialized iBase, iTerm and iStep values. Sequence is -** initialized per given isReversing. Other members are computed. -*/ -static void setupSequence( SequenceSpec *pss ){ - int bSameSigns; - pss->uSeqIndexMax = 0; - pss->isNotEOF = 0; - bSameSigns = (pss->iBase < 0)==(pss->iTerm < 0); - if( pss->iTerm < pss->iBase ){ - sqlite3_uint64 nuspan = 0; - if( bSameSigns ){ - nuspan = (sqlite3_uint64)(pss->iBase - pss->iTerm); - }else{ - /* Under UBSAN (or on 1's complement machines), must do this in steps. - * In this clause, iBase>=0 and iTerm<0 . */ - nuspan = 1; - nuspan += pss->iBase; - nuspan += -(pss->iTerm+1); - } - if( pss->iStep<0 ){ - pss->isNotEOF = 1; - if( nuspan==ULONG_MAX ){ - pss->uSeqIndexMax = ( pss->iStep>LLONG_MIN )? nuspan/-pss->iStep : 1; - }else if( pss->iStep>LLONG_MIN ){ - pss->uSeqIndexMax = nuspan/-pss->iStep; - } - } - }else if( pss->iTerm > pss->iBase ){ - sqlite3_uint64 puspan = 0; - if( bSameSigns ){ - puspan = (sqlite3_uint64)(pss->iTerm - pss->iBase); - }else{ - /* Under UBSAN (or on 1's complement machines), must do this in steps. - * In this clause, iTerm>=0 and iBase<0 . */ - puspan = 1; - puspan += pss->iTerm; - puspan += -(pss->iBase+1); - } - if( pss->iStep>0 ){ - pss->isNotEOF = 1; - pss->uSeqIndexMax = puspan/pss->iStep; - } - }else if( pss->iTerm == pss->iBase ){ - pss->isNotEOF = 1; - pss->uSeqIndexMax = 0; - } - pss->uSeqIndexNow = (pss->isReversing)? pss->uSeqIndexMax : 0; - pss->iValueNow = (pss->isReversing) - ? genSeqMember(pss->iBase, pss->iStep, pss->uSeqIndexMax) - : pss->iBase; -} - -/* -** Progress sequence generator to yield next value, if any. -** Leave its state to either yield next value or be at EOF. -** Return whether there is a next value, or 0 at EOF. -*/ -static int progressSequence( SequenceSpec *pss ){ - if( !pss->isNotEOF ) return 0; - if( pss->isReversing ){ - if( pss->uSeqIndexNow > 0 ){ - pss->uSeqIndexNow--; - pss->iValueNow -= pss->iStep; - }else{ - pss->isNotEOF = 0; - } - }else{ - if( pss->uSeqIndexNow < pss->uSeqIndexMax ){ - pss->uSeqIndexNow++; - pss->iValueNow += pss->iStep; - }else{ - pss->isNotEOF = 0; - } - } - return pss->isNotEOF; -} /* series_cursor is a subclass of sqlite3_vtab_cursor which will ** serve as the underlying representation of a cursor that scans -** over rows of the result +** over rows of the result. +** +** iOBase, iOTerm, and iOStep are the original values of the +** start=, stop=, and step= constraints on the query. These are +** the values reported by the start, stop, and step columns of the +** virtual table. +** +** iBase, iTerm, iStep, and bDescp are the actual values used to generate +** the sequence. These might be different from the iOxxxx values. +** For example in +** +** SELECT value FROM generate_series(1,11,2) +** WHERE value BETWEEN 4 AND 8; +** +** The iOBase is 1, but the iBase is 5. iOTerm is 11 but iTerm is 7. +** Another example: +** +** SELECT value FROM generate_series(1,15,3) ORDER BY value DESC; +** +** The cursor initialization for the above query is: +** +** iOBase = 1 iBase = 13 +** iOTerm = 15 iTerm = 1 +** iOStep = 3 iStep = 3 bDesc = 1 +** +** The actual step size is unsigned so that can have a value of +** +9223372036854775808 which is needed for querys like this: +** +** SELECT value +** FROM generate_series(9223372036854775807, +** -9223372036854775808, +** -9223372036854775808) +** ORDER BY value ASC; +** +** The setup for the previous query will be: +** +** iOBase = 9223372036854775807 iBase = -1 +** iOTerm = -9223372036854775808 iTerm = 9223372036854775807 +** iOStep = -9223372036854775808 iStep = 9223372036854775808 bDesc = 0 */ +typedef unsigned char u8; typedef struct series_cursor series_cursor; struct series_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ - SequenceSpec ss; /* (this) Derived class data */ + sqlite3_int64 iOBase; /* Original starting value ("start") */ + sqlite3_int64 iOTerm; /* Original terminal value ("stop") */ + sqlite3_int64 iOStep; /* Original step value */ + sqlite3_int64 iBase; /* Starting value to actually use */ + sqlite3_int64 iTerm; /* Terminal value to actually use */ + sqlite3_uint64 iStep; /* The step size */ + sqlite3_int64 iValue; /* Current value */ + u8 bDesc; /* iStep is really negative */ + u8 bDone; /* True if stepped past last element */ }; +/* +** Computed the difference between two 64-bit signed integers using a +** convoluted computation designed to work around the silly restriction +** against signed integer overflow in C. +*/ +static sqlite3_uint64 span64(sqlite3_int64 a, sqlite3_int64 b){ + assert( a>=b ); + return (*(sqlite3_uint64*)&a) - (*(sqlite3_uint64*)&b); +} + +/* +** Add or substract an unsigned 64-bit integer from a signed 64-bit integer +** and return the new signed 64-bit integer. +*/ +static sqlite3_int64 add64(sqlite3_int64 a, sqlite3_uint64 b){ + sqlite3_uint64 x = *(sqlite3_uint64*)&a; + x += b; + return *(sqlite3_int64*)&x; +} +static sqlite3_int64 sub64(sqlite3_int64 a, sqlite3_uint64 b){ + sqlite3_uint64 x = *(sqlite3_uint64*)&a; + x -= b; + return *(sqlite3_int64*)&x; +} + /* ** The seriesConnect() method is invoked to create a new ** series_vtab that describes the generate_series virtual table. @@ -296581,6 +348669,7 @@ static int seriesConnect( int rc; /* Column numbers */ +#define SERIES_COLUMN_ROWID (-1) #define SERIES_COLUMN_VALUE 0 #define SERIES_COLUMN_START 1 #define SERIES_COLUMN_STOP 2 @@ -296593,7 +348682,7 @@ static int seriesConnect( rc = sqlite3_declare_vtab(db, "CREATE TABLE x(value,start hidden,stop hidden,step hidden)"); if( rc==SQLITE_OK ){ - pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); + pNew = *ppVtab = sqlite3_malloc64( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); @@ -296615,7 +348704,7 @@ static int seriesDisconnect(sqlite3_vtab *pVtab){ static int seriesOpen(sqlite3_vtab *pUnused, sqlite3_vtab_cursor **ppCursor){ series_cursor *pCur; (void)pUnused; - pCur = sqlite3_malloc( sizeof(*pCur) ); + pCur = sqlite3_malloc64( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; @@ -296636,7 +348725,15 @@ static int seriesClose(sqlite3_vtab_cursor *cur){ */ static int seriesNext(sqlite3_vtab_cursor *cur){ series_cursor *pCur = (series_cursor*)cur; - progressSequence( & pCur->ss ); + if( pCur->iValue==pCur->iTerm ){ + pCur->bDone = 1; + }else if( pCur->bDesc ){ + pCur->iValue = sub64(pCur->iValue, pCur->iStep); + assert( pCur->iValue>=pCur->iTerm ); + }else{ + pCur->iValue = add64(pCur->iValue, pCur->iStep); + assert( pCur->iValue<=pCur->iTerm ); + } return SQLITE_OK; } @@ -296652,29 +348749,27 @@ static int seriesColumn( series_cursor *pCur = (series_cursor*)cur; sqlite3_int64 x = 0; switch( i ){ - case SERIES_COLUMN_START: x = pCur->ss.iOBase; break; - case SERIES_COLUMN_STOP: x = pCur->ss.iOTerm; break; - case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break; - default: x = pCur->ss.iValueNow; break; + case SERIES_COLUMN_START: x = pCur->iOBase; break; + case SERIES_COLUMN_STOP: x = pCur->iOTerm; break; + case SERIES_COLUMN_STEP: x = pCur->iOStep; break; + default: x = pCur->iValue; break; } sqlite3_result_int64(ctx, x); return SQLITE_OK; } #ifndef LARGEST_UINT64 -#define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) -#define LARGEST_UINT64 (0xffffffff|(((sqlite3_uint64)0xffffffff)<<32)) -#define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64) +#define LARGEST_INT64 ((sqlite3_int64)0x7fffffffffffffffLL) +#define LARGEST_UINT64 ((sqlite3_uint64)0xffffffffffffffffULL) +#define SMALLEST_INT64 ((sqlite3_int64)0x8000000000000000LL) #endif /* -** Return the rowid for the current row, logically equivalent to n+1 where -** "n" is the ascending integer in the aforesaid production definition. +** The rowid is the same as the value. */ static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ series_cursor *pCur = (series_cursor*)cur; - sqlite3_uint64 n = pCur->ss.uSeqIndexNow; - *pRowid = (sqlite3_int64)((niValue; return SQLITE_OK; } @@ -296684,7 +348779,7 @@ static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ */ static int seriesEof(sqlite3_vtab_cursor *cur){ series_cursor *pCur = (series_cursor*)cur; - return !pCur->ss.isNotEOF; + return pCur->bDone; } /* True to cause run-time checking of the start=, stop=, and/or step= @@ -296695,6 +348790,69 @@ static int seriesEof(sqlite3_vtab_cursor *cur){ # define SQLITE_SERIES_CONSTRAINT_VERIFY 0 #endif +/* +** Return the number of steps between pCur->iBase and pCur->iTerm if +** the step width is pCur->iStep. +*/ +static sqlite3_uint64 seriesSteps(series_cursor *pCur){ + if( pCur->bDesc ){ + assert( pCur->iBase >= pCur->iTerm ); + return span64(pCur->iBase, pCur->iTerm)/pCur->iStep; + }else{ + assert( pCur->iBase <= pCur->iTerm ); + return span64(pCur->iTerm, pCur->iBase)/pCur->iStep; + } +} + +#if defined(SQLITE_ENABLE_MATH_FUNCTIONS) || defined(_WIN32) +/* +** Case 1 (the most common case): +** The standard math library is available so use ceil() and floor() from there. +*/ +static double seriesCeil(double r){ return ceil(r); } +static double seriesFloor(double r){ return floor(r); } +#elif defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) +/* +** Case 2 (2nd most common): Use GCC/Clang builtins +*/ +static double seriesCeil(double r){ return __builtin_ceil(r); } +static double seriesFloor(double r){ return __builtin_floor(r); } +#else +/* +** Case 3 (rarely happens): Use home-grown ceil() and floor() routines. +*/ +static double seriesCeil(double r){ + sqlite3_int64 x; + if( r!=r ) return r; + if( r<=(-4503599627370496.0) ) return r; + if( r>=(+4503599627370496.0) ) return r; + x = (sqlite3_int64)r; + if( r==(double)x ) return r; + if( r>(double)x ) x++; + return (double)x; +} +static double seriesFloor(double r){ + sqlite3_int64 x; + if( r!=r ) return r; + if( r<=(-4503599627370496.0) ) return r; + if( r>=(+4503599627370496.0) ) return r; + x = (sqlite3_int64)r; + if( r==(double)x ) return r; + if( r<(double)x ) x--; + return (double)x; +} +#endif + +/* Convert a floating point value to its closest integer. Do so in +** a way that avoids 'outside the range of representable values' warnings +** from UBSAN. +*/ +static sqlite3_int64 seriesRealToI64(double r){ + if( r<-9223372036854774784.0 ) return SMALLEST_INT64; + if( r>+9223372036854774784.0 ) return LARGEST_INT64; + return (sqlite3_int64)r; +} + /* ** This method is called to "rewind" the series_cursor object back ** to the first row of output. This method is always called at least @@ -296728,33 +348886,42 @@ static int seriesFilter( int argc, sqlite3_value **argv ){ series_cursor *pCur = (series_cursor *)pVtabCursor; - int i = 0; - int returnNoRows = 0; - sqlite3_int64 iMin = SMALLEST_INT64; - sqlite3_int64 iMax = LARGEST_INT64; - sqlite3_int64 iLimit = 0; - sqlite3_int64 iOffset = 0; + int iArg = 0; /* Arguments used so far */ + int i; /* Loop counter */ + sqlite3_int64 iMin = SMALLEST_INT64; /* Smallest allowed output value */ + sqlite3_int64 iMax = LARGEST_INT64; /* Largest allowed output value */ + sqlite3_int64 iLimit = 0; /* if >0, the value of the LIMIT */ + sqlite3_int64 iOffset = 0; /* if >0, the value of the OFFSET */ (void)idxStrUnused; + + /* If any constraints have a NULL value, then return no rows. + ** See ticket https://sqlite.org/src/info/fac496b61722daf2 + */ + for(i=0; i
      ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -961,7 +978,7 @@ struct sqlite3_io_methods { ** connection. See also [SQLITE_FCNTL_FILE_POINTER]. ** **
    • [[SQLITE_FCNTL_SYNC_OMITTED]] -** No longer in use. +** The SQLITE_FCNTL_SYNC_OMITTED file-control is no longer used. ** **
    • [[SQLITE_FCNTL_SYNC]] ** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and @@ -1036,7 +1053,7 @@ struct sqlite3_io_methods { ** **
    • [[SQLITE_FCNTL_VFSNAME]] ** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of -** all [VFSes] in the VFS stack. The names are of all VFS shims and the +** all [VFSes] in the VFS stack. The names of all VFS shims and the ** final bottom-level VFS are written into memory obtained from ** [sqlite3_malloc()] and the result is stored in the char* variable ** that the fourth parameter of [sqlite3_file_control()] points to. @@ -1050,7 +1067,7 @@ struct sqlite3_io_methods { ** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level ** [VFSes] currently in use. ^(The argument X in ** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be -** of type "[sqlite3_vfs] **". This opcodes will set *X +** of type "[sqlite3_vfs] **". This opcode will set *X ** to a pointer to the top-level VFS.)^ ** ^When there are multiple VFS shims in the stack, this opcode finds the ** upper-most shim only. @@ -1137,6 +1154,11 @@ struct sqlite3_io_methods { ** pointed to by the pArg argument. This capability is used during testing ** and only needs to be supported when SQLITE_TEST is defined. ** +**
    • [[SQLITE_FCNTL_NULL_IO]] +** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor +** or file handle for the [sqlite3_file] object such that it will no longer +** read or write to the database file. +** **
    • [[SQLITE_FCNTL_WAL_BLOCK]] ** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might ** be advantageous to block on the next WAL lock if the lock is not immediately @@ -1195,6 +1217,12 @@ struct sqlite3_io_methods { ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** +**
    • [[SQLITE_FCNTL_BLOCK_ON_CONNECT]] +** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the +** VFS to block when taking a SHARED lock to connect to a wal mode database. +** This is used to implement the functionality associated with +** SQLITE_SETLK_BLOCK_ON_CONNECT. +** **
    • [[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. @@ -1229,7 +1257,7 @@ struct sqlite3_io_methods { **
    • [[SQLITE_FCNTL_EXTERNAL_READER]] ** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect ** whether or not there is a database client in another process with a wal-mode -** transaction open on the database or not. It is only available on unix.The +** transaction open on the database or not. It is only available on unix. The ** (void*) argument passed with this file-control should be a pointer to a ** value of type (int). The integer value is set to 1 if the database is a wal ** mode database and there exists at least one client in another process that @@ -1247,6 +1275,15 @@ struct sqlite3_io_methods { ** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control ** purges the contents of the in-memory page cache. If there is an open ** transaction, or if the db is a temp-db, this opcode is a no-op, not an error. +** +**
    • [[SQLITE_FCNTL_FILESTAT]] +** The [SQLITE_FCNTL_FILESTAT] opcode returns low-level diagnostic information +** about the [sqlite3_file] objects used access the database and journal files +** for the given schema. The fourth parameter to [sqlite3_file_control()] +** should be an initialized [sqlite3_str] pointer. JSON text describing +** various aspects of the sqlite3_file object is appended to the sqlite3_str. +** The SQLITE_FCNTL_FILESTAT opcode is usually a no-op, unless compile-time +** options are used to enable it. **
    */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1290,12 +1327,21 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 +#define SQLITE_FCNTL_NULL_IO 43 +#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44 +#define SQLITE_FCNTL_FILESTAT 45 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO +/* reserved file-control numbers: +** 101 +** 102 +** 103 +*/ + /* ** CAPI3REF: Mutex Handle @@ -1496,7 +1542,7 @@ typedef const char *sqlite3_filename; ** greater and the function pointer is not NULL) and will fall back ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. ** -** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces +** ^The xSetSystemCall(), xGetSystemCall(), and xNextSystemCall() interfaces ** are not used by the SQLite core. These optional interfaces are provided ** by some VFSes to facilitate testing of the VFS code. By overriding ** system calls with functions under its control, a test program can @@ -1652,7 +1698,7 @@ struct sqlite3_vfs { ** SQLite interfaces so that an application usually does not need to ** invoke sqlite3_initialize() directly. For example, [sqlite3_open()] ** calls sqlite3_initialize() so the SQLite library will be automatically -** initialized when [sqlite3_open()] is called if it has not be initialized +** initialized when [sqlite3_open()] is called if it has not been initialized ** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT] ** compile-time option, then the automatic calls to sqlite3_initialize() ** are omitted and the application must call sqlite3_initialize() directly @@ -1717,7 +1763,8 @@ SQLITE_API int sqlite3_os_end(void); ** are called "anytime configuration options". ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before ** [sqlite3_shutdown()] with a first argument that is not an anytime -** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE. +** configuration option, then the sqlite3_config() call will +** return SQLITE_MISUSE. ** Note, however, that ^sqlite3_config() can be called as part of the ** implementation of an application-defined [sqlite3_os_init()]. ** @@ -1909,21 +1956,21 @@ struct sqlite3_mem_methods { ** The [sqlite3_mem_methods] ** structure is filled with the currently defined memory allocation routines.)^ ** This option can be used to overload the default memory allocation -** routines with a wrapper that simulations memory allocation failure or +** routines with a wrapper that simulates memory allocation failure or ** tracks memory usage, for example. ** ** [[SQLITE_CONFIG_SMALL_MALLOC]]
    SQLITE_CONFIG_SMALL_MALLOC
    -**
    ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of +**
    ^The SQLITE_CONFIG_SMALL_MALLOC option takes a single argument of ** type int, interpreted as a boolean, which if true provides a hint to ** SQLite that it should avoid large memory allocations if possible. ** SQLite will run faster if it is free to make large memory allocations, -** but some application might prefer to run slower in exchange for +** but some applications might prefer to run slower in exchange for ** guarantees about memory fragmentation that are possible if large ** allocations are avoided. This hint is normally off. **
    ** ** [[SQLITE_CONFIG_MEMSTATUS]]
    SQLITE_CONFIG_MEMSTATUS
    -**
    ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, +**
    ^The SQLITE_CONFIG_MEMSTATUS option takes a single argument of type int, ** interpreted as a boolean, which enables or disables the collection of ** memory allocation statistics. ^(When memory allocation statistics are ** disabled, the following SQLite interfaces become non-operational: @@ -1968,7 +2015,7 @@ struct sqlite3_mem_methods { ** ^If pMem is NULL and N is non-zero, then each database connection ** does an initial bulk allocation for page cache memory ** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or -** of -1024*N bytes if N is negative, . ^If additional +** of -1024*N bytes if N is negative. ^If additional ** page cache memory is needed beyond what is provided by the initial ** allocation, then SQLite goes to [sqlite3_malloc()] separately for each ** additional cache line.
    @@ -1997,7 +2044,7 @@ struct sqlite3_mem_methods { **
    ^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a ** pointer to an instance of the [sqlite3_mutex_methods] structure. ** The argument specifies alternative low-level mutex routines to be used -** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of +** in place of the mutex routines built into SQLite.)^ ^SQLite makes a copy of ** the content of the [sqlite3_mutex_methods] structure before the call to ** [sqlite3_config()] returns. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then @@ -2020,13 +2067,16 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_LOOKASIDE]]
    SQLITE_CONFIG_LOOKASIDE
    **
    ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine -** the default size of lookaside memory on each [database connection]. +** the default size of [lookaside memory] on each [database connection]. ** The first argument is the -** size of each lookaside buffer slot and the second is the number of -** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE -** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] -** option to [sqlite3_db_config()] can be used to change the lookaside -** configuration on individual connections.)^
    +** size of each lookaside buffer slot ("sz") and the second is the number of +** slots allocated to each database connection ("cnt").)^ +** ^(SQLITE_CONFIG_LOOKASIDE sets the default lookaside size. +** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can +** be used to change the lookaside configuration on individual connections.)^ +** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the +** default lookaside configuration at compile-time. +** ** ** [[SQLITE_CONFIG_PCACHE2]]
    SQLITE_CONFIG_PCACHE2
    **
    ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is @@ -2036,7 +2086,7 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_CONFIG_GETPCACHE2]]
    SQLITE_CONFIG_GETPCACHE2
    **
    ^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which -** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of +** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies off ** the current page cache implementation into that object.)^
    ** ** [[SQLITE_CONFIG_LOG]]
    SQLITE_CONFIG_LOG
    @@ -2053,7 +2103,7 @@ struct sqlite3_mem_methods { ** the logger function is a copy of the first parameter to the corresponding ** [sqlite3_log()] call and is intended to be a [result code] or an ** [extended result code]. ^The third parameter passed to the logger is -** log message after formatting via [sqlite3_snprintf()]. +** a log message after formatting via [sqlite3_snprintf()]. ** The SQLite logging interface is not reentrant; the logger function ** supplied by the application must not invoke any SQLite interface. ** In a multi-threaded application, the application-defined logger @@ -2242,7 +2292,15 @@ struct sqlite3_mem_methods { ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that -** can be passed as the second argument to the [sqlite3_db_config()] interface. +** can be passed as the second parameter to the [sqlite3_db_config()] interface. +** +** The [sqlite3_db_config()] interface is a var-args function. It takes a +** variable number of parameters, though always at least two. The number of +** parameters passed into sqlite3_db_config() depends on which of these +** constants is given as the second parameter. This documentation page +** refers to parameters beyond the second as "arguments". Thus, when this +** page says "the N-th argument" it means "the N-th parameter past the +** configuration option" or "the (N+2)-th parameter to sqlite3_db_config()". ** ** New configuration options may be added in future releases of SQLite. ** Existing configuration options might be discontinued. Applications @@ -2254,31 +2312,58 @@ struct sqlite3_mem_methods { **
    ** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    -**
    ^This option takes three additional arguments that determine the -** [lookaside memory allocator] configuration for the [database connection]. -** ^The first argument (the third parameter to [sqlite3_db_config()] is a +**
    The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the +** configuration of the [lookaside memory allocator] within a database +** connection. +** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are not +** in the [DBCONFIG arguments|usual format]. +** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two, +** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE +** should have a total of five parameters. +**
      +**
    1. The first argument ("buf") is a ** pointer to a memory buffer to use for lookaside memory. -** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb -** may be NULL in which case SQLite will allocate the -** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the -** size of each lookaside buffer slot. ^The third argument is the number of -** slots. The size of the buffer in the first argument must be greater than -** or equal to the product of the second and third arguments. The buffer -** must be aligned to an 8-byte boundary. ^If the second argument to -** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally -** rounded down to the next smaller multiple of 8. ^(The lookaside memory +** The first argument may be NULL in which case SQLite will allocate the +** lookaside buffer itself using [sqlite3_malloc()]. +**

    2. The second argument ("sz") is the +** size of each lookaside buffer slot. Lookaside is disabled if "sz" +** is less than 8. The "sz" argument should be a multiple of 8 less than +** 65536. If "sz" does not meet this constraint, it is reduced in size until +** it does. +**

    3. The third argument ("cnt") is the number of slots. +** Lookaside is disabled if "cnt"is less than 1. +* The "cnt" value will be reduced, if necessary, so +** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt" +** parameter is usually chosen so that the product of "sz" and "cnt" is less +** than 1,000,000. +**

    +**

    If the "buf" argument is not NULL, then it must +** point to a memory buffer with a size that is greater than +** or equal to the product of "sz" and "cnt". +** The buffer must be aligned to an 8-byte boundary. +** The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words -** when the "current value" returned by -** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero. +** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns -** [SQLITE_BUSY].)^

    +** [SQLITE_BUSY]. +** If the "buf" argument is NULL and an attempt +** to allocate memory based on "sz" and "cnt" fails, then +** lookaside is silently disabled. +**

    +** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the +** default lookaside configuration at initialization. The +** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside +** configuration at compile-time. Typical values for lookaside are 1200 for +** "sz" and 40 to 100 for "cnt". +** ** ** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **

    SQLITE_DBCONFIG_ENABLE_FKEY
    **
    ^This option is used to enable or disable the enforcement of -** [foreign key constraints]. There should be two additional arguments. +** [foreign key constraints]. This is the same setting that is +** enabled or disabled by the [PRAGMA foreign_keys] statement. ** The first argument is an integer which is 0 to disable FK enforcement, ** positive to enable FK enforcement or negative to leave FK enforcement ** unchanged. The second parameter is a pointer to an integer into which @@ -2300,13 +2385,13 @@ struct sqlite3_mem_methods { **

    Originally this option disabled all triggers. ^(However, since ** SQLite version 3.35.0, TEMP triggers are still allowed even if ** this option is off. So, in other words, this option now only disables -** triggers in the main database schema or in the schemas of ATTACH-ed +** triggers in the main database schema or in the schemas of [ATTACH]-ed ** databases.)^

    ** ** [[SQLITE_DBCONFIG_ENABLE_VIEW]] **
    SQLITE_DBCONFIG_ENABLE_VIEW
    **
    ^This option is used to enable or disable [CREATE VIEW | views]. -** There should be two additional arguments. +** There must be two additional arguments. ** The first argument is an integer which is 0 to disable views, ** positive to enable views or negative to leave the setting unchanged. ** The second parameter is a pointer to an integer into which @@ -2322,17 +2407,20 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] **
    SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
    -**
    ^This option is used to enable or disable the -** [fts3_tokenizer()] function which is part of the -** [FTS3] full-text search engine extension. -** There should be two additional arguments. -** The first argument is an integer which is 0 to disable fts3_tokenizer() or -** positive to enable fts3_tokenizer() or negative to leave the setting -** unchanged. -** The second parameter is a pointer to an integer into which -** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled -** following this call. The second parameter may be a NULL pointer, in -** which case the new setting is not reported back.
    +**
    ^This option is used to enable or disable using the +** [fts3_tokenizer()] function - part of the [FTS3] full-text search engine +** extension - without using bound parameters as the parameters. Doing so +** is disabled by default. There must be two additional arguments. The first +** argument is an integer. If it is passed 0, then using fts3_tokenizer() +** without bound parameters is disabled. If it is passed a positive value, +** then calling fts3_tokenizer without bound parameters is enabled. If it +** is passed a negative value, this setting is not modified - this can be +** used to query for the current setting. The second parameter is a pointer +** to an integer into which is written 0 or 1 to indicate the current value +** of this setting (after it is modified, if applicable). The second +** parameter may be a NULL pointer, in which case the value of the setting +** is not reported back. Refer to [FTS3] documentation for further details. +**
    ** ** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]] **
    SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
    @@ -2340,12 +2428,12 @@ struct sqlite3_mem_methods { ** interface independently of the [load_extension()] SQL function. ** The [sqlite3_enable_load_extension()] API enables or disables both the ** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. -** There should be two additional arguments. +** There must be two additional arguments. ** When the first argument to this interface is 1, then only the C-API is ** enabled and the SQL function remains disabled. If the first argument to ** this interface is 0, then both the C-API and the SQL function are disabled. -** If the first argument is -1, then no changes are made to state of either the -** C-API or the SQL function. +** If the first argument is -1, then no changes are made to the state of either +** the C-API or the SQL function. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface ** is disabled or enabled following this call. The second parameter may @@ -2354,23 +2442,30 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_DBCONFIG_MAINDBNAME]]
    SQLITE_DBCONFIG_MAINDBNAME
    **
    ^This option is used to change the name of the "main" database -** schema. ^The sole argument is a pointer to a constant UTF8 string -** which will become the new schema name in place of "main". ^SQLite -** does not make a copy of the new main schema name string, so the application -** must ensure that the argument passed into this DBCONFIG option is unchanged -** until after the database connection closes. +** schema. This option does not follow the +** [DBCONFIG arguments|usual SQLITE_DBCONFIG argument format]. +** This option takes exactly one additional argument so that the +** [sqlite3_db_config()] call has a total of three parameters. The +** extra argument must be a pointer to a constant UTF8 string which +** will become the new schema name in place of "main". ^SQLite does +** not make a copy of the new main schema name string, so the application +** must ensure that the argument passed into SQLITE_DBCONFIG MAINDBNAME +** is unchanged until after the database connection closes. **
    ** ** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] **
    SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
    -**
    Usually, when a database in wal mode is closed or detached from a -** database handle, SQLite checks if this will mean that there are now no -** connections at all to the database. If so, it performs a checkpoint -** operation before closing the connection. This option may be used to -** override this behavior. The first parameter passed to this operation -** is an integer - positive to disable checkpoints-on-close, or zero (the -** default) to enable them, and negative to leave the setting unchanged. -** The second parameter is a pointer to an integer +**
    Usually, when a database in [WAL mode] is closed or detached from a +** database handle, SQLite checks if if there are other connections to the +** same database, and if there are no other database connection (if the +** connection being closed is the last open connection to the database), +** then SQLite performs a [checkpoint] before closing the connection and +** deletes the WAL file. The SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE option can +** be used to override that behavior. The first argument passed to this +** operation (the third parameter to [sqlite3_db_config()]) is an integer +** which is positive to disable checkpoints-on-close, or zero (the default) +** to enable them, and negative to leave the setting unchanged. +** The second argument (the fourth parameter) is a pointer to an integer ** into which is written 0 or 1 to indicate whether checkpoints-on-close ** have been disabled - 0 if they are not disabled, 1 if they are. **
    @@ -2456,7 +2551,7 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]] **
    SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
    **
    The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates -** the legacy behavior of the [ALTER TABLE RENAME] command such it +** the legacy behavior of the [ALTER TABLE RENAME] command such that it ** behaves as it did prior to [version 3.24.0] (2018-06-04). See the ** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for ** additional information. This feature can also be turned on and off @@ -2505,7 +2600,7 @@ struct sqlite3_mem_methods { **
    SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
    **
    The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates ** the legacy file format flag. When activated, this flag causes all newly -** created database file to have a schema format version number (the 4-byte +** created database files to have a schema format version number (the 4-byte ** integer found at offset 44 into the database header) of 1. This in turn ** means that the resulting database file will be readable and writable by ** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting, @@ -2526,13 +2621,16 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]] **
    SQLITE_DBCONFIG_STMT_SCANSTATUS
    **
    The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in -** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears -** a flag that enables collection of the sqlite3_stmt_scanstatus_v2() -** statistics. For statistics to be collected, the flag must be set on -** the database handle both when the SQL statement is prepared and when it -** is stepped. The flag is set (collection of statistics is enabled) -** by default. This option takes two arguments: an integer and a pointer to -** an integer.. The first argument is 1, 0, or -1 to enable, disable, or +** [SQLITE_ENABLE_STMT_SCANSTATUS] builds. In this case, it sets or clears +** a flag that enables collection of run-time performance statistics +** used by [sqlite3_stmt_scanstatus_v2()] and the [nexec and ncycle] +** columns of the [bytecode virtual table]. +** For statistics to be collected, the flag must be set on +** the database handle both when the SQL statement is +** [sqlite3_prepare|prepared] and when it is [sqlite3_step|stepped]. +** The flag is set (collection of statistics is enabled) by default. +**

    This option takes two arguments: an integer and a pointer to +** an integer. The first argument is 1, 0, or -1 to enable, disable, or ** leave unchanged the statement scanstatus option. If the second argument ** is not NULL, then the value of the statement scanstatus setting after ** processing the first argument is written into the integer that the second @@ -2545,7 +2643,7 @@ struct sqlite3_mem_methods { ** in which tables and indexes are scanned so that the scans start at the end ** and work toward the beginning rather than starting at the beginning and ** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the -** same as setting [PRAGMA reverse_unordered_selects]. This option takes +** same as setting [PRAGMA reverse_unordered_selects].

    This option takes ** two arguments which are an integer and a pointer to an integer. The first ** argument is 1, 0, or -1 to enable, disable, or leave unchanged the ** reverse scan order flag, respectively. If the second argument is not NULL, @@ -2554,7 +2652,95 @@ struct sqlite3_mem_methods { ** first argument. **

    ** +** [[SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]] +**
    SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE
    +**
    The SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE option enables or disables +** the ability of the [ATTACH DATABASE] SQL command to create a new database +** file if the database filed named in the ATTACH command does not already +** exist. This ability of ATTACH to create a new database is enabled by +** default. Applications can disable or reenable the ability for ATTACH to +** create new database files using this DBCONFIG option.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is 1, 0, or -1 to enable, disable, or +** leave unchanged the attach-create flag, respectively. If the second +** argument is not NULL, then 0 or 1 is written into the integer that the +** second argument points to depending on if the attach-create flag is set +** after processing the first argument. +**

    +** +** [[SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE]] +**
    SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE
    +**
    The SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE option enables or disables the +** ability of the [ATTACH DATABASE] SQL command to open a database for writing. +** This capability is enabled by default. Applications can disable or +** reenable this capability using the current DBCONFIG option. If +** this capability is disabled, the [ATTACH] command will still work, +** but the database will be opened read-only. If this option is disabled, +** then the ability to create a new database using [ATTACH] is also disabled, +** regardless of the value of the [SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE] +** option.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is 1, 0, or -1 to enable, disable, or +** leave unchanged the ability to ATTACH another database for writing, +** respectively. If the second argument is not NULL, then 0 or 1 is written +** into the integer to which the second argument points, depending on whether +** the ability to ATTACH a read/write database is enabled or disabled +** after processing the first argument. +**

    +** +** [[SQLITE_DBCONFIG_ENABLE_COMMENTS]] +**
    SQLITE_DBCONFIG_ENABLE_COMMENTS
    +**
    The SQLITE_DBCONFIG_ENABLE_COMMENTS option enables or disables the +** ability to include comments in SQL text. Comments are enabled by default. +** An application can disable or reenable comments in SQL text using this +** DBCONFIG option.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is 1, 0, or -1 to enable, disable, or +** leave unchanged the ability to use comments in SQL text, +** respectively. If the second argument is not NULL, then 0 or 1 is written +** into the integer that the second argument points to depending on if +** comments are allowed in SQL text after processing the first argument. +**

    +** +** [[SQLITE_DBCONFIG_FP_DIGITS]] +**
    SQLITE_DBCONFIG_FP_DIGITS
    +**
    The SQLITE_DBCONFIG_FP_DIGITS setting is a small integer that determines +** the number of significant digits that SQLite will attempt to preserve when +** converting floating point numbers (IEEE 754 "doubles") into text. The +** default value 17, as of SQLite version 3.52.0. The value was 15 in all +** prior versions.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is a small integer, between 3 and 23, or +** zero. The FP_DIGITS setting is changed to that small integer, or left +** unaltered if the first argument is zero or out of range. The second argument +** is a pointer to an integer. If the pointer is not NULL, then the value of +** the FP_DIGITS setting, after possibly being modified by the first +** arguments, is written into the integer to which the second argument points. +**

    +** **
    +** +** [[DBCONFIG arguments]]

    Arguments To SQLITE_DBCONFIG Options

    +** +**

    Most of the SQLITE_DBCONFIG options take two arguments, so that the +** overall call to [sqlite3_db_config()] has a total of four parameters. +** The first argument (the third parameter to sqlite3_db_config()) is +** an integer. +** The second argument is a pointer to an integer. If the first argument is 1, +** then the option becomes enabled. If the first integer argument is 0, +** then the option is disabled. +** If the first argument is -1, then the option setting +** is unchanged. The second argument, the pointer to an integer, may be NULL. +** If the second argument is not NULL, then a value of 0 or 1 is written into +** the integer to which the second argument points, depending on whether the +** setting is disabled or enabled after applying any changes specified by +** the first argument. +** +**

    While most SQLITE_DBCONFIG options use the argument format +** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME], +** [SQLITE_DBCONFIG_LOOKASIDE], and [SQLITE_DBCONFIG_FP_DIGITS] options +** are different. See the documentation of those exceptional options for +** details. */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ @@ -2576,7 +2762,11 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ #define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */ #define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE 1020 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE 1021 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_COMMENTS 1022 /* int int* */ +#define SQLITE_DBCONFIG_FP_DIGITS 1023 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1023 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -2668,10 +2858,14 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. ** The two functions are identical except for the type of the return value -** and that if the number of rows modified by the most recent INSERT, UPDATE +** and that if the number of rows modified by the most recent INSERT, UPDATE, ** or DELETE is greater than the maximum value supported by type "int", then ** the return value of sqlite3_changes() is undefined. ^Executing any other ** type of SQL statement does not modify the value returned by these functions. +** For the purposes of this interface, a CREATE TABLE AS SELECT statement +** does not count as an INSERT, UPDATE or DELETE statement and hence the rows +** added to the new table by the CREATE TABLE AS SELECT statement are not +** counted. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are ** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], @@ -2824,7 +3018,7 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*); ** ^These routines return 0 if the statement is incomplete. ^If a ** memory allocation fails, then SQLITE_NOMEM is returned. ** -** ^These routines do not parse the SQL statements thus +** ^These routines do not parse the SQL statements and thus ** will not detect syntactically incorrect SQL. ** ** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior @@ -2926,6 +3120,44 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); +/* +** CAPI3REF: Set the Setlk Timeout +** METHOD: sqlite3 +** +** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If +** the VFS supports blocking locks, it sets the timeout in ms used by +** eligible locks taken on wal mode databases by the specified database +** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does +** not support blocking locks, this function is a no-op. +** +** Passing 0 to this function disables blocking locks altogether. Passing +** -1 to this function requests that the VFS blocks for a long time - +** indefinitely if possible. The results of passing any other negative value +** are undefined. +** +** Internally, each SQLite database handle stores two timeout values - the +** busy-timeout (used for rollback mode databases, or if the VFS does not +** support blocking locks) and the setlk-timeout (used for blocking locks +** on wal-mode databases). The sqlite3_busy_timeout() method sets both +** values, this function sets only the setlk-timeout value. Therefore, +** to configure separate busy-timeout and setlk-timeout values for a single +** database handle, call sqlite3_busy_timeout() followed by this function. +** +** Whenever the number of connections to a wal mode database falls from +** 1 to 0, the last connection takes an exclusive lock on the database, +** then checkpoints and deletes the wal file. While it is doing this, any +** new connection that tries to read from the database fails with an +** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is +** passed to this API, the new connection blocks until the exclusive lock +** has been released. +*/ +SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags); + +/* +** CAPI3REF: Flags for sqlite3_setlk_timeout() +*/ +#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01 + /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 @@ -2933,7 +3165,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); ** This is a legacy interface that is preserved for backwards compatibility. ** Use of this interface is not recommended. ** -** Definition: A result table is memory data structure created by the +** Definition: A result table is a memory data structure created by the ** [sqlite3_get_table()] interface. A result table records the ** complete query results from one or more queries. ** @@ -3076,7 +3308,7 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** ^Calling sqlite3_free() with a pointer previously returned ** by sqlite3_malloc() or sqlite3_realloc() releases that memory so ** that it might be reused. ^The sqlite3_free() routine is -** a no-op if is called with a NULL pointer. Passing a NULL pointer +** a no-op if it is called with a NULL pointer. Passing a NULL pointer ** to sqlite3_free() is harmless. After being freed, memory ** should neither be read nor written. Even reading previously freed ** memory might result in a segmentation fault or other severe error. @@ -3094,13 +3326,13 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** sqlite3_free(X). ** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation ** of at least N bytes in size or NULL if insufficient memory is available. -** ^If M is the size of the prior allocation, then min(N,M) bytes -** of the prior allocation are copied into the beginning of buffer returned +** ^If M is the size of the prior allocation, then min(N,M) bytes of the +** prior allocation are copied into the beginning of the buffer returned ** by sqlite3_realloc(X,N) and the prior allocation is freed. ** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the ** prior allocation is not freed. ** -** ^The sqlite3_realloc64(X,N) interfaces works the same as +** ^The sqlite3_realloc64(X,N) interface works the same as ** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead ** of a 32-bit signed integer. ** @@ -3150,7 +3382,7 @@ SQLITE_API sqlite3_uint64 sqlite3_msize(void*); ** was last reset. ^The values returned by [sqlite3_memory_used()] and ** [sqlite3_memory_highwater()] include any overhead ** added by SQLite in its implementation of [sqlite3_malloc()], -** but not overhead added by the any underlying system library +** but not overhead added by any underlying system library ** routines that [sqlite3_malloc()] may call. ** ** ^The memory high-water mark is reset to the current value of @@ -3602,7 +3834,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** there is no harm in trying.) ** ** ^(

    [SQLITE_OPEN_SHAREDCACHE]
    -**
    The database is opened [shared cache] enabled, overriding +**
    The database is opened with [shared cache] enabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** The [use of shared cache mode is discouraged] and hence shared cache @@ -3610,7 +3842,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** this option is a no-op. ** ** ^(
    [SQLITE_OPEN_PRIVATECACHE]
    -**
    The database is opened [shared cache] disabled, overriding +**
    The database is opened with [shared cache] disabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** @@ -3945,7 +4177,7 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); ** ** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of ** database filename D with corresponding journal file J and WAL file W and -** with N URI parameters key/values pairs in the array P. The result from +** an array P of N URI Key/Value pairs. The result from ** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that ** is safe to pass to routines like: **
      @@ -4016,6 +4248,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); **
    • sqlite3_errmsg() **
    • sqlite3_errmsg16() **
    • sqlite3_error_offset() +**
    • sqlite3_db_handle() **
    ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language @@ -4028,7 +4261,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); ** subsequent calls to other SQLite interface functions.)^ ** ** ^The sqlite3_errstr(E) interface returns the English-language text -** that describes the [result code] E, as UTF-8, or NULL if E is not an +** that describes the [result code] E, as UTF-8, or NULL if E is not a ** result code for which a text error message is available. ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. @@ -4036,7 +4269,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); ** ^If the most recent error references a specific token in the input ** SQL, the sqlite3_error_offset() interface returns the byte offset ** of the start of that token. ^The byte offset returned by -** sqlite3_error_offset() assumes that the input SQL is UTF8. +** sqlite3_error_offset() assumes that the input SQL is UTF-8. ** ^If the most recent error does not reference a specific token in the input ** SQL, then the sqlite3_error_offset() function returns -1. ** @@ -4061,6 +4294,34 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3*); SQLITE_API const char *sqlite3_errstr(int); SQLITE_API int sqlite3_error_offset(sqlite3 *db); +/* +** CAPI3REF: Set Error Code And Message +** METHOD: sqlite3 +** +** Set the error code of the database handle passed as the first argument +** to errcode, and the error message to a copy of nul-terminated string +** zErrMsg. If zErrMsg is passed NULL, then the error message is set to +** the default message associated with the supplied error code. Subsequent +** calls to [sqlite3_errcode()] and [sqlite3_errmsg()] and similar will +** return the values set by this routine in place of what was previously +** set by SQLite itself. +** +** This function returns SQLITE_OK if the error code and error message are +** successfully set, SQLITE_NOMEM if an OOM occurs, and SQLITE_MISUSE if +** the database handle is NULL or invalid. +** +** The error code and message set by this routine remains in effect until +** they are changed, either by another call to this routine or until they are +** changed to by SQLite itself to reflect the result of some subsquent +** API call. +** +** This function is intended for use by SQLite extensions or wrappers. The +** idea is that an extension or wrapper can use this routine to set error +** messages and error codes and thus behave more like a core SQLite +** feature from the point of view of an application. +*/ +SQLITE_API int sqlite3_set_errmsg(sqlite3 *db, int errcode, const char *zErrMsg); + /* ** CAPI3REF: Prepared Statement Object ** KEYWORDS: {prepared statement} {prepared statements} @@ -4135,8 +4396,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** These constants define various performance limits ** that can be lowered at run-time using [sqlite3_limit()]. -** The synopsis of the meanings of the various limits is shown below. -** Additional information is available at [limits | Limits in SQLite]. +** A concise description of these limits follows, and additional information +** is available at [limits | Limits in SQLite]. ** **
    ** [[SQLITE_LIMIT_LENGTH]] ^(
    SQLITE_LIMIT_LENGTH
    @@ -4151,7 +4412,12 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** or in an ORDER BY or GROUP BY clause.
    )^ ** ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
    SQLITE_LIMIT_EXPR_DEPTH
    -**
    The maximum depth of the parse tree on any expression.
    )^ +**
    The maximum depth of the parse tree on any expression and +** the maximum nesting depth for subqueries and VIEWs
    )^ +** +** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(
    SQLITE_LIMIT_PARSER_DEPTH
    +**
    The maximum depth of the LALR(1) parser stack used to analyze +** input SQL statements.
    )^ ** ** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(
    SQLITE_LIMIT_COMPOUND_SELECT
    **
    The maximum number of terms in a compound SELECT statement.
    )^ @@ -4178,7 +4444,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); **
    The maximum index number of any [parameter] in an SQL statement.)^ ** ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
    SQLITE_LIMIT_TRIGGER_DEPTH
    -**
    The maximum depth of recursion for triggers.
    )^ +**
    The maximum depth of recursion for triggers, and the maximum +** nesting depth for separate triggers.
    )^ ** ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
    SQLITE_LIMIT_WORKER_THREADS
    **
    The maximum number of auxiliary worker threads that a single @@ -4197,11 +4464,12 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +#define SQLITE_LIMIT_PARSER_DEPTH 12 /* ** CAPI3REF: Prepare Flags ** -** These constants define various flags that can be passed into +** These constants define various flags that can be passed into the ** "prepFlags" parameter of the [sqlite3_prepare_v3()] and ** [sqlite3_prepare16_v3()] interfaces. ** @@ -4231,11 +4499,39 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); **
    The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler ** to return an error (error code SQLITE_ERROR) if the statement uses ** any virtual tables. +** +** [[SQLITE_PREPARE_DONT_LOG]]
    SQLITE_PREPARE_DONT_LOG
    +**
    The SQLITE_PREPARE_DONT_LOG flag prevents SQL compiler +** errors from being sent to the error log defined by +** [SQLITE_CONFIG_LOG]. This can be used, for example, to do test +** compiles to see if some SQL syntax is well-formed, without generating +** messages on the global error log when it is not. If the test compile +** fails, the sqlite3_prepare_v3() call returns the same error indications +** with or without this flag; it just omits the call to [sqlite3_log()] that +** logs the error. +** +** [[SQLITE_PREPARE_FROM_DDL]]
    SQLITE_PREPARE_FROM_DDL
    +**
    The SQLITE_PREPARE_FROM_DDL flag causes the SQL compiler to enforce +** security constraints that would otherwise only be enforced when parsing +** the database schema. In other words, the SQLITE_PREPARE_FROM_DDL flag +** causes the SQL compiler to treat the SQL statement being prepared as if +** it had come from an attacker. When SQLITE_PREPARE_FROM_DDL is used and +** [SQLITE_DBCONFIG_TRUSTED_SCHEMA] is off, SQL functions may only be called +** if they are tagged with [SQLITE_INNOCUOUS] and virtual tables may only +** be used if they are tagged with [SQLITE_VTAB_INNOCUOUS]. Best practice +** is to use the SQLITE_PREPARE_FROM_DDL option when preparing any SQL that +** is derived from parts of the database schema. In particular, virtual +** table implementations that run SQL statements that are derived from +** arguments to their CREATE VIRTUAL TABLE statement should always use +** [sqlite3_prepare_v3()] and set the SQLITE_PREPARE_FROM_DDL flag to +** prevent bypass of the [SQLITE_DBCONFIG_TRUSTED_SCHEMA] security checks. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 #define SQLITE_PREPARE_NORMALIZE 0x02 #define SQLITE_PREPARE_NO_VTAB 0x04 +#define SQLITE_PREPARE_DONT_LOG 0x10 +#define SQLITE_PREPARE_FROM_DDL 0x20 /* ** CAPI3REF: Compiling An SQL Statement @@ -4249,8 +4545,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** The preferred routine to use is [sqlite3_prepare_v2()]. The ** [sqlite3_prepare()] interface is legacy and should be avoided. -** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used -** for special purposes. +** [sqlite3_prepare_v3()] has an extra +** [SQLITE_PREPARE_FROM_DDL|"prepFlags" option] that is sometimes +** needed for special purpose or to pass along security restrictions. ** ** The use of the UTF-8 interfaces is preferred, as SQLite currently ** does all parsing using UTF-8. The UTF-16 interfaces are provided @@ -4277,7 +4574,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** there is a small performance advantage to passing an nByte parameter that ** is the number of bytes in the input string including ** the nul-terminator. -** Note that nByte measure the length of the input in bytes, not +** Note that nByte measures the length of the input in bytes, not ** characters, even for the UTF-16 interfaces. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte @@ -4411,7 +4708,7 @@ SQLITE_API int sqlite3_prepare16_v3( ** ** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory ** is available to hold the result, or if the result would exceed the -** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. +** maximum string length determined by the [SQLITE_LIMIT_LENGTH]. ** ** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time @@ -4599,7 +4896,7 @@ typedef struct sqlite3_value sqlite3_value; ** ** The context in which an SQL function executes is stored in an ** sqlite3_context object. ^A pointer to an sqlite3_context object -** is always first parameter to [application-defined SQL functions]. +** is always the first parameter to [application-defined SQL functions]. ** The application-defined SQL function implementation will pass this ** pointer through into calls to [sqlite3_result_int | sqlite3_result()], ** [sqlite3_aggregate_context()], [sqlite3_user_data()], @@ -4615,7 +4912,7 @@ typedef struct sqlite3_context sqlite3_context; ** METHOD: sqlite3_stmt ** ** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants, -** literals may be replaced by a [parameter] that matches one of following +** literals may be replaced by a [parameter] that matches one of the following ** templates: ** **
      @@ -4655,12 +4952,12 @@ typedef struct sqlite3_context sqlite3_context; ** it should be a pointer to well-formed UTF16 text. ** ^If the third parameter to sqlite3_bind_text64() is not NULL, then ** it should be a pointer to a well-formed unicode string that is -** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16 -** otherwise. +** either UTF8 if the sixth parameter is SQLITE_UTF8 or SQLITE_UTF8_ZT, +** or UTF16 otherwise. ** ** [[byte-order determination rules]] ^The byte-order of ** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF) -** found in first character, which is removed, or in the absence of a BOM +** found in the first character, which is removed, or in the absence of a BOM ** the byte order is the native byte order of the host ** machine for sqlite3_bind_text16() or the byte order specified in ** the 6th parameter for sqlite3_bind_text64().)^ @@ -4680,7 +4977,7 @@ typedef struct sqlite3_context sqlite3_context; ** or sqlite3_bind_text16() or sqlite3_bind_text64() then ** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL -** terminated. If any NUL characters occurs at byte offsets less than +** terminated. If any NUL characters occur at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. @@ -4702,10 +4999,15 @@ typedef struct sqlite3_context sqlite3_context; ** object and pointer to it must remain valid until then. ^SQLite will then ** manage the lifetime of its private copy. ** -** ^The sixth argument to sqlite3_bind_text64() must be one of -** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] -** to specify the encoding of the text in the third parameter. If -** the sixth argument to sqlite3_bind_text64() is not one of the +** ^The sixth argument (the E argument) +** to sqlite3_bind_text64(S,K,Z,N,D,E) must be one of +** [SQLITE_UTF8], [SQLITE_UTF8_ZT], [SQLITE_UTF16], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE] to specify the encoding of the text in the +** third parameter, Z. The special value [SQLITE_UTF8_ZT] means that the +** string argument is both UTF-8 encoded and is zero-terminated. In other +** words, SQLITE_UTF8_ZT means that the Z array is allocated to hold at +** least N+1 bytes and that the Z[N] byte is zero. If +** the E argument to sqlite3_bind_text64(S,K,Z,N,D,E) is not one of the ** allowed values shown above, or if the text encoding is different ** from the encoding specified by the sixth parameter, then the behavior ** is undefined. @@ -4723,9 +5025,11 @@ typedef struct sqlite3_context sqlite3_context; ** associated with the pointer P of type T. ^D is either a NULL pointer or ** a pointer to a destructor function for P. ^SQLite will invoke the ** destructor D with a single argument of P when it is finished using -** P. The T parameter should be a static string, preferably a string -** literal. The sqlite3_bind_pointer() routine is part of the -** [pointer passing interface] added for SQLite 3.20.0. +** P, even if the call to sqlite3_bind_pointer() fails. Due to a +** historical design quirk, results are undefined if D is +** SQLITE_TRANSIENT. The T parameter should be a static string, +** preferably a string literal. The sqlite3_bind_pointer() routine is +** part of the [pointer passing interface] added for SQLite 3.20.0. ** ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer ** for the [prepared statement] or with a prepared statement for which @@ -4892,7 +5196,7 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); ** METHOD: sqlite3_stmt ** ** ^These routines provide a means to determine the database, table, and -** table column that is the origin of a particular result column in +** table column that is the origin of a particular result column in a ** [SELECT] statement. ** ^The name of the database or table or column can be returned as ** either a UTF-8 or UTF-16 string. ^The _database_ routines return @@ -5030,7 +5334,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from -** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], +** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]), ** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility @@ -5336,7 +5640,7 @@ SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); ** ** ^The sqlite3_finalize() function is called to delete a [prepared statement]. ** ^If the most recent evaluation of the statement encountered no errors -** or if the statement is never been evaluated, then sqlite3_finalize() returns +** or if the statement has never been evaluated, then sqlite3_finalize() returns ** SQLITE_OK. ^If the most recent evaluation of statement S failed, then ** sqlite3_finalize(S) returns the appropriate [error code] or ** [extended error code]. @@ -5461,8 +5765,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** ** For best security, the [SQLITE_DIRECTONLY] flag is recommended for ** all application-defined SQL functions that do not need to be -** used inside of triggers, view, CHECK constraints, or other elements of -** the database schema. This flags is especially recommended for SQL +** used inside of triggers, views, CHECK constraints, or other elements of +** the database schema. This flag is especially recommended for SQL ** functions that have side effects or reveal internal application state. ** Without this flag, an attacker might be able to modify the schema of ** a database file to include invocations of the function with parameters @@ -5493,7 +5797,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** [user-defined window functions|available here]. ** ** ^(If the final parameter to sqlite3_create_function_v2() or -** sqlite3_create_window_function() is not NULL, then it is destructor for +** sqlite3_create_window_function() is not NULL, then it is the destructor for ** the application data pointer. The destructor is invoked when the function ** is deleted, either by being overloaded or when the database connection ** closes.)^ ^The destructor is also invoked if the call to @@ -5568,8 +5872,54 @@ SQLITE_API int sqlite3_create_window_function( /* ** CAPI3REF: Text Encodings ** -** These constant define integer codes that represent the various +** These constants define integer codes that represent the various ** text encodings supported by SQLite. +** +**
      +** [[SQLITE_UTF8]]
      SQLITE_UTF8
      Text is encoding as UTF-8
      +** +** [[SQLITE_UTF16LE]]
      SQLITE_UTF16LE
      Text is encoding as UTF-16 +** with each code point being expressed "little endian" - the least significant +** byte first. This is the usual encoding, for example on Windows.
      +** +** [[SQLITE_UTF16BE]]
      SQLITE_UTF16BE
      Text is encoding as UTF-16 +** with each code point being expressed "big endian" - the most significant +** byte first. This encoding is less common, but is still sometimes seen, +** specially on older systems. +** +** [[SQLITE_UTF16]]
      SQLITE_UTF16
      Text is encoding as UTF-16 +** with each code point being expressed either little endian or as big +** endian, according to the native endianness of the host computer. +** +** [[SQLITE_ANY]]
      SQLITE_ANY
      This encoding value may only be used +** to declare the preferred text for [application-defined SQL functions] +** created using [sqlite3_create_function()] and similar. If the preferred +** encoding (the 4th parameter to sqlite3_create_function() - the eTextRep +** parameter) is SQLITE_ANY, that indicates that the function does not have +** a preference regarding the text encoding of its parameters and can take +** any text encoding that the SQLite core find convenient to supply. This +** option is deprecated. Please do not use it in new applications. +** +** [[SQLITE_UTF16_ALIGNED]]
      SQLITE_UTF16_ALIGNED
      This encoding +** value may be used as the 3rd parameter (the eTextRep parameter) to +** [sqlite3_create_collation()] and similar. This encoding value means +** that the application-defined collating sequence created expects its +** input strings to be in UTF16 in native byte order, and that the start +** of the strings must be aligned to a 2-byte boundary. +** +** [[SQLITE_UTF8_ZT]]
      SQLITE_UTF8_ZT
      This option can only be +** used to specify the text encoding to strings input to +** [sqlite3_result_text64()] and [sqlite3_bind_text64()]. +** The SQLITE_UTF8_ZT encoding means that the input string (call it "z") +** is UTF-8 encoded and that it is zero-terminated. If the length parameter +** (call it "n") is non-negative, this encoding option means that the caller +** guarantees that z array contains at least n+1 bytes and that the z[n] +** byte has a value of zero. +** This option gives the same output as SQLITE_UTF8, but can be more efficient +** by avoiding the need to make a copy of the input string, in some cases. +** However, if z is allocated to hold fewer than n+1 bytes or if the +** z[n] byte is not zero, undefined behavior may result. +**
      */ #define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ #define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ @@ -5577,6 +5927,7 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* Deprecated */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ +#define SQLITE_UTF8_ZT 16 /* Zero-terminated UTF8 */ /* ** CAPI3REF: Function Flags @@ -5660,7 +6011,7 @@ SQLITE_API int sqlite3_create_window_function( ** result. ** Every function that invokes [sqlite3_result_subtype()] should have this ** property. If it does not, then the call to [sqlite3_result_subtype()] -** might become a no-op if the function is used as term in an +** might become a no-op if the function is used as a term in an ** [expression index]. On the other hand, SQL functions that never invoke ** [sqlite3_result_subtype()] should avoid setting this property, as the ** purpose of this property is to disable certain optimizations that are @@ -5787,7 +6138,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** sqlite3_value_nochange(X) interface returns true if and only if ** the column corresponding to X is unchanged by the UPDATE operation ** that the xUpdate method call was invoked to implement and if -** and the prior [xColumn] method call that was invoked to extracted +** the prior [xColumn] method call that was invoked to extract ** the value for that column returned without setting a result (probably ** because it queried [sqlite3_vtab_nochange()] and found that the column ** was unchanging). ^Within an [xUpdate] method, any value for which @@ -5811,26 +6162,22 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** the SQL function that supplied the [sqlite3_value*] parameters. ** ** As long as the input parameter is correct, these routines can only -** fail if an out-of-memory error occurs during a format conversion. -** Only the following subset of interfaces are subject to out-of-memory -** errors: -** -**
        -**
      • sqlite3_value_blob() -**
      • sqlite3_value_text() -**
      • sqlite3_value_text16() -**
      • sqlite3_value_text16le() -**
      • sqlite3_value_text16be() -**
      • sqlite3_value_bytes() -**
      • sqlite3_value_bytes16() -**
      -** +** fail if an out-of-memory error occurs while trying to do a +** UTF8→UTF16 or UTF16→UTF8 conversion. ** If an out-of-memory error occurs, then the return value from these ** routines is the same as if the column had contained an SQL NULL value. -** Valid SQL NULL returns can be distinguished from out-of-memory errors -** by invoking the [sqlite3_errcode()] immediately after the suspect +** If the input sqlite3_value was not obtained from [sqlite3_value_dup()], +** then valid SQL NULL returns can also be distinguished from +** out-of-memory errors after extracting the value +** by invoking the [sqlite3_errcode()] immediately after the suspicious ** return value is obtained and before any ** other SQLite interface is called on the same [database connection]. +** If the input sqlite3_value was obtained from sqlite3_value_dup() then +** it is disconnected from the database connection and so sqlite3_errcode() +** will not work. +** In that case, the only way to distinguish an out-of-memory +** condition from a true SQL NULL is to invoke sqlite3_value_type() on the +** input to see if it is NULL prior to trying to extract the value. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); @@ -5857,7 +6204,8 @@ SQLITE_API int sqlite3_value_frombind(sqlite3_value*); ** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X) ** returns something other than SQLITE_TEXT, then the return value from ** sqlite3_value_encoding(X) is meaningless. ^Calls to -** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)], +** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], +** [sqlite3_value_text16be(X)], ** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or ** [sqlite3_value_bytes16(X)] might change the encoding of the value X and ** thus change the return from subsequent calls to sqlite3_value_encoding(X). @@ -5893,7 +6241,7 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); ** METHOD: sqlite3_value ** ** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value] -** object D and returns a pointer to that copy. ^The [sqlite3_value] returned +** object V and returns a pointer to that copy. ^The [sqlite3_value] returned ** is a [protected sqlite3_value] object even if the input is not. ** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a ** memory allocation fails. ^If V is a [pointer value], then the result @@ -5931,7 +6279,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*); ** allocation error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is -** determined by the N parameter on first successful call. Changing the +** determined by the N parameter on the first successful call. Changing the ** value of N in any subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory ** allocation.)^ Within the xFinal callback, it is customary to set @@ -5988,17 +6336,17 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** query execution, under some circumstances the associated auxiliary data ** might be preserved. An example of where this might be useful is in a ** regular-expression matching function. The compiled version of the regular -** expression can be stored as auxiliary data associated with the pattern string. -** Then as long as the pattern string remains the same, +** expression can be stored as auxiliary data associated with the pattern +** string. Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data -** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument -** value to the application-defined function. ^N is zero for the left-most -** function argument. ^If there is no auxiliary data -** associated with the function argument, the sqlite3_get_auxdata(C,N) interface -** returns a NULL pointer. +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary +** data associated by the sqlite3_set_auxdata(C,N,P,X) function with the +** Nth argument value to the application-defined function. ^N is zero +** for the left-most function argument. ^If there is no auxiliary data +** associated with the function argument, the sqlite3_get_auxdata(C,N) +** interface returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the ** N-th argument of the application-defined function. ^Subsequent @@ -6060,6 +6408,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi ** or a NULL pointer if there were no prior calls to ** sqlite3_set_clientdata() with the same values of D and N. ** Names are compared using strcmp() and are thus case sensitive. +** It returns 0 on success and SQLITE_NOMEM on allocation failure. ** ** If P and X are both non-NULL, then the destructor X is invoked with ** argument P on the first of the following occurrences: @@ -6081,10 +6430,14 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi ** ** There is no limit (other than available memory) on the number of different ** client data pointers (with different names) that can be attached to a -** single database connection. However, the implementation is optimized -** for the case of having only one or two different client data names. -** Applications and wrapper libraries are discouraged from using more than -** one client data name each. +** single database connection. However, the current implementation stores +** the content on a linked list. Insert and retrieval performance will +** be proportional to the number of entries. The design use case, and +** the use case for which the implementation is optimized, is +** that an application will store only small number of client data names, +** typically just one or two. This interface is not intended to be a +** generalized key/value store for thousands or millions of keys. It +** will work for that, but performance might be disappointing. ** ** There is no way to enumerate the client data pointers ** associated with a database connection. The N parameter can be thought @@ -6093,7 +6446,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi ** ** Security Warning: These interfaces should not be exposed in scripting ** languages or in other circumstances where it might be possible for an -** an attacker to invoke them. Any agent that can invoke these interfaces +** attacker to invoke them. Any agent that can invoke these interfaces ** can probably also take control of the process. ** ** Database connection client data is only available for SQLite @@ -6192,10 +6545,14 @@ typedef void (*sqlite3_destructor_type)(void*); ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. -** ^The sqlite3_result_text64() interface sets the return value of an +** ^The sqlite3_result_text64(C,Z,N,D,E) interface sets the return value of an ** application-defined function to be a text string in an encoding -** specified by the fifth (and last) parameter, which must be one -** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. +** specified the E parameter, which must be one +** of [SQLITE_UTF8], [SQLITE_UTF8_ZT], [SQLITE_UTF16], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE]. ^The special value [SQLITE_UTF8_ZT] means that +** the result text is both UTF-8 and zero-terminated. In other words, +** SQLITE_UTF8_ZT means that the Z array holds at least N+1 bytes and that +** the Z[N] is zero. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to any of the sqlite3_result_text* interfaces @@ -6207,7 +6564,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** pointed to by the 2nd parameter are taken as the application-defined ** function result. If the 3rd parameter is non-negative, then it ** must be the byte offset into the string where the NUL terminator would -** appear if the string where NUL terminated. If any NUL characters occur +** appear if the string were NUL terminated. If any NUL characters occur ** in the string at a byte offset that is less than the value of the 3rd ** parameter, then the resulting string will contain embedded NULs and the ** result of expressions operating on strings with embedded NULs is undefined. @@ -6265,7 +6622,7 @@ typedef void (*sqlite3_destructor_type)(void*); ** string and preferably a string literal. The sqlite3_result_pointer() ** routine is part of the [pointer passing interface] added for SQLite 3.20.0. ** -** If these routines are called from within the different thread +** If these routines are called from within a different thread ** than the one containing the application-defined function that received ** the [sqlite3_context] pointer, the results are undefined. */ @@ -6282,7 +6639,7 @@ SQLITE_API void sqlite3_result_int(sqlite3_context*, int); SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); SQLITE_API void sqlite3_result_null(sqlite3_context*); SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); -SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, +SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char *z, sqlite3_uint64 n, void(*)(void*), unsigned char encoding); SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); @@ -6671,7 +7028,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); ** METHOD: sqlite3 ** ** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name -** for the N-th database on database connection D, or a NULL pointer of N is +** for the N-th database on database connection D, or a NULL pointer if N is ** out of range. An N value of 0 means the main database file. An N of 1 is ** the "temp" schema. Larger values of N correspond to various ATTACH-ed ** databases. @@ -6766,7 +7123,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); **
      The SQLITE_TXN_READ state means that the database is currently ** in a read transaction. Content has been read from the database file ** but nothing in the database file has changed. The transaction state -** will advanced to SQLITE_TXN_WRITE if any changes occur and there are +** will be advanced to SQLITE_TXN_WRITE if any changes occur and there are ** no other conflicting concurrent write transactions. The transaction ** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or ** [COMMIT].
      @@ -6775,7 +7132,7 @@ SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); **
      The SQLITE_TXN_WRITE state means that the database is currently ** in a write transaction. Content has been written to the database file ** but has not yet committed. The transaction state will change to -** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
      +** SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
    */ #define SQLITE_TXN_NONE 0 #define SQLITE_TXN_READ 1 @@ -6926,6 +7283,8 @@ SQLITE_API int sqlite3_autovacuum_pages( ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. +** ^The update hook is disabled by invoking sqlite3_update_hook() +** with a NULL pointer as the second parameter. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], @@ -7054,7 +7413,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); ** CAPI3REF: Impose A Limit On Heap Size ** ** These interfaces impose limits on the amount of heap memory that will be -** by all database connections within a single process. +** used by all database connections within a single process. ** ** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the ** soft limit on the amount of heap memory that may be allocated by SQLite. @@ -7112,7 +7471,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); ** )^ ** ** The circumstances under which SQLite will enforce the heap limits may -** changes in future releases of SQLite. +** change in future releases of SQLite. */ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N); @@ -7219,7 +7578,7 @@ SQLITE_API int sqlite3_table_column_metadata( ** ^The sqlite3_load_extension() interface attempts to load an ** [SQLite extension] library contained in the file zFile. If ** the file cannot be loaded directly, attempts are made to load -** with various operating-system specific extensions added. +** with various operating-system specific filename extensions added. ** So for example, if "samplelib" cannot be loaded, then names like ** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might ** be tried also. @@ -7227,10 +7586,10 @@ SQLITE_API int sqlite3_table_column_metadata( ** ^The entry point is zProc. ** ^(zProc may be 0, in which case SQLite will try to come up with an ** entry point name on its own. It first tries "sqlite3_extension_init". -** If that does not work, it constructs a name "sqlite3_X_init" where the -** X is consists of the lower-case equivalent of all ASCII alphabetic -** characters in the filename from the last "/" to the first following -** "." and omitting any initial "lib".)^ +** If that does not work, it tries names of the form "sqlite3_X_init" +** where X consists of the lower-case equivalent of all ASCII alphabetic +** characters or all ASCII alphanumeric characters in the filename from +** the last "/" to the first following "." and omitting any initial "lib".)^ ** ^The sqlite3_load_extension() interface returns ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. ** ^If an error occurs and pzErrMsg is not 0, then the @@ -7299,12 +7658,12 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three ** arguments and expects an integer result as if the signature of the -** entry point where as follows: +** entry point were as follows: ** **
     **    int xEntryPoint(
     **      sqlite3 *db,
    -**      const char **pzErrMsg,
    +**      char **pzErrMsg,
     **      const struct sqlite3_api_routines *pThunk
     **    );
     ** 
    )^ @@ -7463,7 +7822,7 @@ struct sqlite3_module { ** virtual table and might not be checked again by the byte code.)^ ^(The ** aConstraintUsage[].omit flag is an optimization hint. When the omit flag ** is left in its default setting of false, the constraint will always be -** checked separately in byte code. If the omit flag is change to true, then +** checked separately in byte code. If the omit flag is changed to true, then ** the constraint may or may not be checked in byte code. In other words, ** when the omit flag is true there is no guarantee that the constraint will ** not be checked again using byte code.)^ @@ -7489,7 +7848,7 @@ struct sqlite3_module { ** The xBestIndex method may optionally populate the idxFlags field with a ** mask of SQLITE_INDEX_SCAN_* flags. One such flag is ** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN] -** output to show the idxNum has hex instead of as decimal. Another flag is +** output to show the idxNum as hex instead of as decimal. Another flag is ** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will ** return at most one row. ** @@ -7630,7 +7989,7 @@ struct sqlite3_index_info { ** the implementation of the [virtual table module]. ^The fourth ** parameter is an arbitrary client data pointer that is passed through ** into the [xCreate] and [xConnect] methods of the virtual table module -** when a new virtual table is be being created or reinitialized. +** when a new virtual table is being created or reinitialized. ** ** ^The sqlite3_create_module_v2() interface has a fifth parameter which ** is a pointer to a destructor for the pClientData. ^SQLite will @@ -7795,7 +8154,7 @@ typedef struct sqlite3_blob sqlite3_blob; ** in *ppBlob. Otherwise an [error code] is returned and, unless the error ** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided ** the API is not misused, it is always safe to call [sqlite3_blob_close()] -** on *ppBlob after this function it returns. +** on *ppBlob after this function returns. ** ** This function fails with SQLITE_ERROR if any of the following are true: **
      @@ -7915,7 +8274,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *); ** ** ^Returns the size in bytes of the BLOB accessible via the ** successfully opened [BLOB handle] in its only argument. ^The -** incremental blob I/O routines can only read or overwriting existing +** incremental blob I/O routines can only read or overwrite existing ** blob content; they cannot change the size of a blob. ** ** This routine only works on a [BLOB handle] which has been created @@ -8054,18 +8413,11 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); ** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix ** and Windows. ** -** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor -** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex -** implementation is included with the library. In this case the -** application must supply a custom mutex implementation using the -** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function -** before calling sqlite3_initialize() or any other public sqlite3_ -** function that calls sqlite3_initialize(). ** ** ^The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc() ** routine returns NULL if it is unable to allocate the requested -** mutex. The argument to sqlite3_mutex_alloc() must one of these +** mutex. The argument to sqlite3_mutex_alloc() must be one of these ** integer constants: ** **
        @@ -8298,7 +8650,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); ** CAPI3REF: Retrieve the mutex for a database connection ** METHOD: sqlite3 ** -** ^This interface returns a pointer the [sqlite3_mutex] object that +** ^This interface returns a pointer to the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument ** when the [threading mode] is Serialized. ** ^If the [threading mode] is Single-thread or Multi-thread then this @@ -8415,13 +8767,14 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */ +#define SQLITE_TESTCTRL_ATOF 34 #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking ** ** These routines provide access to the set of SQL language keywords -** recognized by SQLite. Applications can uses these routines to determine +** recognized by SQLite. Applications can use these routines to determine ** whether or not a specific identifier needs to be escaped (for example, ** by enclosing in double-quotes) so as not to confuse the parser. ** @@ -8523,17 +8876,22 @@ SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); ** pass the returned value to [sqlite3_free()] to avoid a memory leak. ** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any ** errors were encountered during construction of the string. ^The -** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the +** [sqlite3_str_finish(X)] interface might also return a NULL pointer if the ** string in [sqlite3_str] object X is zero bytes long. +** +** ^The [sqlite3_str_free(X)] interface destroys both the sqlite3_str object +** X and the string content it contains. Calling sqlite3_str_free(X) is +** the equivalent of calling [sqlite3_free](sqlite3_str_finish(X)). */ SQLITE_API char *sqlite3_str_finish(sqlite3_str*); +SQLITE_API void sqlite3_str_free(sqlite3_str*); /* ** CAPI3REF: Add Content To A Dynamic String ** METHOD: sqlite3_str ** -** These interfaces add content to an sqlite3_str object previously obtained -** from [sqlite3_str_new()]. +** These interfaces add or remove content to an sqlite3_str object +** previously obtained from [sqlite3_str_new()]. ** ** ^The [sqlite3_str_appendf(X,F,...)] and ** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] @@ -8556,6 +8914,10 @@ SQLITE_API char *sqlite3_str_finish(sqlite3_str*); ** ^The [sqlite3_str_reset(X)] method resets the string under construction ** inside [sqlite3_str] object X back to zero bytes in length. ** +** ^The [sqlite3_str_truncate(X,N)] method changes the length of the string +** under construction to be N bytes or less. This routine is a no-op if +** N is negative or if the string is already N bytes or smaller in size. +** ** These methods do not return a result code. ^If an error occurs, that fact ** is recorded in the [sqlite3_str] object and can be recovered by a ** subsequent call to [sqlite3_str_errcode(X)]. @@ -8566,6 +8928,7 @@ SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn); SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); SQLITE_API void sqlite3_str_reset(sqlite3_str*); +SQLITE_API void sqlite3_str_truncate(sqlite3_str*,int N); /* ** CAPI3REF: Status Of A Dynamic String @@ -8589,7 +8952,7 @@ SQLITE_API void sqlite3_str_reset(sqlite3_str*); ** content of the dynamic string under construction in X. The value ** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X ** and might be freed or altered by any subsequent method on the same -** [sqlite3_str] object. Applications must not used the pointer returned +** [sqlite3_str] object. Applications must not use the pointer returned by ** [sqlite3_str_value(X)] after any subsequent method call on the same ** object. ^Applications may change the content of the string returned ** by [sqlite3_str_value(X)] as long as they do not write into any bytes @@ -8675,7 +9038,7 @@ SQLITE_API int sqlite3_status64( ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] ** buffer and where forced to overflow to [sqlite3_malloc()]. The ** returned value includes allocations that overflowed because they -** where too large (they were larger than the "sz" parameter to +** were too large (they were larger than the "sz" parameter to ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because ** no space was left in the page cache.)^ ** @@ -8734,9 +9097,18 @@ SQLITE_API int sqlite3_status64( ** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a ** non-zero [error code] on failure. ** +** ^The sqlite3_db_status64(D,O,C,H,R) routine works exactly the same +** way as sqlite3_db_status(D,O,C,H,R) routine except that the C and H +** parameters are pointer to 64-bit integers (type: sqlite3_int64) instead +** of pointers to 32-bit integers, which allows larger status values +** to be returned. If a status value exceeds 2,147,483,647 then +** sqlite3_db_status() will truncate the value whereas sqlite3_db_status64() +** will return the full value. +** ** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. */ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); +SQLITE_API int sqlite3_db_status64(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int); /* ** CAPI3REF: Status Parameters for database connections @@ -8759,28 +9131,29 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(
        SQLITE_DBSTATUS_LOOKASIDE_HIT
        **
        This parameter returns the number of malloc attempts that were ** satisfied using lookaside memory. Only the high-water value is meaningful; -** the current value is always zero.)^ +** the current value is always zero.
        )^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] ** ^(
        SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
        -**
        This parameter returns the number malloc attempts that might have +**
        This parameter returns the number of malloc attempts that might have ** been satisfied using lookaside memory but failed due to the amount of ** memory requested being larger than the lookaside slot size. ** Only the high-water value is meaningful; -** the current value is always zero.)^ +** the current value is always zero.
        )^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] ** ^(
        SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
        -**
        This parameter returns the number malloc attempts that might have +**
        This parameter returns the number of malloc attempts that might have ** been satisfied using lookaside memory but failed due to all lookaside ** memory already being in use. ** Only the high-water value is meaningful; -** the current value is always zero.)^ +** the current value is always zero.
        )^ ** ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
        SQLITE_DBSTATUS_CACHE_USED
        **
        This parameter returns the approximate number of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. +**
        ** ** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] ** ^(
        SQLITE_DBSTATUS_CACHE_USED_SHARED
        @@ -8789,10 +9162,10 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** memory used by that pager cache is divided evenly between the attached ** connections.)^ In other words, if none of the pager caches associated ** with the database connection are shared, this request returns the same -** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are +** value as DBSTATUS_CACHE_USED. Or, if one or more of the pager caches are ** shared, the value returned by this call will be smaller than that returned ** by DBSTATUS_CACHE_USED. ^The highwater mark associated with -** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. +** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. ** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
        SQLITE_DBSTATUS_SCHEMA_USED
        **
        This parameter returns the approximate number of bytes of heap @@ -8802,6 +9175,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** schema memory is shared with other database connections due to ** [shared cache mode] being enabled. ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. +**
        ** ** [[SQLITE_DBSTATUS_STMT_USED]] ^(
        SQLITE_DBSTATUS_STMT_USED
        **
        This parameter returns the approximate number of bytes of heap @@ -8831,6 +9205,10 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** If an IO or other error occurs while writing a page to disk, the effect ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. +**

        +** ^(There is overlap between the quantities measured by this parameter +** (SQLITE_DBSTATUS_CACHE_WRITE) and SQLITE_DBSTATUS_TEMPBUF_SPILL. +** Resetting one will reduce the other.)^ **

        ** ** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(
        SQLITE_DBSTATUS_CACHE_SPILL
        @@ -8838,7 +9216,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** been written to disk in the middle of a transaction due to the page ** cache overflowing. Transactions are more efficient if they are written ** to disk all at once. When pages spill mid-transaction, that introduces -** additional overhead. This parameter can be used help identify +** additional overhead. This parameter can be used to help identify ** inefficiencies that can be resolved by increasing the cache size. ** ** @@ -8846,6 +9224,18 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r **
        This parameter returns zero for the current value if and only if ** all foreign key constraints (deferred or immediate) have been ** resolved.)^ ^The highwater mark is always 0. +** +** [[SQLITE_DBSTATUS_TEMPBUF_SPILL] ^(
        SQLITE_DBSTATUS_TEMPBUF_SPILL
        +**
        ^(This parameter returns the number of bytes written to temporary +** files on disk that could have been kept in memory had sufficient memory +** been available. This value includes writes to intermediate tables that +** are part of complex queries, external sorts that spill to disk, and +** writes to TEMP tables.)^ +** ^The highwater mark is always 0. +**

        +** ^(There is overlap between the quantities measured by this parameter +** (SQLITE_DBSTATUS_TEMPBUF_SPILL) and SQLITE_DBSTATUS_CACHE_WRITE. +** Resetting one will reduce the other.)^ **

        ** */ @@ -8862,7 +9252,8 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r #define SQLITE_DBSTATUS_DEFERRED_FKS 10 #define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 #define SQLITE_DBSTATUS_CACHE_SPILL 12 -#define SQLITE_DBSTATUS_MAX 12 /* Largest defined DBSTATUS */ +#define SQLITE_DBSTATUS_TEMPBUF_SPILL 13 +#define SQLITE_DBSTATUS_MAX 13 /* Largest defined DBSTATUS */ /* @@ -8909,13 +9300,13 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** [[SQLITE_STMTSTATUS_SORT]]
        SQLITE_STMTSTATUS_SORT
        **
        ^This is the number of sort operations that have occurred. ** A non-zero value in this counter may indicate an opportunity to -** improvement performance through careful use of indices.
        +** improve performance through careful use of indices. ** ** [[SQLITE_STMTSTATUS_AUTOINDEX]]
        SQLITE_STMTSTATUS_AUTOINDEX
        **
        ^This is the number of rows inserted into transient indices that ** were created automatically in order to help joins run faster. ** A non-zero value in this counter may indicate an opportunity to -** improvement performance by adding permanent indices that do not +** improve performance by adding permanent indices that do not ** need to be reinitialized each time the statement is run.
        ** ** [[SQLITE_STMTSTATUS_VM_STEP]]
        SQLITE_STMTSTATUS_VM_STEP
        @@ -8924,19 +9315,19 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** to 2147483647. The number of virtual machine operations can be ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 -** then the value returned by this statement status code is undefined. +** then the value returned by this statement status code is undefined. ** ** [[SQLITE_STMTSTATUS_REPREPARE]]
        SQLITE_STMTSTATUS_REPREPARE
        **
        ^This is the number of times that the prepare statement has been ** automatically regenerated due to schema changes or changes to -** [bound parameters] that might affect the query plan. +** [bound parameters] that might affect the query plan.
        ** ** [[SQLITE_STMTSTATUS_RUN]]
        SQLITE_STMTSTATUS_RUN
        **
        ^This is the number of times that the prepared statement has ** been run. A single "run" for the purposes of this counter is one ** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()]. ** The counter is incremented on the first [sqlite3_step()] call of each -** cycle. +** cycle.
        ** ** [[SQLITE_STMTSTATUS_FILTER_MISS]] ** [[SQLITE_STMTSTATUS_FILTER HIT]] @@ -8946,7 +9337,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** step was bypassed because a Bloom filter returned not-found. The ** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of ** times that the Bloom filter returned a find, and thus the join step -** had to be processed as normal. +** had to be processed as normal. ** ** [[SQLITE_STMTSTATUS_MEMUSED]]
        SQLITE_STMTSTATUS_MEMUSED
        **
        ^This is the approximate number of bytes of heap memory @@ -9051,9 +9442,9 @@ struct sqlite3_pcache_page { ** SQLite will typically create one cache instance for each open database file, ** though this is not guaranteed. ^The ** first parameter, szPage, is the size in bytes of the pages that must -** be allocated by the cache. ^szPage will always a power of two. ^The +** be allocated by the cache. ^szPage will always be a power of two. ^The ** second parameter szExtra is a number of bytes of extra storage -** associated with each page cache entry. ^The szExtra parameter will +** associated with each page cache entry. ^The szExtra parameter will be ** a number less than 250. SQLite will use the ** extra szExtra bytes on each page to store metadata about the underlying ** database page on disk. The value passed into szExtra depends @@ -9061,17 +9452,17 @@ struct sqlite3_pcache_page { ** ^The third argument to xCreate(), bPurgeable, is true if the cache being ** created will be used to cache database pages of a file stored on disk, or ** false if it is used for an in-memory database. The cache implementation -** does not have to do anything special based with the value of bPurgeable; +** does not have to do anything special based upon the value of bPurgeable; ** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will ** never invoke xUnpin() except to deliberately delete a page. ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to ** false will always have the "discard" flag set to true. -** ^Hence, a cache created with bPurgeable false will +** ^Hence, a cache created with bPurgeable set to false will ** never contain any unpinned pages. ** ** [[the xCachesize() page cache method]] ** ^(The xCachesize() method may be called at any time by SQLite to set the -** suggested maximum cache-size (number of pages stored by) the cache +** suggested maximum cache-size (number of pages stored) for the cache ** instance passed as the first argument. This is the value configured using ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable ** parameter, the implementation is not required to do anything with this @@ -9098,12 +9489,12 @@ struct sqlite3_pcache_page { ** implementation must return a pointer to the page buffer with its content ** intact. If the requested page is not already in the cache, then the ** cache implementation should use the value of the createFlag -** parameter to help it determined what action to take: +** parameter to help it determine what action to take: ** ** ** **
        createFlag Behavior when page is not already in cache **
        0 Do not allocate a new page. Return NULL. -**
        1 Allocate a new page if it easy and convenient to do so. +**
        1 Allocate a new page if it is easy and convenient to do so. ** Otherwise return NULL. **
        2 Make every effort to allocate a new page. Only return ** NULL if allocating a new page is effectively impossible. @@ -9120,7 +9511,7 @@ struct sqlite3_pcache_page { ** as its second argument. If the third parameter, discard, is non-zero, ** then the page must be evicted from the cache. ** ^If the discard parameter is -** zero, then the page may be discarded or retained at the discretion of +** zero, then the page may be discarded or retained at the discretion of the ** page cache implementation. ^The page cache implementation ** may choose to evict unpinned pages at any time. ** @@ -9138,7 +9529,7 @@ struct sqlite3_pcache_page { ** When SQLite calls the xTruncate() method, the cache must discard all ** existing cache entries with page numbers (keys) greater than or equal ** to the value of the iLimit parameter passed to xTruncate(). If any -** of these pages are pinned, they are implicitly unpinned, meaning that +** of these pages are pinned, they become implicitly unpinned, meaning that ** they can be safely discarded. ** ** [[the xDestroy() page cache method]] @@ -9318,7 +9709,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** external process or via a database connection other than the one being ** used by the backup operation, then the backup will be automatically ** restarted by the next call to sqlite3_backup_step(). ^If the source -** database is modified by the using the same database connection as is used +** database is modified by using the same database connection as is used ** by the backup operation, then the backup database is automatically ** updated at the same time. ** @@ -9335,7 +9726,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** and may not be used following a call to sqlite3_backup_finish(). ** ** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no -** sqlite3_backup_step() errors occurred, regardless or whether or not +** sqlite3_backup_step() errors occurred, regardless of whether or not ** sqlite3_backup_step() completed. ** ^If an out-of-memory condition or IO error occurred during any prior ** sqlite3_backup_step() call on the same [sqlite3_backup] object, then @@ -9437,7 +9828,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** application receives an SQLITE_LOCKED error, it may call the ** sqlite3_unlock_notify() method with the blocked connection handle as ** the first argument to register for a callback that will be invoked -** when the blocking connections current transaction is concluded. ^The +** when the blocking connection's current transaction is concluded. ^The ** callback is invoked from within the [sqlite3_step] or [sqlite3_close] ** call that concludes the blocking connection's transaction. ** @@ -9457,7 +9848,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** blocked connection already has a registered unlock-notify callback, ** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is ** called with a NULL pointer as its second argument, then any existing -** unlock-notify callback is canceled. ^The blocked connections +** unlock-notify callback is canceled. ^The blocked connection's ** unlock-notify callback may also be canceled by closing the blocked ** connection using [sqlite3_close()]. ** @@ -9627,7 +10018,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); ** is the number of pages currently in the write-ahead log file, ** including those that were just committed. ** -** The callback function should normally return [SQLITE_OK]. ^If an error +** ^The callback function should normally return [SQLITE_OK]. ^If an error ** code is returned, that error will propagate back up through the ** SQLite code base to cause the statement that provoked the callback ** to report an error, though the commit will have still occurred. If the @@ -9635,13 +10026,26 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); ** that does not correspond to any valid SQLite error code, the results ** are undefined. ** -** A single database handle may have at most a single write-ahead log callback -** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any -** previously registered write-ahead log callback. ^The return value is -** a copy of the third parameter from the previous call, if any, or 0. -** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the -** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will -** overwrite any prior [sqlite3_wal_hook()] settings. +** ^A single database handle may have at most a single write-ahead log +** callback registered at one time. ^Calling [sqlite3_wal_hook()] +** replaces the default behavior or previously registered write-ahead +** log callback. +** +** ^The return value is a copy of the third parameter from the +** previous call, if any, or 0. +** +** ^The [sqlite3_wal_autocheckpoint()] interface and the +** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and +** will overwrite any prior [sqlite3_wal_hook()] settings. +** +** ^If a write-ahead log callback is set using this function then +** [sqlite3_wal_checkpoint_v2()] or [PRAGMA wal_checkpoint] +** should be invoked periodically to keep the write-ahead log file +** from growing without bound. +** +** ^Passing a NULL pointer for the callback disables automatic +** checkpointing entirely. To re-enable the default behavior, call +** sqlite3_wal_autocheckpoint(db,1000) or use [PRAGMA wal_checkpoint]. */ SQLITE_API void *sqlite3_wal_hook( sqlite3*, @@ -9658,7 +10062,7 @@ SQLITE_API void *sqlite3_wal_hook( ** to automatically [checkpoint] ** after committing a transaction if there are N or ** more frames in the [write-ahead log] file. ^Passing zero or -** a negative value as the nFrame parameter disables automatic +** a negative value as the N parameter disables automatic ** checkpoints entirely. ** ** ^The callback registered by this function replaces any existing callback @@ -9674,9 +10078,10 @@ SQLITE_API void *sqlite3_wal_hook( ** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] -** pages. The use of this interface -** is only necessary if the default setting is found to be suboptimal -** for a particular application. +** pages. +** +** ^The use of this interface is only necessary if the default setting +** is found to be suboptimal for a particular application. */ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); @@ -9741,6 +10146,11 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the ** addition that it also truncates the log file to zero bytes just prior ** to a successful return. +** +**
        SQLITE_CHECKPOINT_NOOP
        +** ^This mode always checkpoints zero frames. The only reason to invoke +** a NOOP checkpoint is to access the values returned by +** sqlite3_wal_checkpoint_v2() via output parameters *pnLog and *pnCkpt. ** ** ** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in @@ -9811,6 +10221,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( ** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the ** meaning of each of these checkpoint modes. */ +#define SQLITE_CHECKPOINT_NOOP -1 /* Do no work at all */ #define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ #define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ #define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */ @@ -9855,7 +10266,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** support constraints. In this configuration (which is the default) if ** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire ** statement is rolled back as if [ON CONFLICT | OR ABORT] had been -** specified as part of the users SQL statement, regardless of the actual +** specified as part of the user's SQL statement, regardless of the actual ** ON CONFLICT mode specified. ** ** If X is non-zero, then the virtual table implementation guarantees @@ -9889,7 +10300,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** [[SQLITE_VTAB_INNOCUOUS]]
        SQLITE_VTAB_INNOCUOUS
        **
        Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the -** the [xConnect] or [xCreate] methods of a [virtual table] implementation +** [xConnect] or [xCreate] methods of a [virtual table] implementation ** identify that virtual table as being safe to use from within triggers ** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the ** virtual table can do no serious harm even if it is controlled by a @@ -10048,7 +10459,8 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); **
        sqlite3_vtab_distinct() return value ** Rows are returned in aOrderBy order -** Rows with the same value in all aOrderBy columns are adjacent +** Rows with the same value in all aOrderBy columns are +** adjacent ** Duplicates over all colUsed columns may be omitted **
        0yesyesno **
        1noyesno @@ -10057,8 +10469,8 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); **
        ** ** ^For the purposes of comparing virtual table output values to see if the -** values are same value for sorting purposes, two NULL values are considered -** to be the same. In other words, the comparison operator is "IS" +** values are the same value for sorting purposes, two NULL values are +** considered to be the same. In other words, the comparison operator is "IS" ** (or "IS NOT DISTINCT FROM") and not "==". ** ** If a virtual table implementation is unable to meet the requirements @@ -10067,7 +10479,7 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); ** ** ^A virtual table implementation is always free to return rows in any order ** it wants, as long as the "orderByConsumed" flag is not set. ^When the -** the "orderByConsumed" flag is unset, the query planner will add extra +** "orderByConsumed" flag is unset, the query planner will add extra ** [bytecode] to ensure that the final results returned by the SQL query are ** ordered correctly. The use of the "orderByConsumed" flag and the ** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful @@ -10164,7 +10576,7 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); ** sqlite3_vtab_in_next(X,P) should be one of the parameters to the ** xFilter method which invokes these routines, and specifically ** a parameter that was previously selected for all-at-once IN constraint -** processing use the [sqlite3_vtab_in()] interface in the +** processing using the [sqlite3_vtab_in()] interface in the ** [xBestIndex|xBestIndex method]. ^(If the X parameter is not ** an xFilter argument that was selected for all-at-once IN constraint ** processing, then these routines return [SQLITE_ERROR].)^ @@ -10179,7 +10591,7 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); **   ){ **   // do something with pVal **   } -**   if( rc!=SQLITE_OK ){ +**   if( rc!=SQLITE_DONE ){ **   // an error has occurred **   } ** )^ @@ -10219,7 +10631,7 @@ SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut); ** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V) ** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th ** constraint is not available. ^The sqlite3_vtab_rhs_value() interface -** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if +** can return a result code other than SQLITE_OK or SQLITE_NOTFOUND if ** something goes wrong. ** ** The sqlite3_vtab_rhs_value() interface is usually only successful if @@ -10247,8 +10659,8 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** KEYWORDS: {conflict resolution mode} ** ** These constants are returned by [sqlite3_vtab_on_conflict()] to -** inform a [virtual table] implementation what the [ON CONFLICT] mode -** is for the SQL statement being evaluated. +** inform a [virtual table] implementation of the [ON CONFLICT] mode +** for the SQL statement being evaluated. ** ** Note that the [SQLITE_IGNORE] constant is also used as a potential ** return value from the [sqlite3_set_authorizer()] callback and that @@ -10288,39 +10700,39 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** [[SQLITE_SCANSTAT_EST]]
        SQLITE_SCANSTAT_EST
        **
        ^The "double" variable pointed to by the V parameter will be set to the ** query planner's estimate for the average number of rows output from each -** iteration of the X-th loop. If the query planner's estimates was accurate, +** iteration of the X-th loop. If the query planner's estimate was accurate, ** then this value will approximate the quotient NVISIT/NLOOP and the ** product of this value for all prior loops with the same SELECTID will -** be the NLOOP value for the current loop. +** be the NLOOP value for the current loop.
        ** ** [[SQLITE_SCANSTAT_NAME]]
        SQLITE_SCANSTAT_NAME
        **
        ^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the name of the index or table -** used for the X-th loop. +** used for the X-th loop.
        ** ** [[SQLITE_SCANSTAT_EXPLAIN]]
        SQLITE_SCANSTAT_EXPLAIN
        **
        ^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] -** description for the X-th loop. +** description for the X-th loop.
        ** ** [[SQLITE_SCANSTAT_SELECTID]]
        SQLITE_SCANSTAT_SELECTID
        **
        ^The "int" variable pointed to by the V parameter will be set to the ** id for the X-th query plan element. The id value is unique within the ** statement. The select-id is the same value as is output in the first -** column of an [EXPLAIN QUERY PLAN] query. +** column of an [EXPLAIN QUERY PLAN] query.
        ** ** [[SQLITE_SCANSTAT_PARENTID]]
        SQLITE_SCANSTAT_PARENTID
        **
        The "int" variable pointed to by the V parameter will be set to the -** the id of the parent of the current query element, if applicable, or +** id of the parent of the current query element, if applicable, or ** to zero if the query element has no parent. This is the same value as -** returned in the second column of an [EXPLAIN QUERY PLAN] query. +** returned in the second column of an [EXPLAIN QUERY PLAN] query.
        ** ** [[SQLITE_SCANSTAT_NCYCLE]]
        SQLITE_SCANSTAT_NCYCLE
        **
        The sqlite3_int64 output value is set to the number of cycles, ** according to the processor time-stamp counter, that elapsed while the ** query element was being processed. This value is not available for ** all query elements - if it is unavailable the output variable is -** set to -1. +** set to -1.
        ** */ #define SQLITE_SCANSTAT_NLOOP 0 @@ -10351,9 +10763,9 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** a variable pointed to by the "pOut" parameter. ** ** The "flags" parameter must be passed a mask of flags. At present only -** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX +** one flag is defined - [SQLITE_SCANSTAT_COMPLEX]. If SQLITE_SCANSTAT_COMPLEX ** is specified, then status information is available for all elements -** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If +** of a query plan that are reported by "[EXPLAIN QUERY PLAN]" output. If ** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements ** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of ** the EXPLAIN QUERY PLAN output) are available. Invoking API @@ -10361,13 +10773,14 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter. ** ** Parameter "idx" identifies the specific query element to retrieve statistics -** for. Query elements are numbered starting from zero. A value of -1 may be -** to query for statistics regarding the entire query. ^If idx is out of range +** for. Query elements are numbered starting from zero. A value of -1 may +** retrieve statistics for the entire query. ^If idx is out of range ** - less than -1 or greater than or equal to the total number of query ** elements used to implement the statement - a non-zero value is returned and ** the variable that pOut points to is unchanged. ** -** See also: [sqlite3_stmt_scanstatus_reset()] +** See also: [sqlite3_stmt_scanstatus_reset()] and the +** [nexec and ncycle] columns of the [bytecode virtual table]. */ SQLITE_API int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ @@ -10405,7 +10818,7 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); ** METHOD: sqlite3 ** ** ^If a write-transaction is open on [database connection] D when the -** [sqlite3_db_cacheflush(D)] interface invoked, any dirty +** [sqlite3_db_cacheflush(D)] interface is invoked, any dirty ** pages in the pager-cache that are not currently in use are written out ** to disk. A dirty page may be in use if a database cursor created by an ** active SQL statement is reading from it, or if it is page 1 of a database @@ -10519,8 +10932,8 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** triggers; and so forth. ** ** When the [sqlite3_blob_write()] API is used to update a blob column, -** the pre-update hook is invoked with SQLITE_DELETE. This is because the -** in this case the new values are not available. In this case, when a +** the pre-update hook is invoked with SQLITE_DELETE, because +** the new values are not yet available. In this case, when a ** callback made with op==SQLITE_DELETE is actually a write using the ** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns ** the index of the column being written. In other cases, where the @@ -10638,7 +11051,7 @@ typedef struct sqlite3_snapshot { ** The [sqlite3_snapshot_get()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( +SQLITE_API int sqlite3_snapshot_get( sqlite3 *db, const char *zSchema, sqlite3_snapshot **ppSnapshot @@ -10687,7 +11100,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( ** The [sqlite3_snapshot_open()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( +SQLITE_API int sqlite3_snapshot_open( sqlite3 *db, const char *zSchema, sqlite3_snapshot *pSnapshot @@ -10704,7 +11117,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( ** The [sqlite3_snapshot_free()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ -SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); +SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot*); /* ** CAPI3REF: Compare the ages of two snapshot handles. @@ -10731,7 +11144,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); ** This interface is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SNAPSHOT] option. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( +SQLITE_API int sqlite3_snapshot_cmp( sqlite3_snapshot *p1, sqlite3_snapshot *p2 ); @@ -10759,20 +11172,21 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( ** This interface is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SNAPSHOT] option. */ -SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); +SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Serialize a database ** -** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory -** that is a serialization of the S database on [database connection] D. +** The sqlite3_serialize(D,S,P,F) interface returns a pointer to +** memory that is a serialization of the S database on +** [database connection] D. If S is a NULL pointer, the main database is used. ** If P is not a NULL pointer, then the size of the database in bytes ** is written into *P. ** ** For an ordinary on-disk database file, the serialization is just a ** copy of the disk file. For an in-memory database or a "TEMP" database, ** the serialization is the same sequence of bytes which would be written -** to disk if that database where backed up to disk. +** to disk if that database were backed up to disk. ** ** The usual case is that sqlite3_serialize() copies the serialization of ** the database into memory obtained from [sqlite3_malloc64()] and returns @@ -10781,7 +11195,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c ** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations ** are made, and the sqlite3_serialize() function will return a pointer ** to the contiguous memory representation of the database that SQLite -** is currently using for that database, or NULL if the no such contiguous +** is currently using for that database, or NULL if no such contiguous ** memory representation of the database exists. A contiguous memory ** representation of the database will usually only exist if there has ** been a prior call to [sqlite3_deserialize(D,S,...)] with the same @@ -10832,12 +11246,13 @@ SQLITE_API unsigned char *sqlite3_serialize( ** ** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the ** [database connection] D to disconnect from database S and then -** reopen S as an in-memory database based on the serialization contained -** in P. The serialized database P is N bytes in size. M is the size of -** the buffer P, which might be larger than N. If M is larger than N, and -** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is -** permitted to add content to the in-memory database as long as the total -** size does not exceed M bytes. +** reopen S as an in-memory database based on the serialization +** contained in P. If S is a NULL pointer, the main database is +** used. The serialized database P is N bytes in size. M is the size +** of the buffer P, which might be larger than N. If M is larger than +** N, and the SQLITE_DESERIALIZE_READONLY bit is not set in F, then +** SQLite is permitted to add content to the in-memory database as +** long as the total size does not exceed M bytes. ** ** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will ** invoke sqlite3_free() on the serialization buffer when the database @@ -10852,7 +11267,7 @@ SQLITE_API unsigned char *sqlite3_serialize( ** database is currently in a read transaction or is involved in a backup ** operation. ** -** It is not possible to deserialized into the TEMP database. If the +** It is not possible to deserialize into the TEMP database. If the ** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the ** function returns SQLITE_ERROR. ** @@ -10874,7 +11289,7 @@ SQLITE_API int sqlite3_deserialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which DB to reopen with the deserialization */ unsigned char *pData, /* The serialized database content */ - sqlite3_int64 szDb, /* Number bytes in the deserialization */ + sqlite3_int64 szDb, /* Number of bytes in the deserialization */ sqlite3_int64 szBuf, /* Total size of buffer pData[] */ unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ ); @@ -10882,7 +11297,7 @@ SQLITE_API int sqlite3_deserialize( /* ** CAPI3REF: Flags for sqlite3_deserialize() ** -** The following are allowed values for 6th argument (the F argument) to +** The following are allowed values for the 6th argument (the F argument) to ** the [sqlite3_deserialize(D,S,P,N,M,F)] interface. ** ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization @@ -10904,6 +11319,77 @@ SQLITE_API int sqlite3_deserialize( #define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */ #define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */ +/* +** CAPI3REF: Bind array values to the CARRAY table-valued function +** +** The sqlite3_carray_bind_v2(S,I,P,N,F,X,D) interface binds an array value to +** parameter that is the first argument of the [carray() table-valued function]. +** The S parameter is a pointer to the [prepared statement] that uses the +** carray() functions. I is the parameter index to be bound. I must be the +** index of the parameter that is the first argument to the carray() +** table-valued function. P is a pointer to the array to be bound, and N +** is the number of elements in the array. The F argument is one of +** constants [SQLITE_CARRAY_INT32], [SQLITE_CARRAY_INT64], +** [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT], +** or [SQLITE_CARRAY_BLOB] to indicate the datatype of the array P. +** +** If the X argument is not a NULL pointer or one of the special +** values [SQLITE_STATIC] or [SQLITE_TRANSIENT], then SQLite will invoke +** the function X with argument D when it is finished using the data in P. +** The call to X(D) is a destructor for the array P. The destructor X(D) +** is invoked even if the call to sqlite3_carray_bind_v2() fails. If the X +** parameter is the special-case value [SQLITE_STATIC], then SQLite assumes +** that the data static and the destructor is never invoked. If the X +** parameter is the special-case value [SQLITE_TRANSIENT], then +** sqlite3_carray_bind_v2() makes its own private copy of the data prior +** to returning and never invokes the destructor X. +** +** The sqlite3_carray_bind() function works the same as sqlite3_carray_bind_v2() +** with a D parameter set to P. In other words, +** sqlite3_carray_bind(S,I,P,N,F,X) is same as +** sqlite3_carray_bind_v2(S,I,P,N,F,X,P). +*/ +SQLITE_API int sqlite3_carray_bind_v2( + sqlite3_stmt *pStmt, /* Statement to be bound */ + int i, /* Parameter index */ + void *aData, /* Pointer to array data */ + int nData, /* Number of data elements */ + int mFlags, /* CARRAY flags */ + void (*xDel)(void*), /* Destructor for aData */ + void *pDel /* Optional argument to xDel() */ +); +SQLITE_API int sqlite3_carray_bind( + sqlite3_stmt *pStmt, /* Statement to be bound */ + int i, /* Parameter index */ + void *aData, /* Pointer to array data */ + int nData, /* Number of data elements */ + int mFlags, /* CARRAY flags */ + void (*xDel)(void*) /* Destructor for aData */ +); + +/* +** CAPI3REF: Datatypes for the CARRAY table-valued function +** +** The fifth argument to the [sqlite3_carray_bind()] interface musts be +** one of the following constants, to specify the datatype of the array +** that is being bound into the [carray table-valued function]. +*/ +#define SQLITE_CARRAY_INT32 0 /* Data is 32-bit signed integers */ +#define SQLITE_CARRAY_INT64 1 /* Data is 64-bit signed integers */ +#define SQLITE_CARRAY_DOUBLE 2 /* Data is doubles */ +#define SQLITE_CARRAY_TEXT 3 /* Data is char* */ +#define SQLITE_CARRAY_BLOB 4 /* Data is struct iovec */ + +/* +** Versions of the above #defines that omit the initial SQLITE_, for +** legacy compatibility. +*/ +#define CARRAY_INT32 0 /* Data is 32-bit signed integers */ +#define CARRAY_INT64 1 /* Data is 64-bit signed integers */ +#define CARRAY_DOUBLE 2 /* Data is doubles */ +#define CARRAY_TEXT 3 /* Data is char* */ +#define CARRAY_BLOB 4 /* Data is struct iovec */ + /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. @@ -10926,7 +11412,7 @@ SQLITE_API int sqlite3_deserialize( #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif -#endif /* SQLITE3_H */ +/* #endif for SQLITE3_H will be added by mksqlite3.tcl */ /******** Begin file sqlite3rtree.h *********/ /* @@ -11407,9 +11893,10 @@ SQLITE_API void sqlite3session_table_filter( ** is inserted while a session object is enabled, then later deleted while ** the same session object is disabled, no INSERT record will appear in the ** changeset, even though the delete took place while the session was disabled. -** Or, if one field of a row is updated while a session is disabled, and -** another field of the same row is updated while the session is enabled, the -** resulting changeset will contain an UPDATE change that updates both fields. +** Or, if one field of a row is updated while a session is enabled, and +** then another field of the same row is updated while the session is disabled, +** the resulting changeset will contain an UPDATE change that updates both +** fields. */ SQLITE_API int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ @@ -11481,8 +11968,9 @@ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession ** database zFrom the contents of the two compatible tables would be ** identical. ** -** It an error if database zFrom does not exist or does not contain the -** required compatible table. +** Unless the call to this function is a no-op as described above, it is an +** error if database zFrom does not exist or does not contain the required +** compatible table. ** ** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg @@ -11617,7 +12105,7 @@ SQLITE_API int sqlite3changeset_start_v2( ** The following flags may passed via the 4th parameter to ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: ** -**
        SQLITE_CHANGESETAPPLY_INVERT
        +**
        SQLITE_CHANGESETSTART_INVERT
        ** Invert the changeset while iterating through it. This is equivalent to ** inverting a changeset using sqlite3changeset_invert() before applying it. ** It is an error to specify this flag with a patchset. @@ -11932,19 +12420,6 @@ SQLITE_API int sqlite3changeset_concat( void **ppOut /* OUT: Buffer containing output changeset */ ); - -/* -** CAPI3REF: Upgrade the Schema of a Changeset/Patchset -*/ -SQLITE_API int sqlite3changeset_upgrade( - sqlite3 *db, - const char *zDb, - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ -); - - - /* ** CAPI3REF: Changegroup Handle ** @@ -12174,14 +12649,32 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); ** update the "main" database attached to handle db with the changes found in ** the changeset passed via the second and third arguments. ** +** All changes made by these functions are enclosed in a savepoint transaction. +** If any other error (aside from a constraint failure when attempting to +** write to the target database) occurs, then the savepoint transaction is +** rolled back, restoring the target database to its original state, and an +** SQLite error code returned. Additionally, starting with version 3.51.0, +** an error code and error message that may be accessed using the +** [sqlite3_errcode()] and [sqlite3_errmsg()] APIs are left in the database +** handle. +** ** The fourth argument (xFilter) passed to these functions is the "filter -** callback". If it is not NULL, then for each table affected by at least one -** change in the changeset, the filter callback is invoked with -** the table name as the second argument, and a copy of the context pointer -** passed as the sixth argument as the first. If the "filter callback" -** returns zero, then no attempt is made to apply any changes to the table. -** Otherwise, if the return value is non-zero or the xFilter argument to -** is NULL, all changes related to the table are attempted. +** callback". This may be passed NULL, in which case all changes in the +** changeset are applied to the database. For sqlite3changeset_apply() and +** sqlite3_changeset_apply_v2(), if it is not NULL, then it is invoked once +** for each table affected by at least one change in the changeset. In this +** case the table name is passed as the second argument, and a copy of +** the context pointer passed as the sixth argument to apply() or apply_v2() +** as the first. If the "filter callback" returns zero, then no attempt is +** made to apply any changes to the table. Otherwise, if the return value is +** non-zero, all changes related to the table are attempted. +** +** For sqlite3_changeset_apply_v3(), the xFilter callback is invoked once +** per change. The second argument in this case is an sqlite3_changeset_iter +** that may be queried using the usual APIs for the details of the current +** change. If the "filter callback" returns zero in this case, then no attempt +** is made to apply the current change. If it returns non-zero, the change +** is applied. ** ** For each table that is not excluded by the filter callback, this function ** tests that the target database contains a compatible table. A table is @@ -12202,11 +12695,11 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); ** one such warning is issued for each table in the changeset. ** ** For each change for which there is a compatible table, an attempt is made -** to modify the table contents according to the UPDATE, INSERT or DELETE -** change. If a change cannot be applied cleanly, the conflict handler -** function passed as the fifth argument to sqlite3changeset_apply() may be -** invoked. A description of exactly when the conflict handler is invoked for -** each type of change is below. +** to modify the table contents according to each UPDATE, INSERT or DELETE +** change that is not excluded by a filter callback. If a change cannot be +** applied cleanly, the conflict handler function passed as the fifth argument +** to sqlite3changeset_apply() may be invoked. A description of exactly when +** the conflict handler is invoked for each type of change is below. ** ** Unlike the xFilter argument, xConflict may not be passed NULL. The results ** of passing anything other than a valid function pointer as the xConflict @@ -12302,12 +12795,6 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); ** This can be used to further customize the application's conflict ** resolution strategy. ** -** All changes made by these functions are enclosed in a savepoint transaction. -** If any other error (aside from a constraint failure when attempting to -** write to the target database) occurs, then the savepoint transaction is -** rolled back, restoring the target database to its original state, and an -** SQLite error code returned. -** ** If the output parameters (ppRebase) and (pnRebase) are non-NULL and ** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2() ** may set (*ppRebase) to point to a "rebase" that may be used with the @@ -12357,6 +12844,23 @@ SQLITE_API int sqlite3changeset_apply_v2( void **ppRebase, int *pnRebase, /* OUT: Rebase data */ int flags /* SESSION_CHANGESETAPPLY_* flags */ ); +SQLITE_API int sqlite3changeset_apply_v3( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + sqlite3_changeset_iter *p /* Handle describing change */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, /* OUT: Rebase data */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ +); /* ** CAPI3REF: Flags for sqlite3changeset_apply_v2 @@ -12397,11 +12901,23 @@ SQLITE_API int sqlite3changeset_apply_v2( ** database behave as if they were declared with "ON UPDATE NO ACTION ON ** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL ** or SET DEFAULT. +** +**
        SQLITE_CHANGESETAPPLY_NOUPDATELOOP
        +** Sometimes, a changeset contains two or more update statements such that +** although after applying all updates the database will contain no +** constraint violations, no single update can be applied before the others. +** The simplest example of this is a pair of UPDATEs that have "swapped" +** two column values with a UNIQUE constraint. +**

        +** Usually, sqlite3changeset_apply() and similar functions work hard to try +** to find a way to apply such a changeset. However, if this flag is set, +** then all such updates are considered CONSTRAINT conflicts. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 #define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004 #define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008 +#define SQLITE_CHANGESETAPPLY_NOUPDATELOOP 0x0010 /* ** CAPI3REF: Constants Passed To The Conflict Handler @@ -12776,6 +13292,23 @@ SQLITE_API int sqlite3changeset_apply_v2_strm( void **ppRebase, int *pnRebase, int flags ); +SQLITE_API int sqlite3changeset_apply_v3_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + sqlite3_changeset_iter *p + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, + int flags +); SQLITE_API int sqlite3changeset_concat_strm( int (*xInputA)(void *pIn, void *pData, int *pnData), void *pInA, @@ -12867,6 +13400,232 @@ SQLITE_API int sqlite3session_config(int op, void *pArg); */ #define SQLITE_SESSION_CONFIG_STRMSIZE 1 +/* +** CAPI3REF: Configure a changegroup object +** +** Configure the changegroup object passed as the first argument. +** At present the only valid value for the second parameter is +** [SQLITE_CHANGEGROUP_CONFIG_PATCHSET]. +*/ +SQLITE_API int sqlite3changegroup_config(sqlite3_changegroup*, int, void *pArg); + +/* +** CAPI3REF: Options for sqlite3changegroup_config(). +** +** The following values may be passed as the 2nd parameter to +** sqlite3changegroup_config(). +** +**

        SQLITE_CHANGEGROUP_CONFIG_PATCHSET
        +** A changegroup object generates either a changeset or patchset. Usually, +** this is determined by whether the first call to sqlite3changegroup_add() +** is passed a changeset or a patchset. Or, if the first changes are added +** to the changegroup object using the sqlite3changegroup_change_xxx() +** APIs, then this option may be used to configure whether the changegroup +** object generates a changeset or patchset. +** +** When this option is invoked, parameter pArg must point to a value of +** type int. If the changegroup currently contains zero changes, and the +** value of the int variable is zero or greater than zero, then the +** changegroup is configured to generate a changeset or patchset, +** respectively. It is a no-op, not an error, if the changegroup is not +** configured because it has already started accumulating changes. +** +** Before returning, the int variable is set to 0 if the changegroup is +** configured to generate a changeset, or 1 if it is configured to generate +** a patchset. +*/ +#define SQLITE_CHANGEGROUP_CONFIG_PATCHSET 1 + + +/* +** CAPI3REF: Begin adding a change to a changegroup +** +** This API is used, in concert with other sqlite3changegroup_change_xxx() +** APIs, to add changes to a changegroup object one at a time. To add a +** single change, the caller must: +** +** 1. Invoke sqlite3changegroup_change_begin() to indicate the type of +** change (INSERT, UPDATE or DELETE), the affected table and whether +** or not the change should be marked as indirect. +** +** 2. Invoke sqlite3changegroup_change_int64() or one of the other four +** value functions - _null(), _double(), _text() or _blob() - one or +** more times to specify old.* and new.* values for the change being +** constructed. +** +** 3. Invoke sqlite3changegroup_change_finish() to either finish adding +** the change to the group, or to discard the change altogether. +** +** The first argument to this function must be a pointer to the existing +** changegroup object that the change will be added to. The second argument +** must be SQLITE_INSERT, SQLITE_UPDATE or SQLITE_DELETE. The third is the +** name of the table that the change affects, and the fourth is a boolean +** flag specifying whether the change should be marked as "indirect" (if +** bIndirect is non-zero) or not indirect (if bIndirect is zero). +** +** Following a successful call to this function, this function may not be +** called again on the same changegroup object until after +** sqlite3changegroup_change_finish() has been called. Doing so is an +** SQLITE_MISUSE error. +** +** The changegroup object passed as the first argument must be already +** configured with schema data for the specified table. It may be configured +** either by calling sqlite3changegroup_schema() with a database that contains +** the table, or sqlite3changegroup_add() with a changeset that contains the +** table. If the changegroup object has not been configured with a schema for +** the specified table when this function is called, SQLITE_ERROR is returned. +** +** If successful, SQLITE_OK is returned. Otherwise, if an error occurs, an +** SQLite error code is returned. In this case, if argument pzErr is non-NULL, +** then (*pzErr) may be set to point to a buffer containing a utf-8 formated, +** nul-terminated, English language error message. It is the responsibility +** of the caller to eventually free this buffer using sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_change_begin( + sqlite3_changegroup*, + int eOp, + const char *zTab, + int bIndirect, + char **pzErr +); + +/* +** CAPI3REF: Add a 64-bit integer to a changegroup +** +** This function may only be called between a successful call to +** sqlite3changegroup_change_begin() and its matching +** sqlite3changegroup_change_finish() call. If it is called at any +** other time, it is an SQLITE_MISUSE error. Calling this function +** specifies a 64-bit integer value to be used in the change currently being +** added to the changegroup object passed as the first argument. +** +** The second parameter, bNew, specifies whether the value is to be part of +** the new.* (if bNew is non-zero) or old.* (if bNew is zero) record of +** the change under construction. If this does not match the type of change +** specified by the preceding call to sqlite3changegroup_change_begin() (i.e. +** an old.* value for an SQLITE_INSERT change, or a new.* value for an +** SQLITE_DELETE), then SQLITE_ERROR is returned. +** +** The third parameter specifies the column of the old.* or new.* record that +** the value will be a part of. If the specified table has an explicit primary +** key, then this is the index of the table column, numbered from 0 in the order +** specified within the CREATE TABLE statement. Or, if the table uses an +** implicit rowid key, then the column 0 is the rowid and the explicit columns +** are numbered starting from 1. If the iCol parameter is less than 0 or greater +** than the index of the last column in the table, SQLITE_RANGE is returned. +** +** The fourth parameter is the integer value to use as part of the old.* or +** new.* record. +** +** If this call is successful, SQLITE_OK is returned. Otherwise, if an +** error occurs, an SQLite error code is returned. +*/ +SQLITE_API int sqlite3changegroup_change_int64( + sqlite3_changegroup*, + int bNew, + int iCol, + sqlite3_int64 iVal +); + +/* +** CAPI3REF: Add a NULL to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). Except that +** it configures the change currently under construction with a NULL value +** instead of a 64-bit integer. +*/ +SQLITE_API int sqlite3changegroup_change_null(sqlite3_changegroup*, int, int); + +/* +** CAPI3REF: Add an double to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). Except that +** it configures the change currently being constructed with a real value +** instead of a 64-bit integer. +*/ +SQLITE_API int sqlite3changegroup_change_double(sqlite3_changegroup*, int, int, double); + +/* +** CAPI3REF: Add a text value to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). It configures +** the currently accumulated change with a text value instead of a 64-bit +** integer. Parameter pVal points to a buffer containing the text encoded using +** utf-8. Parameter nVal may either be the size of the text value in bytes, or +** else a negative value, in which case the buffer pVal points to is assumed to +** be nul-terminated. +*/ +SQLITE_API int sqlite3changegroup_change_text( + sqlite3_changegroup*, int, int, const char *pVal, int nVal +); + +/* +** CAPI3REF: Add a blob to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). It configures +** the currently accumulated change with a blob value instead of a 64-bit +** integer. Parameter pVal points to a buffer containing the blob. Parameter +** nVal is the size of the blob in bytes. +*/ +SQLITE_API int sqlite3changegroup_change_blob( + sqlite3_changegroup*, int, int, const void *pVal, int nVal +); + +/* +** CAPI3REF: Finish adding one-at-at-time changes to a changegroup +** +** This function may only be called following a successful call to +** sqlite3changegroup_change_begin(). Otherwise, it is an SQLITE_MISUSE error. +** +** If parameter bDiscard is non-zero, then the current change is simply +** discarded. In this case this function is always successful and SQLITE_OK +** returned. +** +** If parameter bDiscard is zero, then an attempt is made to add the current +** change to the changegroup. Assuming the changegroup is configured to +** produce a changeset (not a patchset), this requires that: +** +** * If the change is an INSERT or DELETE, then a value must be specified +** for all columns of the new.* or old.* record, respectively. +** +** * If the change is an UPDATE record, then values must be provided for +** the PRIMARY KEY columns of the old.* record, but must not be provided +** for PRIMARY KEY columns of the new.* record. +** +** * If the change is an UPDATE record, then for each non-PRIMARY KEY +** column in the old.* record for which a value has been provided, a +** value must also be provided for the same column in the new.* record. +** Similarly, for each non-PK column in the old.* record for which +** a value is not provided, a value must not be provided for the same +** column in the new.* record. +** +** * All values specified for PRIMARY KEY columns must be non-NULL. +** +** Otherwise, it is an error. +** +** If the changegroup already contains a change for the same row (identified +** by PRIMARY KEY columns), then the current change is combined with the +** existing change in the same way as for sqlite3changegroup_add(). +** +** For a patchset, all of the above rules apply except that it doesn't matter +** whether or not values are provided for the non-PK old.* record columns +** for an UPDATE or DELETE change. This means that code used to produce +** a changeset using the sqlite3changegroup_change_xxx() APIs may also +** be used to produce patchsets. +** +** If the call is successful, SQLITE_OK is returned. Otherwise, if an error +** occurs, an SQLite error code is returned. If an error is returned and +** parameter pzErr is not NULL, then (*pzErr) may be set to point to a buffer +** containing a nul-terminated, utf-8 encoded, English language error message. +** It is the responsibility of the caller to eventually free any such error +** message buffer using sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_change_finish( + sqlite3_changegroup*, + int bDiscard, + char **pzErr +); + /* ** Make sure we can call this stuff from C++. */ @@ -13177,14 +13936,29 @@ struct Fts5PhraseIter { ** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, ** output variable (*ppToken) is set to point to a buffer containing the ** matching document token, and (*pnToken) to the size of that buffer in -** bytes. This API is not available if the specified token matches a -** prefix query term. In that case both output variables are always set -** to 0. +** bytes. ** ** The output text is not a copy of the document text that was tokenized. ** It is the output of the tokenizer module. For tokendata=1 tables, this ** includes any embedded 0x00 and trailing data. ** +** This API may be slow in some cases if the token identified by parameters +** iIdx and iToken matched a prefix token in the query. In most cases, the +** first call to this API for each prefix token in the query is forced +** to scan the portion of the full-text index that matches the prefix +** token to collect the extra data required by this API. If the prefix +** token matches a large number of token instances in the document set, +** this may be a performance problem. +** +** If the user knows in advance that a query may use this API for a +** prefix token, FTS5 may be configured to collect all required data as part +** of the initial querying of the full-text index, avoiding the second scan +** entirely. This also causes prefix queries that do not use this API to +** run more slowly and use more memory. FTS5 may be configured in this way +** either on a per-table basis using the [FTS5 insttoken | 'insttoken'] +** option, or on a per-query basis using the +** [fts5_insttoken | fts5_insttoken()] user function. +** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. ** @@ -13618,110 +14392,12 @@ struct fts5_api { #endif /* _FTS5_H */ /******** End of fts5.h *********/ +#endif /* SQLITE3_H */ /*** End of #include "sqlite3.h" ***/ #ifdef SQLITE_USER_AUTHENTICATION -/* #include "sqlite3userauth.h" */ -/*** Begin of #include "sqlite3userauth.h" ***/ -/* -** 2014-09-08 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -** This file contains the application interface definitions for the -** user-authentication extension feature. -** -** To compile with the user-authentication feature, append this file to -** end of an SQLite amalgamation header file ("sqlite3.h"), then add -** the SQLITE_USER_AUTHENTICATION compile-time option. See the -** user-auth.txt file in the same source directory as this file for -** additional information. -*/ -#ifdef SQLITE_USER_AUTHENTICATION - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** If a database contains the SQLITE_USER table, then the -** sqlite3_user_authenticate() interface must be invoked with an -** appropriate username and password prior to enable read and write -** access to the database. -** -** Return SQLITE_OK on success or SQLITE_ERROR if the username/password -** combination is incorrect or unknown. -** -** If the SQLITE_USER table is not present in the database file, then -** this interface is a harmless no-op returnning SQLITE_OK. -*/ -SQLITE_API int sqlite3_user_authenticate( - sqlite3 *db, /* The database connection */ - const char *zUsername, /* Username */ - const char *aPW, /* Password or credentials */ - int nPW /* Number of bytes in aPW[] */ -); - -/* -** The sqlite3_user_add() interface can be used (by an admin user only) -** to create a new user. When called on a no-authentication-required -** database, this routine converts the database into an authentication- -** required database, automatically makes the added user an -** administrator, and logs in the current connection as that user. -** The sqlite3_user_add() interface only works for the "main" database, not -** for any ATTACH-ed databases. Any call to sqlite3_user_add() by a -** non-admin user results in an error. -*/ -SQLITE_API int sqlite3_user_add( - sqlite3 *db, /* Database connection */ - const char *zUsername, /* Username to be added */ - const char *aPW, /* Password or credentials */ - int nPW, /* Number of bytes in aPW[] */ - int isAdmin /* True to give new user admin privilege */ -); - -/* -** The sqlite3_user_change() interface can be used to change a users -** login credentials or admin privilege. Any user can change their own -** login credentials. Only an admin user can change another users login -** credentials or admin privilege setting. No user may change their own -** admin privilege setting. -*/ -SQLITE_API int sqlite3_user_change( - sqlite3 *db, /* Database connection */ - const char *zUsername, /* Username to change */ - const char *aPW, /* New password or credentials */ - int nPW, /* Number of bytes in aPW[] */ - int isAdmin /* Modified admin privilege for the user */ -); - -/* -** The sqlite3_user_delete() interface can be used (by an admin user only) -** to delete a user. The currently logged-in user cannot be deleted, -** which guarantees that there is always an admin user and hence that -** the database cannot be converted into a no-authentication-required -** database. -*/ -SQLITE_API int sqlite3_user_delete( - sqlite3 *db, /* Database connection */ - const char *zUsername /* Username to remove */ -); - -#ifdef __cplusplus -} /* end of the 'extern "C"' block */ -#endif - -#endif /* SQLITE_USER_AUTHENTICATION */ -/*** End of #include "sqlite3userauth.h" ***/ - +#undef SQLITE_USER_AUTHENTICATION #endif /* @@ -13734,7 +14410,8 @@ SQLITE_API int sqlite3_user_delete( #define CODEC_TYPE_SQLCIPHER 4 #define CODEC_TYPE_RC4 5 #define CODEC_TYPE_ASCON128 6 -#define CODEC_TYPE_MAX_BUILTIN 6 +#define CODEC_TYPE_AEGIS 7 +#define CODEC_TYPE_MAX_BUILTIN 7 /* ** Definition of API functions @@ -13806,6 +14483,7 @@ SQLITE_API void sqlite3_activate_see(const char* zPassPhrase); SQLITE_API int sqlite3mc_cipher_count(); SQLITE_API int sqlite3mc_cipher_index(const char* cipherName); SQLITE_API const char* sqlite3mc_cipher_name(int cipherIndex); +SQLITE_API int sqlite3mc_cipher_name_copy(int cipherIndex, char* cipherName, int maxCipherNameSize); SQLITE_API int sqlite3mc_config(sqlite3* db, const char* paramName, int newValue); SQLITE_API int sqlite3mc_config_cipher(sqlite3* db, const char* cipherName, const char* paramName, int newValue); SQLITE_API unsigned char* sqlite3mc_codec_data(sqlite3* db, const char* zDbName, const char* paramName); @@ -13941,4 +14619,930 @@ SQLITE_API void sqlite3mc_vfs_shutdown(); /*** End of #include "sqlite3mc_vfs.h" ***/ +/* +** Dispatch table support +*/ + +#ifdef SQLITE3MC_USE_DISPATCH_TABLE + +/* +** Instead of making the SQLite symbols public dispatch tables can be +** used. In that case only the pointers to the dispatch tables are +** made public, hiding all other SQLite symbols. This is useful for +** modules which want to use an embedded SQLite version without +** conflicts with other SQLite implementation. +** +** The only rule to obey is that such an embedded SQLite instance +** should not access the same database files as a separate SQLite +** instance within the same process, because that could lead to +** database corruption. +** +** Define symbol SQLITE3MC_USE_DISPATCH_TABLE to activate the use of +** dispatch tables. +** +** Define symbol SQLITE3MC_API_TABLE_PREFIX to specify your own +** global symbols for the dispatch tables to avoid name clashes. +** +** Example: #define SQLITE3MC_API_TABLE_PREFIX MyApplication +** +** The default prefix is "sqlite3mc". +*/ + +#ifndef SQLITE3MC_API_TABLE_PREFIX +#define SQLITE3MC_API_TABLE_PREFIX sqlite3mc #endif + +#define SQLITE3MC_CONCAT(A,B) SQLITE3MC_CONCAT_(A,B) +#define SQLITE3MC_CONCAT_(A,B) A##B +#define SQLITE3MC_API_TABLE(name) SQLITE3MC_CONCAT(SQLITE3MC_API_TABLE_PREFIX,SQLITE3MC_CONCAT(_,name)) + +#define SQLITE3MC_API_TABLE_EXT SQLITE3MC_API_TABLE(api_ext) +#define SQLITE3MC_API_TABLE_CORE SQLITE3MC_API_TABLE(api_core) +#define SQLITE3MC_API_TABLE_MC SQLITE3MC_API_TABLE(api_mc) + +/* Define the dispatch table name for sqlite3ext.h */ +#define sqlite3_api SQLITE3MC_API_TABLE_EXT + +/* #include "sqlite3ext.h" */ +/*** Begin of #include "sqlite3ext.h" ***/ +/* +** 2006 June 7 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This header file defines the SQLite interface for use by +** shared libraries that want to be imported as extensions into +** an SQLite instance. Shared libraries that intend to be loaded +** as extensions by SQLite should #include this file instead of +** sqlite3.h. +*/ +#ifndef SQLITE3EXT_H +#define SQLITE3EXT_H +/* #include "sqlite3.h" */ + + +/* +** The following structure holds pointers to all of the SQLite API +** routines. +** +** WARNING: In order to maintain backwards compatibility, add new +** interfaces to the end of this structure only. If you insert new +** interfaces in the middle of this structure, then older different +** versions of SQLite will not be able to load each other's shared +** libraries! +*/ +struct sqlite3_api_routines { + void * (*aggregate_context)(sqlite3_context*,int nBytes); + int (*aggregate_count)(sqlite3_context*); + int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); + int (*bind_double)(sqlite3_stmt*,int,double); + int (*bind_int)(sqlite3_stmt*,int,int); + int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64); + int (*bind_null)(sqlite3_stmt*,int); + int (*bind_parameter_count)(sqlite3_stmt*); + int (*bind_parameter_index)(sqlite3_stmt*,const char*zName); + const char * (*bind_parameter_name)(sqlite3_stmt*,int); + int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); + int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*)); + int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*); + int (*busy_handler)(sqlite3*,int(*)(void*,int),void*); + int (*busy_timeout)(sqlite3*,int ms); + int (*changes)(sqlite3*); + int (*close)(sqlite3*); + int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*, + int eTextRep,const char*)); + int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*, + int eTextRep,const void*)); + const void * (*column_blob)(sqlite3_stmt*,int iCol); + int (*column_bytes)(sqlite3_stmt*,int iCol); + int (*column_bytes16)(sqlite3_stmt*,int iCol); + int (*column_count)(sqlite3_stmt*pStmt); + const char * (*column_database_name)(sqlite3_stmt*,int); + const void * (*column_database_name16)(sqlite3_stmt*,int); + const char * (*column_decltype)(sqlite3_stmt*,int i); + const void * (*column_decltype16)(sqlite3_stmt*,int); + double (*column_double)(sqlite3_stmt*,int iCol); + int (*column_int)(sqlite3_stmt*,int iCol); + sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol); + const char * (*column_name)(sqlite3_stmt*,int); + const void * (*column_name16)(sqlite3_stmt*,int); + const char * (*column_origin_name)(sqlite3_stmt*,int); + const void * (*column_origin_name16)(sqlite3_stmt*,int); + const char * (*column_table_name)(sqlite3_stmt*,int); + const void * (*column_table_name16)(sqlite3_stmt*,int); + const unsigned char * (*column_text)(sqlite3_stmt*,int iCol); + const void * (*column_text16)(sqlite3_stmt*,int iCol); + int (*column_type)(sqlite3_stmt*,int iCol); + sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol); + void * (*commit_hook)(sqlite3*,int(*)(void*),void*); + int (*complete)(const char*sql); + int (*complete16)(const void*sql); + int (*create_collation)(sqlite3*,const char*,int,void*, + int(*)(void*,int,const void*,int,const void*)); + int (*create_collation16)(sqlite3*,const void*,int,void*, + int(*)(void*,int,const void*,int,const void*)); + int (*create_function)(sqlite3*,const char*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*)); + int (*create_function16)(sqlite3*,const void*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*)); + int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); + int (*data_count)(sqlite3_stmt*pStmt); + sqlite3 * (*db_handle)(sqlite3_stmt*); + int (*declare_vtab)(sqlite3*,const char*); + int (*enable_shared_cache)(int); + int (*errcode)(sqlite3*db); + const char * (*errmsg)(sqlite3*); + const void * (*errmsg16)(sqlite3*); + int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); + int (*expired)(sqlite3_stmt*); + int (*finalize)(sqlite3_stmt*pStmt); + void (*free)(void*); + void (*free_table)(char**result); + int (*get_autocommit)(sqlite3*); + void * (*get_auxdata)(sqlite3_context*,int); + int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); + int (*global_recover)(void); + void (*interruptx)(sqlite3*); + sqlite_int64 (*last_insert_rowid)(sqlite3*); + const char * (*libversion)(void); + int (*libversion_number)(void); + void *(*malloc)(int); + char * (*mprintf)(const char*,...); + int (*open)(const char*,sqlite3**); + int (*open16)(const void*,sqlite3**); + int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); + int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); + void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*); + void (*progress_handler)(sqlite3*,int,int(*)(void*),void*); + void *(*realloc)(void*,int); + int (*reset)(sqlite3_stmt*pStmt); + void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_double)(sqlite3_context*,double); + void (*result_error)(sqlite3_context*,const char*,int); + void (*result_error16)(sqlite3_context*,const void*,int); + void (*result_int)(sqlite3_context*,int); + void (*result_int64)(sqlite3_context*,sqlite_int64); + void (*result_null)(sqlite3_context*); + void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*)); + void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_value)(sqlite3_context*,sqlite3_value*); + void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); + int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, + const char*,const char*),void*); + void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); + char * (*xsnprintf)(int,char*,const char*,...); + int (*step)(sqlite3_stmt*); + int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, + char const**,char const**,int*,int*,int*); + void (*thread_cleanup)(void); + int (*total_changes)(sqlite3*); + void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); + int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); + void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*, + sqlite_int64),void*); + void * (*user_data)(sqlite3_context*); + const void * (*value_blob)(sqlite3_value*); + int (*value_bytes)(sqlite3_value*); + int (*value_bytes16)(sqlite3_value*); + double (*value_double)(sqlite3_value*); + int (*value_int)(sqlite3_value*); + sqlite_int64 (*value_int64)(sqlite3_value*); + int (*value_numeric_type)(sqlite3_value*); + const unsigned char * (*value_text)(sqlite3_value*); + const void * (*value_text16)(sqlite3_value*); + const void * (*value_text16be)(sqlite3_value*); + const void * (*value_text16le)(sqlite3_value*); + int (*value_type)(sqlite3_value*); + char *(*vmprintf)(const char*,va_list); + /* Added ??? */ + int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); + /* Added by 3.3.13 */ + int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); + int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); + int (*clear_bindings)(sqlite3_stmt*); + /* Added by 3.4.1 */ + int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*, + void (*xDestroy)(void *)); + /* Added by 3.5.0 */ + int (*bind_zeroblob)(sqlite3_stmt*,int,int); + int (*blob_bytes)(sqlite3_blob*); + int (*blob_close)(sqlite3_blob*); + int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64, + int,sqlite3_blob**); + int (*blob_read)(sqlite3_blob*,void*,int,int); + int (*blob_write)(sqlite3_blob*,const void*,int,int); + int (*create_collation_v2)(sqlite3*,const char*,int,void*, + int(*)(void*,int,const void*,int,const void*), + void(*)(void*)); + int (*file_control)(sqlite3*,const char*,int,void*); + sqlite3_int64 (*memory_highwater)(int); + sqlite3_int64 (*memory_used)(void); + sqlite3_mutex *(*mutex_alloc)(int); + void (*mutex_enter)(sqlite3_mutex*); + void (*mutex_free)(sqlite3_mutex*); + void (*mutex_leave)(sqlite3_mutex*); + int (*mutex_try)(sqlite3_mutex*); + int (*open_v2)(const char*,sqlite3**,int,const char*); + int (*release_memory)(int); + void (*result_error_nomem)(sqlite3_context*); + void (*result_error_toobig)(sqlite3_context*); + int (*sleep)(int); + void (*soft_heap_limit)(int); + sqlite3_vfs *(*vfs_find)(const char*); + int (*vfs_register)(sqlite3_vfs*,int); + int (*vfs_unregister)(sqlite3_vfs*); + int (*xthreadsafe)(void); + void (*result_zeroblob)(sqlite3_context*,int); + void (*result_error_code)(sqlite3_context*,int); + int (*test_control)(int, ...); + void (*randomness)(int,void*); + sqlite3 *(*context_db_handle)(sqlite3_context*); + int (*extended_result_codes)(sqlite3*,int); + int (*limit)(sqlite3*,int,int); + sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*); + const char *(*sql)(sqlite3_stmt*); + int (*status)(int,int*,int*,int); + int (*backup_finish)(sqlite3_backup*); + sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*); + int (*backup_pagecount)(sqlite3_backup*); + int (*backup_remaining)(sqlite3_backup*); + int (*backup_step)(sqlite3_backup*,int); + const char *(*compileoption_get)(int); + int (*compileoption_used)(const char*); + int (*create_function_v2)(sqlite3*,const char*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void(*xDestroy)(void*)); + int (*db_config)(sqlite3*,int,...); + sqlite3_mutex *(*db_mutex)(sqlite3*); + int (*db_status)(sqlite3*,int,int*,int*,int); + int (*extended_errcode)(sqlite3*); + void (*log)(int,const char*,...); + sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); + const char *(*sourceid)(void); + int (*stmt_status)(sqlite3_stmt*,int,int); + int (*strnicmp)(const char*,const char*,int); + int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); + int (*wal_autocheckpoint)(sqlite3*,int); + int (*wal_checkpoint)(sqlite3*,const char*); + void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); + int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); + int (*vtab_config)(sqlite3*,int op,...); + int (*vtab_on_conflict)(sqlite3*); + /* Version 3.7.16 and later */ + int (*close_v2)(sqlite3*); + const char *(*db_filename)(sqlite3*,const char*); + int (*db_readonly)(sqlite3*,const char*); + int (*db_release_memory)(sqlite3*); + const char *(*errstr)(int); + int (*stmt_busy)(sqlite3_stmt*); + int (*stmt_readonly)(sqlite3_stmt*); + int (*stricmp)(const char*,const char*); + int (*uri_boolean)(const char*,const char*,int); + sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); + const char *(*uri_parameter)(const char*,const char*); + char *(*xvsnprintf)(int,char*,const char*,va_list); + int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); + /* Version 3.8.7 and later */ + int (*auto_extension)(void(*)(void)); + int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, + void(*)(void*)); + int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, + void(*)(void*),unsigned char); + int (*cancel_auto_extension)(void(*)(void)); + int (*load_extension)(sqlite3*,const char*,const char*,char**); + void *(*malloc64)(sqlite3_uint64); + sqlite3_uint64 (*msize)(void*); + void *(*realloc64)(void*,sqlite3_uint64); + void (*reset_auto_extension)(void); + void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, + void(*)(void*)); + void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, + void(*)(void*), unsigned char); + int (*strglob)(const char*,const char*); + /* Version 3.8.11 and later */ + sqlite3_value *(*value_dup)(const sqlite3_value*); + void (*value_free)(sqlite3_value*); + int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64); + int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64); + /* Version 3.9.0 and later */ + unsigned int (*value_subtype)(sqlite3_value*); + void (*result_subtype)(sqlite3_context*,unsigned int); + /* Version 3.10.0 and later */ + int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); + int (*strlike)(const char*,const char*,unsigned int); + int (*db_cacheflush)(sqlite3*); + /* Version 3.12.0 and later */ + int (*system_errno)(sqlite3*); + /* Version 3.14.0 and later */ + int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); + char *(*expanded_sql)(sqlite3_stmt*); + /* Version 3.18.0 and later */ + void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); + /* Version 3.20.0 and later */ + int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, + sqlite3_stmt**,const char**); + int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, + sqlite3_stmt**,const void**); + int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); + void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); + void *(*value_pointer)(sqlite3_value*,const char*); + int (*vtab_nochange)(sqlite3_context*); + int (*value_nochange)(sqlite3_value*); + const char *(*vtab_collation)(sqlite3_index_info*,int); + /* Version 3.24.0 and later */ + int (*keyword_count)(void); + int (*keyword_name)(int,const char**,int*); + int (*keyword_check)(const char*,int); + sqlite3_str *(*str_new)(sqlite3*); + char *(*str_finish)(sqlite3_str*); + void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); + void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); + void (*str_append)(sqlite3_str*, const char *zIn, int N); + void (*str_appendall)(sqlite3_str*, const char *zIn); + void (*str_appendchar)(sqlite3_str*, int N, char C); + void (*str_reset)(sqlite3_str*); + int (*str_errcode)(sqlite3_str*); + int (*str_length)(sqlite3_str*); + char *(*str_value)(sqlite3_str*); + /* Version 3.25.0 and later */ + int (*create_window_function)(sqlite3*,const char*,int,int,void*, + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInv)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*)); + /* Version 3.26.0 and later */ + const char *(*normalized_sql)(sqlite3_stmt*); + /* Version 3.28.0 and later */ + int (*stmt_isexplain)(sqlite3_stmt*); + int (*value_frombind)(sqlite3_value*); + /* Version 3.30.0 and later */ + int (*drop_modules)(sqlite3*,const char**); + /* Version 3.31.0 and later */ + sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64); + const char *(*uri_key)(const char*,int); + const char *(*filename_database)(const char*); + const char *(*filename_journal)(const char*); + const char *(*filename_wal)(const char*); + /* Version 3.32.0 and later */ + const char *(*create_filename)(const char*,const char*,const char*, + int,const char**); + void (*free_filename)(const char*); + sqlite3_file *(*database_file_object)(const char*); + /* Version 3.34.0 and later */ + int (*txn_state)(sqlite3*,const char*); + /* Version 3.36.1 and later */ + sqlite3_int64 (*changes64)(sqlite3*); + sqlite3_int64 (*total_changes64)(sqlite3*); + /* Version 3.37.0 and later */ + int (*autovacuum_pages)(sqlite3*, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, void(*)(void*)); + /* Version 3.38.0 and later */ + int (*error_offset)(sqlite3*); + int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**); + int (*vtab_distinct)(sqlite3_index_info*); + int (*vtab_in)(sqlite3_index_info*,int,int); + int (*vtab_in_first)(sqlite3_value*,sqlite3_value**); + int (*vtab_in_next)(sqlite3_value*,sqlite3_value**); + /* Version 3.39.0 and later */ + int (*deserialize)(sqlite3*,const char*,unsigned char*, + sqlite3_int64,sqlite3_int64,unsigned); + unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*, + unsigned int); + const char *(*db_name)(sqlite3*,int); + /* Version 3.40.0 and later */ + int (*value_encoding)(sqlite3_value*); + /* Version 3.41.0 and later */ + int (*is_interrupted)(sqlite3*); + /* Version 3.43.0 and later */ + int (*stmt_explain)(sqlite3_stmt*,int); + /* Version 3.44.0 and later */ + void *(*get_clientdata)(sqlite3*,const char*); + int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*)); + /* Version 3.50.0 and later */ + int (*setlk_timeout)(sqlite3*,int,int); + /* Version 3.51.0 and later */ + int (*set_errmsg)(sqlite3*,int,const char*); + int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int); + /* Version 3.52.0 and later */ + void (*str_truncate)(sqlite3_str*,int); + void (*str_free)(sqlite3_str*); + int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*)); + int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*); +}; + +/* +** This is the function signature used for all extension entry points. It +** is also defined in the file "loadext.c". +*/ +typedef int (*sqlite3_loadext_entry)( + sqlite3 *db, /* Handle to the database. */ + char **pzErrMsg, /* Used to set error string on failure. */ + const sqlite3_api_routines *pThunk /* Extension API function pointers. */ +); + +/* +** The following macros redefine the API routines so that they are +** redirected through the global sqlite3_api structure. +** +** This header file is also used by the loadext.c source file +** (part of the main SQLite library - not an extension) so that +** it can get access to the sqlite3_api_routines structure +** definition. But the main library does not want to redefine +** the API. So the redefinition macros are only valid if the +** SQLITE_CORE macros is undefined. +*/ +#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) +#define sqlite3_aggregate_context sqlite3_api->aggregate_context +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_aggregate_count sqlite3_api->aggregate_count +#endif +#define sqlite3_bind_blob sqlite3_api->bind_blob +#define sqlite3_bind_double sqlite3_api->bind_double +#define sqlite3_bind_int sqlite3_api->bind_int +#define sqlite3_bind_int64 sqlite3_api->bind_int64 +#define sqlite3_bind_null sqlite3_api->bind_null +#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count +#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index +#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name +#define sqlite3_bind_text sqlite3_api->bind_text +#define sqlite3_bind_text16 sqlite3_api->bind_text16 +#define sqlite3_bind_value sqlite3_api->bind_value +#define sqlite3_busy_handler sqlite3_api->busy_handler +#define sqlite3_busy_timeout sqlite3_api->busy_timeout +#define sqlite3_changes sqlite3_api->changes +#define sqlite3_close sqlite3_api->close +#define sqlite3_collation_needed sqlite3_api->collation_needed +#define sqlite3_collation_needed16 sqlite3_api->collation_needed16 +#define sqlite3_column_blob sqlite3_api->column_blob +#define sqlite3_column_bytes sqlite3_api->column_bytes +#define sqlite3_column_bytes16 sqlite3_api->column_bytes16 +#define sqlite3_column_count sqlite3_api->column_count +#define sqlite3_column_database_name sqlite3_api->column_database_name +#define sqlite3_column_database_name16 sqlite3_api->column_database_name16 +#define sqlite3_column_decltype sqlite3_api->column_decltype +#define sqlite3_column_decltype16 sqlite3_api->column_decltype16 +#define sqlite3_column_double sqlite3_api->column_double +#define sqlite3_column_int sqlite3_api->column_int +#define sqlite3_column_int64 sqlite3_api->column_int64 +#define sqlite3_column_name sqlite3_api->column_name +#define sqlite3_column_name16 sqlite3_api->column_name16 +#define sqlite3_column_origin_name sqlite3_api->column_origin_name +#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16 +#define sqlite3_column_table_name sqlite3_api->column_table_name +#define sqlite3_column_table_name16 sqlite3_api->column_table_name16 +#define sqlite3_column_text sqlite3_api->column_text +#define sqlite3_column_text16 sqlite3_api->column_text16 +#define sqlite3_column_type sqlite3_api->column_type +#define sqlite3_column_value sqlite3_api->column_value +#define sqlite3_commit_hook sqlite3_api->commit_hook +#define sqlite3_complete sqlite3_api->complete +#define sqlite3_complete16 sqlite3_api->complete16 +#define sqlite3_create_collation sqlite3_api->create_collation +#define sqlite3_create_collation16 sqlite3_api->create_collation16 +#define sqlite3_create_function sqlite3_api->create_function +#define sqlite3_create_function16 sqlite3_api->create_function16 +#define sqlite3_create_module sqlite3_api->create_module +#define sqlite3_create_module_v2 sqlite3_api->create_module_v2 +#define sqlite3_data_count sqlite3_api->data_count +#define sqlite3_db_handle sqlite3_api->db_handle +#define sqlite3_declare_vtab sqlite3_api->declare_vtab +#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache +#define sqlite3_errcode sqlite3_api->errcode +#define sqlite3_errmsg sqlite3_api->errmsg +#define sqlite3_errmsg16 sqlite3_api->errmsg16 +#define sqlite3_exec sqlite3_api->exec +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_expired sqlite3_api->expired +#endif +#define sqlite3_finalize sqlite3_api->finalize +#define sqlite3_free sqlite3_api->free +#define sqlite3_free_table sqlite3_api->free_table +#define sqlite3_get_autocommit sqlite3_api->get_autocommit +#define sqlite3_get_auxdata sqlite3_api->get_auxdata +#define sqlite3_get_table sqlite3_api->get_table +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_global_recover sqlite3_api->global_recover +#endif +#define sqlite3_interrupt sqlite3_api->interruptx +#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid +#define sqlite3_libversion sqlite3_api->libversion +#define sqlite3_libversion_number sqlite3_api->libversion_number +#define sqlite3_malloc sqlite3_api->malloc +#define sqlite3_mprintf sqlite3_api->mprintf +#define sqlite3_open sqlite3_api->open +#define sqlite3_open16 sqlite3_api->open16 +#define sqlite3_prepare sqlite3_api->prepare +#define sqlite3_prepare16 sqlite3_api->prepare16 +#define sqlite3_prepare_v2 sqlite3_api->prepare_v2 +#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 +#define sqlite3_profile sqlite3_api->profile +#define sqlite3_progress_handler sqlite3_api->progress_handler +#define sqlite3_realloc sqlite3_api->realloc +#define sqlite3_reset sqlite3_api->reset +#define sqlite3_result_blob sqlite3_api->result_blob +#define sqlite3_result_double sqlite3_api->result_double +#define sqlite3_result_error sqlite3_api->result_error +#define sqlite3_result_error16 sqlite3_api->result_error16 +#define sqlite3_result_int sqlite3_api->result_int +#define sqlite3_result_int64 sqlite3_api->result_int64 +#define sqlite3_result_null sqlite3_api->result_null +#define sqlite3_result_text sqlite3_api->result_text +#define sqlite3_result_text16 sqlite3_api->result_text16 +#define sqlite3_result_text16be sqlite3_api->result_text16be +#define sqlite3_result_text16le sqlite3_api->result_text16le +#define sqlite3_result_value sqlite3_api->result_value +#define sqlite3_rollback_hook sqlite3_api->rollback_hook +#define sqlite3_set_authorizer sqlite3_api->set_authorizer +#define sqlite3_set_auxdata sqlite3_api->set_auxdata +#define sqlite3_snprintf sqlite3_api->xsnprintf +#define sqlite3_step sqlite3_api->step +#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata +#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup +#define sqlite3_total_changes sqlite3_api->total_changes +#define sqlite3_trace sqlite3_api->trace +#ifndef SQLITE_OMIT_DEPRECATED +#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings +#endif +#define sqlite3_update_hook sqlite3_api->update_hook +#define sqlite3_user_data sqlite3_api->user_data +#define sqlite3_value_blob sqlite3_api->value_blob +#define sqlite3_value_bytes sqlite3_api->value_bytes +#define sqlite3_value_bytes16 sqlite3_api->value_bytes16 +#define sqlite3_value_double sqlite3_api->value_double +#define sqlite3_value_int sqlite3_api->value_int +#define sqlite3_value_int64 sqlite3_api->value_int64 +#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type +#define sqlite3_value_text sqlite3_api->value_text +#define sqlite3_value_text16 sqlite3_api->value_text16 +#define sqlite3_value_text16be sqlite3_api->value_text16be +#define sqlite3_value_text16le sqlite3_api->value_text16le +#define sqlite3_value_type sqlite3_api->value_type +#define sqlite3_vmprintf sqlite3_api->vmprintf +#define sqlite3_vsnprintf sqlite3_api->xvsnprintf +#define sqlite3_overload_function sqlite3_api->overload_function +#define sqlite3_prepare_v2 sqlite3_api->prepare_v2 +#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 +#define sqlite3_clear_bindings sqlite3_api->clear_bindings +#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob +#define sqlite3_blob_bytes sqlite3_api->blob_bytes +#define sqlite3_blob_close sqlite3_api->blob_close +#define sqlite3_blob_open sqlite3_api->blob_open +#define sqlite3_blob_read sqlite3_api->blob_read +#define sqlite3_blob_write sqlite3_api->blob_write +#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2 +#define sqlite3_file_control sqlite3_api->file_control +#define sqlite3_memory_highwater sqlite3_api->memory_highwater +#define sqlite3_memory_used sqlite3_api->memory_used +#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc +#define sqlite3_mutex_enter sqlite3_api->mutex_enter +#define sqlite3_mutex_free sqlite3_api->mutex_free +#define sqlite3_mutex_leave sqlite3_api->mutex_leave +#define sqlite3_mutex_try sqlite3_api->mutex_try +#define sqlite3_open_v2 sqlite3_api->open_v2 +#define sqlite3_release_memory sqlite3_api->release_memory +#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem +#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig +#define sqlite3_sleep sqlite3_api->sleep +#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit +#define sqlite3_vfs_find sqlite3_api->vfs_find +#define sqlite3_vfs_register sqlite3_api->vfs_register +#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister +#define sqlite3_threadsafe sqlite3_api->xthreadsafe +#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob +#define sqlite3_result_error_code sqlite3_api->result_error_code +#define sqlite3_test_control sqlite3_api->test_control +#define sqlite3_randomness sqlite3_api->randomness +#define sqlite3_context_db_handle sqlite3_api->context_db_handle +#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes +#define sqlite3_limit sqlite3_api->limit +#define sqlite3_next_stmt sqlite3_api->next_stmt +#define sqlite3_sql sqlite3_api->sql +#define sqlite3_status sqlite3_api->status +#define sqlite3_backup_finish sqlite3_api->backup_finish +#define sqlite3_backup_init sqlite3_api->backup_init +#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount +#define sqlite3_backup_remaining sqlite3_api->backup_remaining +#define sqlite3_backup_step sqlite3_api->backup_step +#define sqlite3_compileoption_get sqlite3_api->compileoption_get +#define sqlite3_compileoption_used sqlite3_api->compileoption_used +#define sqlite3_create_function_v2 sqlite3_api->create_function_v2 +#define sqlite3_db_config sqlite3_api->db_config +#define sqlite3_db_mutex sqlite3_api->db_mutex +#define sqlite3_db_status sqlite3_api->db_status +#define sqlite3_extended_errcode sqlite3_api->extended_errcode +#define sqlite3_log sqlite3_api->log +#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64 +#define sqlite3_sourceid sqlite3_api->sourceid +#define sqlite3_stmt_status sqlite3_api->stmt_status +#define sqlite3_strnicmp sqlite3_api->strnicmp +#define sqlite3_unlock_notify sqlite3_api->unlock_notify +#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint +#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint +#define sqlite3_wal_hook sqlite3_api->wal_hook +#define sqlite3_blob_reopen sqlite3_api->blob_reopen +#define sqlite3_vtab_config sqlite3_api->vtab_config +#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict +/* Version 3.7.16 and later */ +#define sqlite3_close_v2 sqlite3_api->close_v2 +#define sqlite3_db_filename sqlite3_api->db_filename +#define sqlite3_db_readonly sqlite3_api->db_readonly +#define sqlite3_db_release_memory sqlite3_api->db_release_memory +#define sqlite3_errstr sqlite3_api->errstr +#define sqlite3_stmt_busy sqlite3_api->stmt_busy +#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly +#define sqlite3_stricmp sqlite3_api->stricmp +#define sqlite3_uri_boolean sqlite3_api->uri_boolean +#define sqlite3_uri_int64 sqlite3_api->uri_int64 +#define sqlite3_uri_parameter sqlite3_api->uri_parameter +#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf +#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 +/* Version 3.8.7 and later */ +#define sqlite3_auto_extension sqlite3_api->auto_extension +#define sqlite3_bind_blob64 sqlite3_api->bind_blob64 +#define sqlite3_bind_text64 sqlite3_api->bind_text64 +#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension +#define sqlite3_load_extension sqlite3_api->load_extension +#define sqlite3_malloc64 sqlite3_api->malloc64 +#define sqlite3_msize sqlite3_api->msize +#define sqlite3_realloc64 sqlite3_api->realloc64 +#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension +#define sqlite3_result_blob64 sqlite3_api->result_blob64 +#define sqlite3_result_text64 sqlite3_api->result_text64 +#define sqlite3_strglob sqlite3_api->strglob +/* Version 3.8.11 and later */ +#define sqlite3_value_dup sqlite3_api->value_dup +#define sqlite3_value_free sqlite3_api->value_free +#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64 +#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64 +/* Version 3.9.0 and later */ +#define sqlite3_value_subtype sqlite3_api->value_subtype +#define sqlite3_result_subtype sqlite3_api->result_subtype +/* Version 3.10.0 and later */ +#define sqlite3_status64 sqlite3_api->status64 +#define sqlite3_strlike sqlite3_api->strlike +#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush +/* Version 3.12.0 and later */ +#define sqlite3_system_errno sqlite3_api->system_errno +/* Version 3.14.0 and later */ +#define sqlite3_trace_v2 sqlite3_api->trace_v2 +#define sqlite3_expanded_sql sqlite3_api->expanded_sql +/* Version 3.18.0 and later */ +#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid +/* Version 3.20.0 and later */ +#define sqlite3_prepare_v3 sqlite3_api->prepare_v3 +#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3 +#define sqlite3_bind_pointer sqlite3_api->bind_pointer +#define sqlite3_result_pointer sqlite3_api->result_pointer +#define sqlite3_value_pointer sqlite3_api->value_pointer +/* Version 3.22.0 and later */ +#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange +#define sqlite3_value_nochange sqlite3_api->value_nochange +#define sqlite3_vtab_collation sqlite3_api->vtab_collation +/* Version 3.24.0 and later */ +#define sqlite3_keyword_count sqlite3_api->keyword_count +#define sqlite3_keyword_name sqlite3_api->keyword_name +#define sqlite3_keyword_check sqlite3_api->keyword_check +#define sqlite3_str_new sqlite3_api->str_new +#define sqlite3_str_finish sqlite3_api->str_finish +#define sqlite3_str_appendf sqlite3_api->str_appendf +#define sqlite3_str_vappendf sqlite3_api->str_vappendf +#define sqlite3_str_append sqlite3_api->str_append +#define sqlite3_str_appendall sqlite3_api->str_appendall +#define sqlite3_str_appendchar sqlite3_api->str_appendchar +#define sqlite3_str_reset sqlite3_api->str_reset +#define sqlite3_str_errcode sqlite3_api->str_errcode +#define sqlite3_str_length sqlite3_api->str_length +#define sqlite3_str_value sqlite3_api->str_value +/* Version 3.25.0 and later */ +#define sqlite3_create_window_function sqlite3_api->create_window_function +/* Version 3.26.0 and later */ +#define sqlite3_normalized_sql sqlite3_api->normalized_sql +/* Version 3.28.0 and later */ +#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain +#define sqlite3_value_frombind sqlite3_api->value_frombind +/* Version 3.30.0 and later */ +#define sqlite3_drop_modules sqlite3_api->drop_modules +/* Version 3.31.0 and later */ +#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64 +#define sqlite3_uri_key sqlite3_api->uri_key +#define sqlite3_filename_database sqlite3_api->filename_database +#define sqlite3_filename_journal sqlite3_api->filename_journal +#define sqlite3_filename_wal sqlite3_api->filename_wal +/* Version 3.32.0 and later */ +#define sqlite3_create_filename sqlite3_api->create_filename +#define sqlite3_free_filename sqlite3_api->free_filename +#define sqlite3_database_file_object sqlite3_api->database_file_object +/* Version 3.34.0 and later */ +#define sqlite3_txn_state sqlite3_api->txn_state +/* Version 3.36.1 and later */ +#define sqlite3_changes64 sqlite3_api->changes64 +#define sqlite3_total_changes64 sqlite3_api->total_changes64 +/* Version 3.37.0 and later */ +#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages +/* Version 3.38.0 and later */ +#define sqlite3_error_offset sqlite3_api->error_offset +#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value +#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct +#define sqlite3_vtab_in sqlite3_api->vtab_in +#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first +#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next +/* Version 3.39.0 and later */ +#ifndef SQLITE_OMIT_DESERIALIZE +#define sqlite3_deserialize sqlite3_api->deserialize +#define sqlite3_serialize sqlite3_api->serialize +#endif +#define sqlite3_db_name sqlite3_api->db_name +/* Version 3.40.0 and later */ +#define sqlite3_value_encoding sqlite3_api->value_encoding +/* Version 3.41.0 and later */ +#define sqlite3_is_interrupted sqlite3_api->is_interrupted +/* Version 3.43.0 and later */ +#define sqlite3_stmt_explain sqlite3_api->stmt_explain +/* Version 3.44.0 and later */ +#define sqlite3_get_clientdata sqlite3_api->get_clientdata +#define sqlite3_set_clientdata sqlite3_api->set_clientdata +/* Version 3.50.0 and later */ +#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout +/* Version 3.51.0 and later */ +#define sqlite3_set_errmsg sqlite3_api->set_errmsg +#define sqlite3_db_status64 sqlite3_api->db_status64 +/* Version 3.52.0 and later */ +#define sqlite3_str_truncate sqlite3_api->str_truncate +#define sqlite3_str_free sqlite3_api->str_free +#define sqlite3_carray_bind sqlite3_api->carray_bind +#define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2 +#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ + +#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) + /* This case when the file really is being compiled as a loadable + ** extension */ +# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; +# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; +# define SQLITE_EXTENSION_INIT3 \ + extern const sqlite3_api_routines *sqlite3_api; +#else + /* This case when the file is being statically linked into the + ** application */ +# define SQLITE_EXTENSION_INIT1 /*no-op*/ +# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ +# define SQLITE_EXTENSION_INIT3 /*no-op*/ +#endif + +#endif /* SQLITE3EXT_H */ +/*** End of #include "sqlite3ext.h" ***/ + + +struct sqlite3mc_core_routines { + int (*initialize)(void); + int (*shutdown)(void); + int (*config)(int, ...); + int (*enable_load_extension)(sqlite3*, int); + int (*memory_alarm)(void(*)(void*, sqlite3_int64, int), void*, sqlite3_int64); + int (*mutex_held)(sqlite3_mutex*); + int (*mutex_notheld)(sqlite3_mutex*); + int (*os_init)(void); + int (*os_end)(void); + int (*preupdate_blobwrite)(sqlite3*); + int (*preupdate_count)(sqlite3*); + int (*preupdate_depth)(sqlite3*); + void* (*preupdate_hook)(sqlite3*, + void(*xPreUpdate)(void*, sqlite3*, int, char const*, char const*, sqlite3_int64, sqlite3_int64), + void*); + int (*preupdate_old)(sqlite3*, int, sqlite3_value**); + int (*preupdate_new)(sqlite3*, int, sqlite3_value**); + + int (*snapshot_cmp)(sqlite3_snapshot*, sqlite3_snapshot*); + void (*snapshot_free)(sqlite3_snapshot*); + int (*snapshot_get)(sqlite3*, const char*, sqlite3_snapshot**); + int (*snapshot_open)(sqlite3*, const char*, sqlite3_snapshot*); + int (*snapshot_recover)(sqlite3*, const char*); + + int (*stmt_scanstatus)(sqlite3_stmt*, int, int, void*); + int (*stmt_scanstatus_v2)(sqlite3_stmt*, int, int, int, void*); + void (*stmt_scanstatus_reset)(sqlite3_stmt*); + + int (*win32_set_directory)(unsigned long type, void* zValue); + int (*win32_set_directory8)(unsigned long type, const char* zValue); + int (*win32_set_directory16)(unsigned long type, const void* zValue); +}; + +struct sqlite3mc_api_routines { + void (*activate_see)(const char* zPassPhrase); + int (*key)(sqlite3* db, const void* pKey, int nKey); + int (*key_v2)(sqlite3*, const char* zDbName, const void* pKey, int nKey); + int (*rekey)(sqlite3*, const void* pKey, int nKey); + int (*rekey_v2)(sqlite3*, const char* zDbName, const void* pKey, int nKey); + + const char* (*mc_version)(); + int (*mc_cipher_count)(); + int (*mc_cipher_index)(const char* cipherName); + const char* (*mc_cipher_name)(int cipherIndex); + int (*mc_cipher_name_copy)(int cipherIndex, char* cipherName, int maxCipherNameSize); + int (*mc_config)(sqlite3* db, const char* paramName, int newValue); + int (*mc_config_cipher)(sqlite3* db, const char* cipherName, const char* paramName, int newValue); + unsigned char* (*mc_codec_data)(sqlite3* db, const char* zDbName, const char* paramName); + + int (*mc_vfs_create)(const char* zVfsReal, int makeDefault); + void (*mc_vfs_destroy)(const char* zName); + void (*mc_vfs_shutdown)(); +}; + +typedef struct sqlite3mc_core_routines sqlite3mc_core_routines; +typedef struct sqlite3mc_api_routines sqlite3mc_api_routines; + +#ifndef SQLITE3MC_DISPATCH_API +#if defined(_WIN32) +#define SQLITE3MC_DISPATCH_API __declspec(dllexport) +#else +#define SQLITE3MC_DISPATCH_API +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +SQLITE3MC_DISPATCH_API extern const sqlite3_api_routines* SQLITE3MC_API_TABLE_EXT; +SQLITE3MC_DISPATCH_API extern const sqlite3mc_core_routines* SQLITE3MC_API_TABLE_CORE; +SQLITE3MC_DISPATCH_API extern const sqlite3mc_api_routines* SQLITE3MC_API_TABLE_MC; + +#ifdef __cplusplus +} /* End of the 'extern "C"' block */ +#endif + +#if !defined(SQLITE_CORE) + +/* SQLite core API - not defined in sqlite3ext.h */ + +#define sqlite3_initialize SQLITE3MC_API_TABLE_CORE->initialize +#define sqlite3_shutdown SQLITE3MC_API_TABLE_CORE->shutdown +#define sqlite3_config SQLITE3MC_API_TABLE_CORE->config +#define sqlite3_enable_load_extension SQLITE3MC_API_TABLE_CORE->enable_load_extension +#define sqlite3_memory_alarm SQLITE3MC_API_TABLE_CORE->memory_alarm +#define sqlite3_mutex_held SQLITE3MC_API_TABLE_CORE->mutex_held +#define sqlite3_mutex_notheld SQLITE3MC_API_TABLE_CORE->mutex_notheld +#define sqlite3_os_init SQLITE3MC_API_TABLE_CORE->os_init +#define sqlite3_os_end SQLITE3MC_API_TABLE_CORE->os_end +#define sqlite3_preupdate_blobwrite SQLITE3MC_API_TABLE_CORE->preupdate_blobwrite +#define sqlite3_preupdate_count SQLITE3MC_API_TABLE_CORE->preupdate_count +#define sqlite3_preupdate_depth SQLITE3MC_API_TABLE_CORE->preupdate_depth +#define sqlite3_preupdate_hook SQLITE3MC_API_TABLE_CORE->preupdate_hook +#define sqlite3_preupdate_old SQLITE3MC_API_TABLE_CORE->preupdate_old +#define sqlite3_preupdate_new SQLITE3MC_API_TABLE_CORE->preupdate_new + +#define sqlite3_snapshot_cmp SQLITE3MC_API_TABLE_CORE->snapshot_cmp +#define sqlite3_snapshot_free SQLITE3MC_API_TABLE_CORE->snapshot_free +#define sqlite3_snapshot_get SQLITE3MC_API_TABLE_CORE->snapshot_get +#define sqlite3_snapshot_open SQLITE3MC_API_TABLE_CORE->snapshot_open +#define sqlite3_snapshot_recover SQLITE3MC_API_TABLE_CORE->snapshot_recover + +#define sqlite3_stmt_scanstatus SQLITE3MC_API_TABLE_CORE->stmt_scanstatus +#define sqlite3_stmt_scanstatus_v2 SQLITE3MC_API_TABLE_CORE->stmt_scanstatus_v2 +#define sqlite3_stmt_scanstatus_reset SQLITE3MC_API_TABLE_CORE->stmt_scanstatus_reset + +#define sqlite3_win32_set_directory SQLITE3MC_API_TABLE_CORE->win32_set_directory +#define sqlite3_win32_set_directory8 SQLITE3MC_API_TABLE_CORE->win32_set_directory8 +#define sqlite3_win32_set_directory16 SQLITE3MC_API_TABLE_CORE->win32_set_directory16 + +/* SQLite3 Multiple Ciphers API */ + +#define sqlite3_activate_see SQLITE3MC_API_TABLE_MC->activate_see +#define sqlite3_key SQLITE3MC_API_TABLE_MC->key +#define sqlite3_key_v2 SQLITE3MC_API_TABLE_MC->key_v2 +#define sqlite3_rekey SQLITE3MC_API_TABLE_MC->rekey +#define sqlite3_rekey_v2 SQLITE3MC_API_TABLE_MC->rekey_v2 + +#define sqlite3mc_version SQLITE3MC_API_TABLE_MC->mc_version +#define sqlite3mc_cipher_count SQLITE3MC_API_TABLE_MC->mc_cipher_count +#define sqlite3mc_cipher_index SQLITE3MC_API_TABLE_MC->mc_cipher_index +#define sqlite3mc_cipher_name SQLITE3MC_API_TABLE_MC->mc_cipher_name +#define sqlite3mc_cipher_name_copy SQLITE3MC_API_TABLE_MC->mc_cipher_name_copy +#define sqlite3mc_config SQLITE3MC_API_TABLE_MC->mc_config +#define sqlite3mc_config_cipher SQLITE3MC_API_TABLE_MC->mc_config_cipher +#define sqlite3mc_codec_data SQLITE3MC_API_TABLE_MC->mc_codec_data + +#define sqlite3mc_vfs_create SQLITE3MC_API_TABLE_MC->mc_vfs_create +#define sqlite3mc_vfs_destroy SQLITE3MC_API_TABLE_MC->mc_vfs_destroy +#define sqlite3mc_vfs_shutdown SQLITE3MC_API_TABLE_MC->mc_vfs_shutdown + +#endif /* !SQLITE_CORE */ + +#endif /* SQLITE3MC_USE_DISPATCH_TABLE */ + +#endif /* SQLITE3MC_H_ */ diff --git a/src/sqlitecipher.cpp b/src/sqlitecipher.cpp index 48b42dc..3fb6bac 100644 --- a/src/sqlitecipher.cpp +++ b/src/sqlitecipher.cpp @@ -59,6 +59,8 @@ #include #include +#include + #if defined Q_OS_WIN # include #else @@ -101,11 +103,13 @@ Q_DECLARE_METATYPE(sqlite3_stmt*) #define CHECK_SQLITE_KEY \ do { \ - sqlite3_key(d->access, password.toUtf8().constData(), password.size()); \ - int result = sqlite3_exec(d->access, QStringLiteral("SELECT count(*) FROM sqlite_master LIMIT 1").toUtf8().constData(), nullptr, nullptr, nullptr); \ - if (result != SQLITE_OK) { \ - if (d->access) { sqlite3_close(d->access); d->access = nullptr; } \ - setLastError(qMakeError(d->access, tr("Invalid password."), QSqlError::ConnectionError, result)); setOpenError(true); return false; \ + const QByteArray keyBytes = password.toUtf8(); \ + sqlite3_key(d->access, keyBytes.constData(), keyBytes.size()); \ + const int rc = sqlite3_exec(d->access, "SELECT count(*) FROM sqlite_master LIMIT 1", nullptr, nullptr, nullptr); \ + if (rc != SQLITE_OK) { \ + const QSqlError err = qMakeError(d->access, tr("Invalid password."), QSqlError::ConnectionError, rc); \ + sqlite3_close_v2(d->access); d->access = nullptr; \ + setLastError(err); setOpenError(true); setOpen(false); return false; \ } \ } while (0) @@ -519,16 +523,23 @@ bool SQLiteResult::execBatch(bool arrayBind) Q_UNUSED(arrayBind) Q_D(QSqlResult); QScopedValueRollbackvalues)> valuesScope(d->values); - QVector values = d->values; - if (values.count() == 0) + if (d->values.isEmpty()) return false; - for (int i = 0; i < values.at(0).toList().count(); ++i) { + // Convert each bound column to a list once (values are implicitly shared, so this is + // cheap) instead of calling toList() again for every row/placeholder. + QList columns; + columns.reserve(d->values.size()); + for (const QVariant &v : d->values) + columns.append(v.toList()); + + const int rowCount = columns.at(0).count(); + for (int row = 0; row < rowCount; ++row) { d->values.clear(); QScopedValueRollbackindexes)> indexesScope(d->indexes); decltype(d->indexes)::const_iterator it = d->indexes.constBegin(); while (it != d->indexes.constEnd()) { - bindValue(it.key(), values.at(it.value().first()).toList().at(i), QSql::In); + bindValue(it.key(), columns.at(it.value().first()).at(row), QSql::In); ++it; } if (!exec()) @@ -694,7 +705,11 @@ int SQLiteResult::size() int SQLiteResult::numRowsAffected() { Q_D(const SQLiteResult); +#if (SQLITE_VERSION_NUMBER >= 3037000) + return int(qMin(sqlite3_changes64(d->drv_d_func()->access), INT_MAX)); +#else return sqlite3_changes(d->drv_d_func()->access); +#endif } QVariant SQLiteResult::lastInsertId() const @@ -921,314 +936,71 @@ bool SQLiteCipherDriver::open(const QString & db, const QString &, const QString const auto opts = QString(conOpts).remove(QLatin1Char(' ')).split(QLatin1Char(';')); #if (QT_VERSION >= 0x050700) - for (auto option : opts) { + for (const auto &rawOption : opts) { #else - foreach (auto option : opts) { + foreach (const auto &rawOption : opts) { #endif - option = option.trimmed(); - if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT"))) { - option = option.mid(20).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - timeOut = v; - } - } - } - if (option.startsWith(QLatin1String("QSQLITE_UPDATE_KEY"))) { - option = option.mid(18).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - newPassword = option.mid(1); - } - keyOp = UPDATE_KEY; - } - if (option.startsWith(QLatin1String("QSQLITE_USE_CIPHER"))) { - option = option.mid(18).trimmed(); - cipher = _cipherNameToValue(option.mid(1)); - } - if (option.startsWith(QLatin1String("AES128CBC_LEGACY"))) { - option = option.mid(16).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - aes128cbcLegacy = v; - } - } - } - if (option.startsWith(QLatin1String("AES128CBC_LEGACY_PAGE_SIZE"))) { - option = option.mid(26).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - aes128cbcLegacyPageSize = v; - if (aes128cbcLegacyPageSize < 0) { - aes128cbcLegacyPageSize = 0; - } else if (aes128cbcLegacyPageSize > 65536) { - aes128cbcLegacyPageSize = 65536; - } - } - } - } - if (option.startsWith(QLatin1String("AES256CBC_LEGACY"))) { - option = option.mid(16).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - aes256cbcLegacy = v; - } - } - } - if (option.startsWith(QLatin1String("AES256CBC_LEGACY_PAGE_SIZE"))) { - option = option.mid(26).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - aes256cbcLegacyPageSize = v; - if (aes256cbcLegacyPageSize < 0) { - aes256cbcLegacyPageSize = 0; - } else if (aes256cbcLegacyPageSize > 65536) { - aes256cbcLegacyPageSize = 65536; - } - } - } - } - if (option.startsWith(QLatin1String("AES256CBC_KDF_ITER"))) { - option = option.mid(18).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - aes256cbcKdfIter = v; - if (aes256cbcKdfIter < 1) { - aes256cbcKdfIter = 1; - } - } - } - } - if (option.startsWith(QLatin1String("CHACHA20_LEGACY"))) { - option = option.mid(15).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - chacha20Legacy = v; - } - } - } - if (option.startsWith(QLatin1String("CHACHA20_LEGACY_PAGE_SIZE"))) { - option = option.mid(25).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - chacha20LegacyPageSize = v; - if (chacha20LegacyPageSize < 0) { - chacha20LegacyPageSize = 0; - } else if (chacha20LegacyPageSize > 65536) { - chacha20LegacyPageSize = 65536; - } - } - } - } - if (option.startsWith(QLatin1String("CHACHA20_KDF_ITER"))) { - option = option.mid(17).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - chacha20KdfIter = v; - if (chacha20KdfIter < 1) { - chacha20KdfIter = 1; - } - } - } - } - if (option.startsWith(QLatin1String("SQLCIPHER_LEGACY"))) { - option = option.mid(16).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - sqlcipherLegacy = v; - if (sqlcipherLegacy < 0) { - sqlcipherLegacy = 0; - } else if (sqlcipherLegacy > 4) { - sqlcipherLegacy = 4; - } - } - } - } - if (option.startsWith(QLatin1String("SQLCIPHER_LEGACY_PAGE_SIZE"))) { - option = option.mid(26).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - sqlcipherLegacyPageSize = v; - if (sqlcipherLegacyPageSize < 0) { - sqlcipherLegacyPageSize = 0; - } else if (sqlcipherLegacyPageSize > 65536) { - sqlcipherLegacyPageSize = 65536; - } - } - } - } - if (option.startsWith(QLatin1String("SQLCIPHER_KDF_ITER"))) { - option = option.mid(18).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - sqlcipherKdfIter = v; - if (sqlcipherKdfIter < 1) { - sqlcipherKdfIter = 1; - } - } - } - } - if (option.startsWith(QLatin1String("SQLCIPHER_FAST_KDF_ITER"))) { - option = option.mid(23).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - sqlcipherFastKdfIter = v; - if (sqlcipherFastKdfIter < 1) { - sqlcipherFastKdfIter = 1; - } - } - } - } - if (option.startsWith(QLatin1String("SQLCIPHER_HMAC_USE"))) { - option = option.mid(18).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - sqlcipherHmacUse = v; - } - } - } - if (option.startsWith(QLatin1String("SQLCIPHER_HMAC_PGNO"))) { - option = option.mid(19).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - sqlcipherHmacPgno = v; - if (sqlcipherHmacPgno < 0) { - sqlcipherHmacPgno = 0; - } - if (sqlcipherHmacPgno > 2) { - sqlcipherHmacPgno = 2; - } - } - } - } - if (option.startsWith(QLatin1String("SQLCIPHER_HMAC_SALT_MASK"))) { - option = option.mid(24).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - sqlcipherHmacSaltMask = v; - if (sqlcipherHmacSaltMask < 0) { - sqlcipherHmacSaltMask = 0; - } - if (sqlcipherHmacSaltMask > 255) { - sqlcipherHmacSaltMask = 255; - } - } - } - } - if (option.startsWith(QLatin1String("SQLCIPHER_KDF_ALGORITHM"))) { - option = option.mid(23).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - sqlcipherKdfAlgorithm = v; - if (sqlcipherKdfAlgorithm < 0) { - sqlcipherKdfAlgorithm = 0; - } - if (sqlcipherKdfAlgorithm > 2) { - sqlcipherKdfAlgorithm = 2; - } - } - } - } - if (option.startsWith(QLatin1String("SQLCIPHER_HMAC_ALGORITHM"))) { - option = option.mid(24).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - sqlcipherHmacAlgorithm = v; - if (sqlcipherHmacAlgorithm < 0) { - sqlcipherHmacAlgorithm = 0; - } - if (sqlcipherHmacAlgorithm > 2) { - sqlcipherHmacAlgorithm = 2; - } - } - } - } - if (option.startsWith(QLatin1String("SQLCIPHER_PLAINTEXT_HEADER_SIZE"))) { - option = option.mid(31).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - sqlcipherPlainTextHeaderSize = v; - if (sqlcipherPlainTextHeaderSize < 0) { - sqlcipherPlainTextHeaderSize = 0; - } - if (sqlcipherPlainTextHeaderSize > 100) { - sqlcipherPlainTextHeaderSize = 100; - } - } - } - } - if (option.startsWith(QLatin1String("RC4_LEGACY_PAGE_SIZE"))) { - option = option.mid(20).trimmed(); - if (option.startsWith(QLatin1Char('='))) { - bool ok; - const int v = option.mid(1).trimmed().toInt(&ok); - if (ok) { - rc4LegacyPageSize = v; - if (rc4LegacyPageSize < 0) { - rc4LegacyPageSize = 0; - } else if (rc4LegacyPageSize > 65536) { - rc4LegacyPageSize = 65536; - } - } - } - } + const QString option = rawOption.trimmed(); + if (option.isEmpty()) + continue; - if (option == QLatin1String("QSQLITE_OPEN_READONLY")) { - openReadOnlyOption = true; - } else if (option == QLatin1String("QSQLITE_OPEN_URI")) { - openUriOption = true; - } else if (option == QLatin1String("QSQLITE_ENABLE_SHARED_CACHE")) { - sharedCache = true; - } else if (option == QLatin1String("QSQLITE_CREATE_KEY")) { - keyOp = CREATE_KEY; - } else if (option == QLatin1String("QSQLITE_REMOVE_KEY")) { - keyOp = REMOVE_KEY; - } + // Split into key / value on the first '=' (value may contain '=', e.g. a password). + const int eq = option.indexOf(QLatin1Char('=')); + const QString key = (eq < 0) ? option : option.left(eq); + const QString value = (eq < 0) ? QString() : option.mid(eq + 1); + const bool hasValue = (eq >= 0); + // Numeric options trim the value (matches the original parser); cipher name + // and passwords use the raw value. + const auto numValue = value.trimmed(); + + // Override the default only when the value parses as an integer; keep the default otherwise. + const auto intOpt = [&](int def, int lo, int hi) -> int { + if (!hasValue) return def; + bool ok = false; + const int v = numValue.toInt(&ok); + return ok ? qBound(lo, v, hi) : def; + }; + const auto boolOpt = [&](bool def) -> bool { + if (!hasValue) return def; + bool ok = false; + const int v = numValue.toInt(&ok); + return ok ? (v != 0) : def; + }; + + if (key == QLatin1String("QSQLITE_BUSY_TIMEOUT")) timeOut = intOpt(timeOut, INT_MIN, INT_MAX); + else if (key == QLatin1String("QSQLITE_UPDATE_KEY")) { keyOp = UPDATE_KEY; if (hasValue) newPassword = value; } + else if (key == QLatin1String("QSQLITE_USE_CIPHER")) cipher = _cipherNameToValue(value); + else if (key == QLatin1String("AES128CBC_LEGACY")) aes128cbcLegacy = boolOpt(aes128cbcLegacy); + else if (key == QLatin1String("AES128CBC_LEGACY_PAGE_SIZE")) aes128cbcLegacyPageSize = intOpt(aes128cbcLegacyPageSize, 0, 65536); + else if (key == QLatin1String("AES256CBC_LEGACY")) aes256cbcLegacy = boolOpt(aes256cbcLegacy); + else if (key == QLatin1String("AES256CBC_LEGACY_PAGE_SIZE")) aes256cbcLegacyPageSize = intOpt(aes256cbcLegacyPageSize, 0, 65536); + else if (key == QLatin1String("AES256CBC_KDF_ITER")) aes256cbcKdfIter = intOpt(aes256cbcKdfIter, 1, INT_MAX); + else if (key == QLatin1String("CHACHA20_LEGACY")) chacha20Legacy = boolOpt(chacha20Legacy); + else if (key == QLatin1String("CHACHA20_LEGACY_PAGE_SIZE")) chacha20LegacyPageSize = intOpt(chacha20LegacyPageSize, 0, 65536); + else if (key == QLatin1String("CHACHA20_KDF_ITER")) chacha20KdfIter = intOpt(chacha20KdfIter, 1, INT_MAX); + else if (key == QLatin1String("SQLCIPHER_LEGACY")) sqlcipherLegacy = intOpt(sqlcipherLegacy, 0, 4); + else if (key == QLatin1String("SQLCIPHER_LEGACY_PAGE_SIZE")) sqlcipherLegacyPageSize = intOpt(sqlcipherLegacyPageSize, 0, 65536); + else if (key == QLatin1String("SQLCIPHER_KDF_ITER")) sqlcipherKdfIter = intOpt(sqlcipherKdfIter, 1, INT_MAX); + else if (key == QLatin1String("SQLCIPHER_FAST_KDF_ITER")) sqlcipherFastKdfIter = intOpt(sqlcipherFastKdfIter, 1, INT_MAX); + else if (key == QLatin1String("SQLCIPHER_HMAC_USE")) sqlcipherHmacUse = boolOpt(sqlcipherHmacUse); + else if (key == QLatin1String("SQLCIPHER_HMAC_PGNO")) sqlcipherHmacPgno = intOpt(sqlcipherHmacPgno, 0, 2); + else if (key == QLatin1String("SQLCIPHER_HMAC_SALT_MASK")) sqlcipherHmacSaltMask = intOpt(sqlcipherHmacSaltMask, 0, 255); + else if (key == QLatin1String("SQLCIPHER_KDF_ALGORITHM")) sqlcipherKdfAlgorithm = intOpt(sqlcipherKdfAlgorithm, 0, 2); + else if (key == QLatin1String("SQLCIPHER_HMAC_ALGORITHM")) sqlcipherHmacAlgorithm = intOpt(sqlcipherHmacAlgorithm, 0, 2); + else if (key == QLatin1String("SQLCIPHER_PLAINTEXT_HEADER_SIZE")) sqlcipherPlainTextHeaderSize = intOpt(sqlcipherPlainTextHeaderSize, 0, 100); + else if (key == QLatin1String("RC4_LEGACY_PAGE_SIZE")) rc4LegacyPageSize = intOpt(rc4LegacyPageSize, 0, 65536); + else if (key == QLatin1String("QSQLITE_OPEN_READONLY")) openReadOnlyOption = true; + else if (key == QLatin1String("QSQLITE_OPEN_URI")) openUriOption = true; + else if (key == QLatin1String("QSQLITE_ENABLE_SHARED_CACHE")) sharedCache = true; + else if (key == QLatin1String("QSQLITE_CREATE_KEY")) keyOp = CREATE_KEY; + else if (key == QLatin1String("QSQLITE_REMOVE_KEY")) keyOp = REMOVE_KEY; #ifdef REGULAR_EXPRESSION_ENABLED - else if (option.startsWith(regexpConnectOption)) { - option = option.mid(regexpConnectOption.size()).trimmed(); - if (option.isEmpty()) { + else if (key == regexpConnectOption) { + if (!hasValue) { defineRegexp = true; - } else if (option.startsWith(QLatin1Char('='))) { + } else { bool ok = false; - const int cacheSize = option.mid(1).trimmed().toInt(&ok); + const int cacheSize = numValue.toInt(&ok); if (ok) { defineRegexp = true; if (cacheSize > 0) @@ -1308,7 +1080,7 @@ bool SQLiteCipherDriver::open(const QString & db, const QString &, const QString } } - if (!(password.isNull() || password.isEmpty())) { + if (!password.isEmpty()) { switch (keyOp) { case OPEN_WITH_KEY: { @@ -1317,12 +1089,14 @@ bool SQLiteCipherDriver::open(const QString & db, const QString &, const QString } case CREATE_KEY: { - int res = sqlite3_rekey(d->access, password.toUtf8().constData(), password.size()); + const QByteArray keyBytes = password.toUtf8(); + int res = sqlite3_rekey(d->access, keyBytes.constData(), keyBytes.size()); if (SQLITE_OK != res) { setLastError(qMakeError(d->access, tr("Cannot create password. Maybe it is encrypted?"), QSqlError::ConnectionError, res)); setOpenError(true); setOpen(false); sqlite3_close_v2(d->access); + d->access = nullptr; return false; } break; @@ -1332,10 +1106,11 @@ bool SQLiteCipherDriver::open(const QString & db, const QString &, const QString // verify old password CHECK_SQLITE_KEY; // set new password - if (newPassword.isEmpty() || newPassword.isNull()) { + if (newPassword.isEmpty()) { sqlite3_rekey(d->access, nullptr, 0); } else { - sqlite3_rekey(d->access, newPassword.toUtf8().constData(), newPassword.size()); + const QByteArray newKey = newPassword.toUtf8(); + sqlite3_rekey(d->access, newKey.constData(), newKey.size()); } break; } @@ -1489,7 +1264,7 @@ static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool only if (onlyPIndex && !isPk) continue; QString typeName = q.value(2).toString().toLower(); - QString defVal = q.value(4).toString(); + QString defVal = q.value(4).toString(); if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\'')) { const int end = defVal.lastIndexOf(QLatin1Char('\'')); if (end > 0)