From 5c698ac92599c1e57e1329d37e0e1d80d38560b0 Mon Sep 17 00:00:00 2001 From: utelle Date: Tue, 31 Dec 2024 23:30:52 +0100 Subject: [PATCH] Add new cipher scheme AEGIS and other changes SQLite3 Multiple Ciphers 2.0.0 supports the new cipher scheme AEGIS. Support for it was added to wxSQLite3. The upstream SQLite project is about to remove support for the User Authentication extension completely, beginning with version 3.48.0, which will be released in January 2025. Support for this extension in wxSQLite3 has been disabled. --- CHANGELOG.md | 4 + configure.ac | 19 +- include/wx/wxsqlite3.h | 104 +- include/wx/wxsqlite3_version.h | 6 +- include/wx/wxsqlite3def.h | 8 + samples/minimal.cpp | 71 +- src/sqlite3mc_amalgamation.c | 43164 ++++++++++++++++++++++++++++++- src/sqlite3mc_amalgamation.h | 125 +- src/sqlite3mc_config.h | 26 +- src/wxsqlite3.cpp | 222 +- 10 files changed, 42845 insertions(+), 904 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd8891b3..dc22955f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Upgrade to SQLite3 Multiple Ciphers version 2.0.0 (SQLite version 3.47.2) +- Removed support for User Authentication extension +- Added new cipher scheme AEGIS + ## [4.9.12] - 2024-10-22 - Upgrade to SQLite3 Multiple Ciphers version 1.9.0 (SQLite version 3.47.0) diff --git a/configure.ac b/configure.ac index fd1ca493..840adaa1 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ dnl Copyright (C) 2017-2024 Ulrich Telle , Vadim Zeitlin dnl dnl This file is covered by the same licence as the entire wxSQLite3 package. -AC_INIT([wxsqlite3], [4.9.12], [ulrich@telle-online.de]) +AC_INIT([wxsqlite3], [4.10.0], [ulrich@telle-online.de]) dnl This is the version tested with, might work with earlier ones. AC_PREREQ([2.69]) @@ -91,6 +91,15 @@ AC_ARG_WITH([ascon128], AS_IF([test "x$with_ascon128" = xno], [AC_DEFINE([WXSQLITE3_HAVE_CIPHER_ASCON128], [0], [Define if you have Ascon 128 disabled])]) +AC_ARG_WITH([aegis], + [AS_HELP_STRING([--without-aegis], + [Disable support for Aegis Encryption])], + [], + [with_aegis=yes]) + +AS_IF([test "x$with_aegis" = xno], + [AC_DEFINE([WXSQLITE3_HAVE_CIPHER_AEGIS], [0], [Define if you have Aegis disabled])]) + AC_ARG_ENABLE(codec, [ --enable-codec[=] Specify the codec type: aes128: AES 128 Bit CBC Encryption @@ -98,7 +107,8 @@ AC_ARG_ENABLE(codec, chacha20 [default]: ChaCha20-Poly1305 Encryption sqlcipher: SQLCipher Encryption rc4: RC4 Encryption - ascon128: Ascon 128 Encryption], + ascon128: Ascon 128 Encryption + aegis: Aegis Encryption], [if test "x$enableval" = "xaes128" && test "x$with_aes128cbc" = xyes ; then codec_type=CODEC_TYPE_AES128 elif test "x$enableval" = "xaes256" && test "x$with_aes256cbc" = xyes ; then @@ -111,6 +121,8 @@ AC_ARG_ENABLE(codec, codec_type=CODEC_TYPE_RC4 elif test "x$enableval" = "xascon128" && test "x$with_ascon128" = xyes ; then codec_type=CODEC_TYPE_ASCON128 + elif test "x$enableval" = "xaegis" && test "x$with_aegis" = xyes ; then + codec_type=CODEC_TYPE_AEGIS else echo echo "Error!" @@ -125,7 +137,8 @@ AS_IF([test "x$with_aes128cbc" = xno && test "x$with_chacha20" = xno && test "x$with_sqlcipher" = xno && test "x$with_rc4" = xno && - test "x$with_ascon128" = xno], + test "x$with_ascon128" = xno && + test "x$with_aegis" = xno], [AC_DEFINE([WXSQLITE3_HAVE_CODEC], [0], [All ciphers disabled so encryption is disabled])]) dnl We only need the libraries above for the main library itself, but the diff --git a/include/wx/wxsqlite3.h b/include/wx/wxsqlite3.h index f3d6e4ee..40730c44 100644 --- a/include/wx/wxsqlite3.h +++ b/include/wx/wxsqlite3.h @@ -3,7 +3,7 @@ ** Purpose: wxWidgets wrapper around the SQLite3 embedded database library. ** Author: Ulrich Telle ** Created: 2005-07-14 -** Copyright: (c) 2005-2023 Ulrich Telle +** Copyright: (c) 2005-2024 Ulrich Telle ** License: LGPL-3.0+ WITH WxWindows-exception-3.1 */ @@ -39,7 +39,8 @@ enum wxSQLite3CipherType WXSQLITE_CIPHER_CHACHA20, WXSQLITE_CIPHER_SQLCIPHER, WXSQLITE_CIPHER_RC4, - WXSQLITE_CIPHER_ASCON128 + WXSQLITE_CIPHER_ASCON128, + WXSQLITE_CIPHER_AEGIS }; #define WXSQLITE_ERROR 1000 @@ -1290,6 +1291,105 @@ class WXDLLIMPEXP_SQLITE3 wxSQLite3CipherAscon128 : public wxSQLite3Cipher int m_kdfIter; ///< Iteration count for KDF function }; +/// Cipher class representing Aegis encryption with Ascon tag +class WXDLLIMPEXP_SQLITE3 wxSQLite3CipherAegis : public wxSQLite3Cipher +{ +public: + /// Constructor + wxSQLite3CipherAegis(); + + /// Copy constructor + wxSQLite3CipherAegis(const wxSQLite3CipherAegis& cipher); + + /// Destructor + virtual ~wxSQLite3CipherAegis(); + + /// Initialize the cipher instance based on global default settings + /** + * The parameters of the cipher instance are initialize with the global default settings of the associated cipher type. + * \return true if the cipher instance could be initialized successfully, false otherwise + */ + virtual bool InitializeFromGlobalDefault(); + + /// Initialize the cipher instance based on current settings + /** + * The parameters of the cipher instance are initialize with the current settings of the associated cipher type + * as defined in the given database connection. + * \param db database instance representing a database connection + * \return true if the cipher instance could be initialized successfully, false otherwise + */ + virtual bool InitializeFromCurrent(wxSQLite3Database& db); + + /// Initialize the cipher instance based on current default settings + /** + * The parameters of the cipher instance are initialize with the current default settings of the associated cipher type + * as defined in the given database connection. + * \param db database instance representing a database connection + * \return true if the cipher instance could be initialized successfully, false otherwise + */ + virtual bool InitializeFromCurrentDefault(wxSQLite3Database& db); + + /// Apply the cipher parameters to a database connection + /** + * The parameters of the cipher instance are applied to the given database connection. + * \param db database instance representing a database connection + * \return true if the cipher parameters could be applied successfully, false otherwise + */ + virtual bool Apply(wxSQLite3Database& db) const; + virtual bool Apply(void* dbHandle) const; + +#if 0 + // Currently no legacy mode available + /// Set legacy mode + void SetLegacy(bool legacy) { m_legacy = legacy; } + + /// Get legacy mode + bool GetLegacy() const { return m_legacy; } +#endif + + /// Set number of iterations of KDF function for ordinary key + void SetIterCount(int iterCount) { m_tcost = iterCount; } + + /// Get number of iterations of KDF function for ordinary key + int GetIterCount() const { return m_tcost; } + + /// Set size of memory in kB of KDF function for ordinary key + void SetMemorySize(int memSize) { m_mcost = memSize; } + + /// Get size of memory in kB of KDF function for ordinary key + int GetMemorySize() const { return m_mcost; } + + /// Set number of threads of KDF function for ordinary key + void SetThreadCount(int threads) { m_pcost = threads; } + + /// Get number of threads of KDF function for ordinary key + int GetThreadCount() const { return m_pcost; } + + /// Aegis algorithm types + enum Algorithm + { + ALGORITHM_AEGIS_128L = 1, + ALGORITHM_AEGIS_128X2, + ALGORITHM_AEGIS_128X4, + ALGORITHM_AEGIS_256, + ALGORITHM_AEGIS_256X2, + ALGORITHM_AEGIS_256X4 + }; + + /// Set Aegis algorithm to be used for encryption + void SetAlgorithm(Algorithm algorithm) { m_algorithm = algorithm; } + + /// Get Aegis algorithm used for encryption + Algorithm GetAlgorithm() const { return m_algorithm; } + +private: + bool m_legacy; ///< Flag for legacy mode + int m_tcost; ///< Time cost (number of iterations) for KDF function + int m_mcost; ///< Amount of memory in kB for KDF function + int m_pcost; ///< Parallelism (number of threads) for KDF function + Algorithm m_algorithm; ///< Aegis algorithm to be used for encryption +}; + /// Interface for a user defined hook function /** diff --git a/include/wx/wxsqlite3_version.h b/include/wx/wxsqlite3_version.h index 3452306c..f6ceea3a 100644 --- a/include/wx/wxsqlite3_version.h +++ b/include/wx/wxsqlite3_version.h @@ -13,9 +13,9 @@ #define WXSQLITE3_VERSION_H_ #define WXSQLITE3_MAJOR_VERSION 4 -#define WXSQLITE3_MINOR_VERSION 9 -#define WXSQLITE3_RELEASE_NUMBER 12 +#define WXSQLITE3_MINOR_VERSION 10 +#define WXSQLITE3_RELEASE_NUMBER 0 #define WXSQLITE3_SUBRELEASE_NUMBER 0 -#define WXSQLITE3_VERSION_STRING "wxSQLite3 4.9.12" +#define WXSQLITE3_VERSION_STRING "wxSQLite3 4.10.0" #endif // WXSQLITE3_VERSION_H_ diff --git a/include/wx/wxsqlite3def.h b/include/wx/wxsqlite3def.h index 039b93fa..f8d0f5b4 100644 --- a/include/wx/wxsqlite3def.h +++ b/include/wx/wxsqlite3def.h @@ -46,6 +46,14 @@
+
4.10.0 - December 2024
+
+Upgrade to SQLite3 Multiple Ciphers version 2.0.0 (SQLite version 3.47.2)
+Removed User Authentication extension
+Added new cipher scheme AEGIS + +
+
4.9.12 - October 2024
Upgrade to SQLite3 Multiple Ciphers version 1.9.0 (SQLite version 3.47.0) diff --git a/samples/minimal.cpp b/samples/minimal.cpp index 75d57b83..55ab9bbf 100644 --- a/samples/minimal.cpp +++ b/samples/minimal.cpp @@ -4,7 +4,7 @@ ** This example is based on the CppSQLite example. ** Author: Ulrich Telle ** Created: 2005-07-14 -** Copyright: (c) 2005-2018 Ulrich Telle +** Copyright: (c) 2005-2024 Ulrich Telle ** License: LGPL-3.0+ WITH WxWindows-exception-3.1 */ @@ -123,69 +123,6 @@ static void testTransaction() clearDB(db); } -static void testUserAuthentication() -{ - wxString testDBName = wxGetCwd() + wxS("/test3.db"); - if (wxFileExists(testDBName)) - { - wxRemoveFile(testDBName); - } - wxSQLite3Database* db = new wxSQLite3Database(); - try - { - db->Open(testDBName); - db->UserAdd(wxS("testuser"), wxS("testpswd"), true); - cout << "User authentication enabled for database using 'testuser'." << endl; - if (db->UserLogin(wxS("sampleuser"), wxS("samplepswd"))) - { - cout << "'sampleuser' successfully logged in, but this shouldn't happen due to enabled user authentication." << endl; - } - else - { - cout << "Login of 'sampleuser' rejected." << endl; - } - if (db->UserLogin(wxS("testuser"), wxS("testpswd"))) - { - cout << "Login of 'testuser' succeeded." << endl; - db->ExecuteUpdate(wxS("CREATE TABLE test (col1 INTEGER)")); - db->ExecuteUpdate(wxS("INSERT INTO test (col1) VALUES (2)")); - db->UserAdd(wxS("myuser"), wxS("mypswd"), false); - cout << "Added 'myuser' without privileges." << endl; - if (db->UserIsPrivileged(wxS("myuser"))) - { - cout << "'myuser' is privileged." << endl; - } - else - { - cout << "'myuser' is NOT privileged." << endl; - } - db->UserChange(wxS("myuser"), wxS("mypswd"), true); - cout << "Make 'myuser' privileged." << endl; - if (db->UserIsPrivileged(wxS("myuser"))) - { - cout << "'myuser' is now privileged." << endl; - } - else - { - cout << "'myuser' is still NOT privileged." << endl; - } - db->UserDelete(wxS("myuser")); - cout << "'myuser' deleted." << endl; - } - else - { - cout << "Login of 'testuser' failed unexpectedly." << endl; - } - db->Close(); - } - catch (wxSQLite3Exception& e) - { - cerr << e.GetErrorCode() << ":" << (const char*)(e.GetMessage().mb_str()) << endl; - } - - delete db; -} - // User defined aggregate function class MyAggregateFunction : public wxSQLite3AggregateFunction { @@ -864,12 +801,6 @@ int Minimal::OnRun() cout << endl << "Test of RAII transactions" << endl; testTransaction(); - if (wxSQLite3Database::HasUserAuthenticationSupport()) - { - cout << endl << "Test of user authentication" << endl; - testUserAuthentication(); - } - // Test accessing encrypted database files (currently SQLCipher only) TestCiphers(); diff --git a/src/sqlite3mc_amalgamation.c b/src/sqlite3mc_amalgamation.c index 556e6185..8056eb67 100644 --- a/src/sqlite3mc_amalgamation.c +++ b/src/sqlite3mc_amalgamation.c @@ -17,7 +17,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 */ @@ -75,11 +74,9 @@ SQLITE_PRIVATE void sqlite3mc_shutdown(void); ** 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 +133,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.47.2. 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,7 +151,7 @@ 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. +** 2aabe05e2e8cae4847a802ee2daddc1d7413. */ #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 @@ -598,9 +595,9 @@ 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.47.2" +#define SQLITE_VERSION_NUMBER 3047002 +#define SQLITE_SOURCE_ID "2024-12-07 20:39:59 2aabe05e2e8cae4847a802ee2daddc1d7413d8fc560254d93ee3e72c14685b6c" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -1104,6 +1101,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 +1124,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 @@ -1266,6 +1271,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 @@ -11345,6 +11351,7 @@ 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); /******** Begin file sqlite3rtree.h *********/ /* @@ -32452,6 +32459,7 @@ SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExp pExpr = pExpr->pLeft; } if( pExpr==0 ) return; + if( ExprHasProperty(pExpr, EP_FromDDL) ) return; db->errByteOffset = pExpr->w.iOfst; } @@ -35841,8 +35849,8 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en 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 */ + u64 s2; /* round-tripped significand */ double rr[2]; - u64 s2; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ @@ -35945,7 +35953,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en e = (e*esign) + d; /* Try to adjust the exponent to make it smaller */ - while( e>0 && s<(LARGEST_UINT64/10) ){ + while( e>0 && s<((LARGEST_UINT64-0x7ff)/10) ){ s *= 10; e--; } @@ -35955,11 +35963,16 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en } 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); + assert( sizeof(s2)==sizeof(rr[0]) ); + memcpy(&s2, &rr[0], sizeof(s2)); + if( s2<=0x43efffffffffffffLL ){ + s2 = (u64)rr[0]; + rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); + }else{ + rr[1] = 0.0; + } + assert( rr[1]<=1.0e-10*rr[0] ); /* Equal only when rr[0]==0.0 */ + if( e>0 ){ while( e>=100 ){ e -= 100; @@ -42749,6 +42762,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; } @@ -50549,7 +50563,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); } @@ -51937,7 +51951,7 @@ static int winOpen( int rc = SQLITE_OK; /* Function Return Code */ #if !defined(NDEBUG) || SQLITE_OS_WINCE - int eType = flags&0xFFFFFF00; /* Type of file to open */ + int eType = flags&0x0FFF00; /* Type of file to open */ #endif int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); @@ -58157,19 +58171,27 @@ static const unsigned char aJournalMagic[] = { ** 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) */ + assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 ); + if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd) + & SQLITE_IOCAP_SUBPAGE_READ)==0 ){ + return 0; /* Case (2) */ + } + 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; + return iRead==0; /* Condition (4) */ } #endif return 1; @@ -147756,32 +147778,32 @@ 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{ @@ -156333,6 +156355,15 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( } 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; + } + sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL); @@ -159109,6 +159140,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 @@ -189976,10 +190008,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 ){ @@ -193150,7 +193187,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; @@ -194703,10 +194740,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]; @@ -194721,9 +194759,6 @@ static int getNextString( nToken = ii+1; } } - - pModule->xClose(pCursor); - pCursor = 0; } if( rc==SQLITE_DONE ){ @@ -194731,7 +194766,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]; @@ -194739,11 +194777,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++){ @@ -194753,17 +194789,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; } /* @@ -232984,7 +233020,27 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){ /************** 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) @@ -232994,6 +233050,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 ** @@ -255066,7 +255128,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: 2024-12-07 20:39:59 2aabe05e2e8cae4847a802ee2daddc1d7413d8fc560254d93ee3e72c14685b6c", -1, SQLITE_TRANSIENT); } /* @@ -260257,7 +260319,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 ************************************************/ @@ -260665,6 +260727,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 */ @@ -260692,6 +260758,10 @@ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } #define HAVE_CIPHER_ASCON128 1 #endif +#ifndef HAVE_CIPHER_AEGIS +#define HAVE_CIPHER_AEGIS 1 +#endif + /* ** Define whether dynamic ciphers will be used */ @@ -260715,12 +260785,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 /* @@ -260732,7 +260804,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 @@ -260838,11 +260911,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 0 #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.0.0" #endif /* SQLITE3MC_VERSION_H_ */ /*** End of #include "sqlite3mc_version.h" ***/ @@ -261001,9 +261074,9 @@ 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.47.2" +#define SQLITE_VERSION_NUMBER 3047002 +#define SQLITE_SOURCE_ID "2024-12-07 20:39:59 2aabe05e2e8cae4847a802ee2daddc1d7413d8fc560254d93ee3e72c14685b6c" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -261507,6 +261580,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 @@ -261523,6 +261603,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 @@ -261669,6 +261750,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 @@ -274431,106 +274513,7 @@ struct fts5_api { #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 /* @@ -274543,7 +274526,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 @@ -276618,7 +276602,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" ***/ /* @@ -277649,372 +277633,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 */ @@ -278420,6 +278038,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 */ @@ -278456,6 +278105,7 @@ aesHardwareCheck() #include #include +SQLITE3MC_FUNC_ISA("sse4.2,aes") static int aesGenKeyEncryptInternal(const unsigned char* userKey, const int bits, __m128i* keyData) { @@ -278509,6 +278159,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) { @@ -278531,6 +278182,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) { @@ -278565,6 +278217,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, @@ -278632,6 +278285,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, @@ -280830,6 +280484,41734 @@ void RijndaelInvalidate(Rijndael* rijndael) /*** End of #include "rijndael.c" ***/ #endif + +#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" ***/ +/* +** Name: libaegis.c +** Purpose: Amalgamation of the AEGIS library +** Copyright: (c) 2024-2024 Ulrich Telle +** SPDX-License-Identifier: MIT +*/ + +/* +** AEGIS library source code +*/ + +#ifndef AEGIS_API +#define AEGIS_API +#endif +#ifndef AEGIS_PRIVATE +#define AEGIS_PRIVATE static +#endif + +/* #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 +*/ + +#ifndef AEGIS_CPU_H +#define AEGIS_CPU_H + +/* #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 +*/ + +#ifndef AEGIS_AES_HARDWARE_H +#define AEGIS_AES_HARDWARE_H + +#define AEGIS_AES_HARDWARE_NONE 0 +#define AEGIS_AES_HARDWARE_NI 1 +#define AEGIS_AES_HARDWARE_NEON 2 +#define AEGIS_AES_HARDWARE_ALTIVEC 3 + +#ifndef AEGIS_OMIT_AES_HARDWARE_SUPPORT + +#if defined __ARM_FEATURE_CRYPTO +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NEON + + +/* --- CLang --- */ +#elif defined(__clang__) + +#if __has_attribute(target) && __has_include() && (defined(__x86_64__) || defined(__i386)) +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NI + +#elif __has_attribute(target) && __has_include() && (defined(__aarch64__)) +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NEON + +#endif + + +/* --- GNU C/C++ */ +#elif defined(__GNUC__) + +#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 + + +/* --- Visual C/C++ --- */ +#elif defined (_MSC_VER) + +/* Architecture: x86 or x86_64 */ +#if (defined(_M_X64) || defined(_M_IX86)) && _MSC_FULL_VER >= 150030729 +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NI + +/* Architecture: ARM 64-bit */ +#elif defined(_M_ARM64) +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NEON + +/* Use header instead of */ +#ifndef USE_ARM64_NEON_H +#define USE_ARM64_NEON_H +#endif + +/* Architecture: ARM 32-bit */ +#elif defined _M_ARM +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NEON + +/* 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 + +#endif + +#else + +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NONE + +#endif + +#if HAS_AEGIS_AES_HARDWARE == AEGIS_AES_HARDWARE_NONE + +/* 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 + +#endif + +#else /* AEGIS_OMIT_AES_HARDWARE_SUPPORT defined */ + +/* Omit AES hardware support */ +#define HAS_AEGIS_AES_HARDWARE AEGIS_AES_HARDWARE_NONE + +#endif /* SQLITE3MC_OMIT_AES_HARDWARE_SUPPORT */ + +#endif /* AEGIS_AES_HARDWARE_H */ +/*** End of #include "aeshardware.h" ***/ + + +AEGIS_PRIVATE +int aegis_runtime_get_cpu_features(void); + +AEGIS_PRIVATE +int aegis_runtime_has_neon(void); + +AEGIS_PRIVATE +int aegis_runtime_has_armcrypto(void); + +AEGIS_PRIVATE +int aegis_runtime_has_avx(void); + +AEGIS_PRIVATE +int aegis_runtime_has_avx2(void); + +AEGIS_PRIVATE +int aegis_runtime_has_avx512f(void); + +AEGIS_PRIVATE +int aegis_runtime_has_aesni(void); + +AEGIS_PRIVATE +int aegis_runtime_has_vaes(void); + +AEGIS_PRIVATE +int aegis_runtime_has_altivec(void); + +#endif /* AEGIS_CPU_H */ +/*** End of #include "common/cpu.h" ***/ + + +/* 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 +*/ + +#include +#include + +/* #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 +*/ + +#ifndef AEGIS_COMMON_H +#define AEGIS_COMMON_H + +#include +#include +#include +#include + +/* #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 +*/ + +#ifndef AEGIS_H +#define AEGIS_H + +#include + +#if !defined(__clang__) && !defined(__GNUC__) +# ifdef __attribute__ +# undef __attribute__ +# endif +# define __attribute__(a) +#endif + +#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 + +#ifndef AEGIS_API +#define AEGIS_API +#endif +#ifndef AEGIS_PRIVATE +#define AEGIS_PRIVATE static +#endif + +/* #include "aegis128l.h" */ +/*** Begin of #include "aegis128l.h" ***/ +/* +** Name: aegis128l.h +** Purpose: Header for AEGIS-128L API +** Copyright: (c) 2023-2024 Frank Denis +** SPDX-License-Identifier: MIT +*/ + +#ifndef AEGIS128L_H +#define AEGIS128L_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The length of an AEGIS key, in bytes */ +#define aegis128l_KEYBYTES 16 + +/* The length of an AEGIS nonce, in bytes */ +#define aegis128l_NPUBBYTES 16 + +/* The minimum length of an AEGIS authentication tag, in bytes */ +#define aegis128l_ABYTES_MIN 16 + +/* The maximum length of an AEGIS authentication tag, in bytes */ +#define aegis128l_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 aegis128l_TAILBYTES_MAX 31 + +/* An AEGIS state, for incremental updates */ +typedef struct aegis128l_state { + CRYPTO_ALIGN(32) uint8_t opaque[256]; +} aegis128l_state; + +/* An AEGIS state, only for MAC updates */ +typedef struct aegis128l_mac_state { + CRYPTO_ALIGN(32) uint8_t opaque[384]; +} aegis128l_mac_state; + + +/* The length of an AEGIS key, in bytes */ +AEGIS_API +size_t aegis128l_keybytes(void); + +/* The length of an AEGIS nonce, in bytes */ +AEGIS_API +size_t aegis128l_npubbytes(void); + +/* The minimum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis128l_abytes_min(void); + +/* The maximum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis128l_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 aegis128l_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 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); + +/* + * 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)); + +/* + * 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); + +/* + * 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)); + +#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 aegis128l_state_init(aegis128l_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 aegis128l_state_encrypt_update(aegis128l_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 aegis128l_state_encrypt_detached_final(aegis128l_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 aegis128l_state_encrypt_final(aegis128l_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 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)); + +/* + * 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)); + +#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 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); + +/* + * 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); + +#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); + +/* + * 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); + +/* + * 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); + +/* + * 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); + +/* + * Reset an AEGIS_MAC state. + */ +AEGIS_API +void aegis128l_mac_reset(aegis128l_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 aegis128l_mac_state_clone(aegis128l_mac_state *dst, const aegis128l_mac_state *src); + +#endif /* AEGIS_OMIT_MAC_API */ + +#ifdef __cplusplus +} +#endif + +#endif /* AEGIS128L_H */ +/*** End of #include "aegis128l.h" ***/ + +/* #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 +*/ + +#ifndef AEGIS128X2_H +#define AEGIS128X2_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The length of an AEGIS key, in bytes */ +#define aegis128x2_KEYBYTES 16 + +/* The length of an AEGIS nonce, in bytes */ +#define aegis128x2_NPUBBYTES 16 + +/* The minimum length of an AEGIS authentication tag, in bytes */ +#define aegis128x2_ABYTES_MIN 16 + +/* The maximum length of an AEGIS authentication tag, in bytes */ +#define aegis128x2_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 aegis128x2_TAILBYTES_MAX 63 + +/* An AEGIS state, for incremental updates */ +typedef struct aegis128x2_state { + CRYPTO_ALIGN(64) uint8_t opaque[448]; +} aegis128x2_state; + +/* An AEGIS state, only for MAC updates */ +typedef struct aegis128x2_mac_state { + CRYPTO_ALIGN(64) uint8_t opaque[704]; +} aegis128x2_mac_state; + +/* The length of an AEGIS key, in bytes */ +AEGIS_API +size_t aegis128x2_keybytes(void); + +/* The length of an AEGIS nonce, in bytes */ +AEGIS_API +size_t aegis128x2_npubbytes(void); + +/* The minimum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis128x2_abytes_min(void); + +/* The maximum length of an AEGIS authentication tag, in bytes */ +AEGIS_API +size_t aegis128x2_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 aegis128x2_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 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); + +/* + * 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)); + +/* + * 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)); + +#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 aegis128x2_state_init(aegis128x2_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 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 +# endif +# if defined(__clang__) || defined(__GNUC__) +# if __has_include() +# define HAVE_ANDROID_GETCPUFEATURES +# endif +# 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 +#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 + +#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 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(); +} +/*** 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) + 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(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) + 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(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 + +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" ***/ + + +/* AEGIS 128 L */ +/* #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 "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 +*/ + +#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" */ + + +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" ***/ + + +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 +/*** End of #include "aegis128l/aegis128l_aesni.c" ***/ + +/* #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 +*/ + +#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" */ + + +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" ***/ + + +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 +/*** End of #include "aegis128l/aegis128l_altivec.c" ***/ + +/* #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" */ + + +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" ***/ + + +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 "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" */ + + +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" ***/ + + +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 "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" ***/ + + +/* AEGIS 128 x2 */ +/* #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 "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 +*/ + +#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" */ + + +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, 32); + 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 + 16, 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" ***/ + + +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 +/*** End of #include "aegis128x2/aegis128x2_aesni.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 +*/ + +#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" */ + + +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, 32); + 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 + 16, 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" ***/ + + +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 +/*** End of #include "aegis128x2/aegis128x2_altivec.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" */ + + +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, 32); + 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 + 16, 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" ***/ + + +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 "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 +*/ + +#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 +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, 32); + 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 + 16, 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" ***/ + + +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 +/*** End of #include "aegis128x2/aegis128x2_avx2.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" */ + + +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, 32); + 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 + 16, 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" ***/ + + +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 "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" ***/ + + +/* AEGIS 128 x4 */ +/* #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 "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 +*/ + +#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" */ + + +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, 32); + 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 + 16, 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" ***/ + + +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 +/*** End of #include "aegis128x4/aegis128x4_aesni.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 +*/ + +#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" */ + + +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, 32); + 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 + 16, 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" ***/ + + +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 +/*** End of #include "aegis128x4/aegis128x4_altivec.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" */ + + +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, 32); + 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 + 16, 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" ***/ + + +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 "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 +*/ + +#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 +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, 32); + 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 + 16, 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" ***/ + + +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 +/*** End of #include "aegis128x4/aegis128x4_avx2.c" ***/ + +/* #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 +*/ + +#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 +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 +# 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 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) +{ + return _mm512_broadcast_i32x4(_mm_set_epi64x(a, b)); +} + +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, 32); + 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 + 16, 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" ***/ + + +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 +/*** End of #include "aegis128x4/aegis128x4_avx512.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" */ + + +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, 32); + 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 + 16, 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" ***/ + + +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 "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" ***/ + + +/* AEGIS 256 */ +/* #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 "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 +*/ + +#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" */ + + +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" ***/ + + +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 +/*** End of #include "aegis256/aegis256_aesni.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 +*/ + +#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" */ + + +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" ***/ + + +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 +/*** End of #include "aegis256/aegis256_altivec.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" */ + + +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" ***/ + + +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 "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" */ + + +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" ***/ + + +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 "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" ***/ + + +/* AEGIS 256 x2 */ +/* #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 "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 +*/ + +#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" */ + + +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" ***/ + + +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 +/*** End of #include "aegis256x2/aegis256x2_aesni.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 +*/ + +#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" */ + + +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" ***/ + + +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 +/*** End of #include "aegis256x2/aegis256x2_altivec.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" */ + + +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" ***/ + + +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 "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 +*/ + +#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 +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" ***/ + + +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 +/*** End of #include "aegis256x2/aegis256x2_avx2.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" */ + + +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" ***/ + + +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 "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" ***/ + + +/* AEGIS 256 x4 */ +/* #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" ***/ + +/* #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 +*/ + +#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" */ + + +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" ***/ + + +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 +/*** End of #include "aegis256x4/aegis256x4_aesni.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 +*/ + +#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" */ + + +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" ***/ + + +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 +/*** End of #include "aegis256x4/aegis256x4_altivec.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" */ + + +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" ***/ + + +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" ***/ + +/* #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 +*/ + +#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 +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" ***/ + + +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 +/*** End of #include "aegis256x4/aegis256x4_avx2.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 +*/ + +#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 +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 +# 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) +{ + return _mm512_broadcast_i32x4(_mm_set_epi64x(a, b)); +} + +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" ***/ + + +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 +/*** End of #include "aegis256x4/aegis256x4_avx512.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" */ + + +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" ***/ + + +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" ***/ + +/* #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" ***/ + +/*** 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_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 + +/* + * 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). */ +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. */ +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" ***/ /* @@ -284549,6 +325931,518 @@ 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-2024 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 }, + 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_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; + } + } + return aegisCipher; +} + +static void +FreeAegisCipher(void* cipher) +{ + AegisCipher* aegisCipher = (AegisCipher*) cipher; + memset(aegisCipher, 0, 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_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 bypass = 0; + + int keyOnly = 1; + if (rekey || cipherSalt == NULL) + { + chacha20_rng(aegisCipher->m_salt, SALTLENGTH_AEGIS); + keyOnly = 0; + } + else + { + memcpy(aegisCipher->m_salt, cipherSalt, SALTLENGTH_AEGIS); + } + + /* 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; + if (nRaw == aegisCipher->m_keyLength) + { + /* Binary key */ + memcpy(aegisCipher->m_key, zRaw, aegisCipher->m_keyLength); + bypass = 1; + } + else if (nRaw == aegisCipher->m_keyLength + SALTLENGTH_AEGIS) + { + /* Binary key and salt) */ + if (!keyOnly) + { + memcpy(aegisCipher->m_salt, zRaw + aegisCipher->m_keyLength, SALTLENGTH_AEGIS); + } + memcpy(aegisCipher->m_key, zRaw, aegisCipher->m_keyLength); + bypass = 1; + } + else if (nRaw == 2 * aegisCipher->m_keyLength) + { + /* Hex-encoded key */ + if (sqlite3mcIsHexKey(zRaw, nRaw) != 0) + { + sqlite3mcConvertHex2Bin(zRaw, nRaw, aegisCipher->m_key); + bypass = 1; + } + } + else if (nRaw == 2 * (aegisCipher->m_keyLength + SALTLENGTH_AEGIS)) + { + /* Hex-encoded key and salt */ + if (sqlite3mcIsHexKey(zRaw, nRaw) != 0) + { + sqlite3mcConvertHex2Bin(zRaw, 2 * aegisCipher->m_keyLength, aegisCipher->m_key); + if (!keyOnly) + { + sqlite3mcConvertHex2Bin(zRaw + 2 * aegisCipher->m_keyLength, 2 * SALTLENGTH_AEGIS, aegisCipher->m_salt); + } + bypass = 1; + } + } + } + + 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; + + /* Generate one-time keys */ + uint8_t otk[OTK_LEN_MAX_AEGIS]; + int offset; + memset(otk, 0, OTK_LEN_MAX_AEGIS); + + /* 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); + + offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0; + 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) + { + 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 */ + offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0; + mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].encryptNoTag( + data + offset, + data + offset, mlen - offset, + otk + aegisCipher->m_keyLength, otk); + + if (page == 1) + { + memcpy(data, aegisCipher->m_salt, SALTLENGTH_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; + + /* Generate one-time keys */ + uint8_t otk[OTK_LEN_MAX_AEGIS]; + int offset; + memset(otk, 0, OTK_LEN_MAX_AEGIS); + + /* 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 */ + offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0; + + 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 && 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 */ + offset = (page == 1) ? CIPHER_PAGE1_OFFSET : 0; + mcAegisCryptFunctions[aegisCipher->m_aegisAlgorithm].decryptNoTag( + data + offset, + data + offset, clen - offset, + otk + aegisCipher->m_keyLength, otk); + + if (page == 1) + { + memcpy(data, SQLITE_FILE_HEADER, 16); + } + } + + 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" ***/ /* @@ -284670,8 +326564,9 @@ sqlite3mcCloneCodecParameterTable() } SQLITE_PRIVATE void -sqlite3mcFreeCodecParameterTable(CodecParameter* codecParams) +sqlite3mcFreeCodecParameterTable(void* ptr) { + CodecParameter* codecParams = (CodecParameter*)ptr; sqlite3_free(codecParams[0].m_params); sqlite3_free(codecParams); } @@ -286043,12 +327938,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 */ @@ -286332,6 +328260,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; @@ -286342,7 +328283,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 @@ -286537,7 +328487,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.47.2 amalgamation. */ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3mcRunVacuumForRekey( char **pzErrMsg, /* Write error message here */ @@ -287280,7 +329230,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); @@ -287301,7 +329251,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); @@ -290374,9 +332324,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" ***/ @@ -291327,15 +333275,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, @@ -291364,9 +333312,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" ***/ @@ -293376,11 +335322,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, @@ -293415,9 +335360,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" ***/ @@ -294233,11 +336176,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, @@ -294285,9 +336227,7 @@ int sqlite3_shathree_init( */ #ifdef SQLITE_ENABLE_CARRAY /* Prototype for initialization function of CARRAY extension */ -#ifdef _WIN32 -__declspec(dllexport) -#endif +SQLITE_API int sqlite3_carray_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* pApi); /* #include "carray.c" */ /*** Begin of #include "carray.c" ***/ @@ -294370,14 +336310,6 @@ SQLITE_EXTENSION_INIT1 # 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 /* @@ -294835,7 +336767,11 @@ static void inttoptrFunc( #endif /* SQLITE_OMIT_VIRTUALTABLE */ -SQLITE_API int sqlite3_carray_init( +#ifndef SQLITE_API +#define SQLITE_API +#endif +SQLITE_API +int sqlite3_carray_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi @@ -294862,9 +336798,7 @@ SQLITE_API int sqlite3_carray_init( */ #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 */ @@ -296251,9 +338185,10 @@ static int fsdirRegister(sqlite3 *db){ # define fsdirRegister(x) SQLITE_OK #endif -#ifdef _WIN32 -__declspec(dllexport) +#ifndef SQLITE_API +#define SQLITE_API #endif +SQLITE_API int sqlite3_fileio_init( sqlite3 *db, char **pzErrMsg, @@ -296297,9 +338232,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" ***/ @@ -296965,7 +338898,7 @@ static int seriesBestIndex( continue; } if( pConstraint->iColumniColumn==SERIES_COLUMN_VALUE ){ + if( pConstraint->iColumn==SERIES_COLUMN_VALUE && pConstraint->usable ){ switch( op ){ case SQLITE_INDEX_CONSTRAINT_EQ: case SQLITE_INDEX_CONSTRAINT_IS: { @@ -296973,7 +338906,9 @@ static int seriesBestIndex( idxNum &= ~0x3300; aIdx[5] = i; aIdx[6] = -1; +#ifndef ZERO_ARGUMENT_GENERATE_SERIES bStartSeen = 1; +#endif break; } case SQLITE_INDEX_CONSTRAINT_GE: { @@ -296981,7 +338916,9 @@ static int seriesBestIndex( idxNum |= 0x0100; idxNum &= ~0x0200; aIdx[5] = i; +#ifndef ZERO_ARGUMENT_GENERATE_SERIES bStartSeen = 1; +#endif break; } case SQLITE_INDEX_CONSTRAINT_GT: { @@ -296989,7 +338926,9 @@ static int seriesBestIndex( idxNum |= 0x0200; idxNum &= ~0x0100; aIdx[5] = i; +#ifndef ZERO_ARGUMENT_GENERATE_SERIES bStartSeen = 1; +#endif break; } case SQLITE_INDEX_CONSTRAINT_LE: { @@ -297119,9 +339058,10 @@ static sqlite3_module seriesModule = { #endif /* SQLITE_OMIT_VIRTUALTABLE */ -#ifdef _WIN32 -__declspec(dllexport) +#ifndef SQLITE_API +#define SQLITE_API #endif +SQLITE_API int sqlite3_series_init( sqlite3 *db, char **pzErrMsg, @@ -297148,9 +339088,7 @@ int sqlite3_series_init( */ #ifdef SQLITE_ENABLE_UUID /* Prototype for initialization function of UUID extension */ -#ifdef _WIN32 -__declspec(dllexport) -#endif +SQLITE_API int sqlite3_uuid_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* pApi); /* #include "uuid.c" */ /*** Begin of #include "uuid.c" ***/ @@ -297363,9 +339301,10 @@ static void sqlite3UuidBlobFunc( sqlite3_result_blob(context, pBlob, 16, SQLITE_TRANSIENT); } -#ifdef _WIN32 -__declspec(dllexport) +#ifndef SQLITE_API +#define SQLITE_API #endif +SQLITE_API int sqlite3_uuid_init( sqlite3 *db, char **pzErrMsg, @@ -297397,9 +339336,7 @@ int sqlite3_uuid_init( */ #ifdef SQLITE_ENABLE_REGEXP /* Prototype for initialization function of REGEXP extension */ -#ifdef _WIN32 -__declspec(dllexport) -#endif +SQLITE_API int sqlite3_regexp_init(sqlite3* db, char** pzErrMsg, const sqlite3_api_routines* pApi); /* #include "regexp.c" */ /*** Begin of #include "regexp.c" ***/ @@ -298250,14 +340187,14 @@ static void re_bytecode_func( #endif /* SQLITE_DEBUG */ - /* ** Invoke this routine to register the regexp() function with the ** SQLite database connection. */ -#ifdef _WIN32 -__declspec(dllexport) +#ifndef SQLITE_API +#define SQLITE_API #endif +SQLITE_API int sqlite3_regexp_init( sqlite3 *db, char **pzErrMsg, @@ -307388,9 +349325,7 @@ mz_bool mz_zip_end(mz_zip_archive *pZip) ** COMPRESS */ #ifdef SQLITE_ENABLE_COMPRESS -#ifdef _WIN32 -__declspec(dllexport) -#endif +SQLITE_API int sqlite3_compress_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi); /* #include "compress.c" */ /*** Begin of #include "compress.c" ***/ @@ -307530,10 +349465,10 @@ static void uncompressFunc( } } - -#ifdef _WIN32 -__declspec(dllexport) +#ifndef SQLITE_API +#define SQLITE_API #endif +SQLITE_API int sqlite3_compress_init( sqlite3 *db, char **pzErrMsg, @@ -307560,9 +349495,7 @@ int sqlite3_compress_init( ** SQLAR */ #ifdef SQLITE_ENABLE_SQLAR -#ifdef _WIN32 -__declspec(dllexport) -#endif +SQLITE_API int sqlite3_sqlar_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi); /* #include "sqlar.c" */ /*** Begin of #include "sqlar.c" ***/ @@ -307673,9 +349606,10 @@ static void sqlarUncompressFunc( } } -#ifdef _WIN32 -__declspec(dllexport) +#ifndef SQLITE_API +#define SQLITE_API #endif +SQLITE_API int sqlite3_sqlar_init( sqlite3 *db, char **pzErrMsg, @@ -307702,9 +349636,7 @@ int sqlite3_sqlar_init( ** ZIPFILE */ #ifdef SQLITE_ENABLE_ZIPFILE -#ifdef _WIN32 -__declspec(dllexport) -#endif +SQLITE_API int sqlite3_zipfile_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi); /* #include "zipfile.c" */ /*** Begin of #include "zipfile.c" ***/ @@ -309944,9 +351876,10 @@ static int zipfileRegister(sqlite3 *db){ # define zipfileRegister(x) SQLITE_OK #endif -#ifdef _WIN32 -__declspec(dllexport) +#ifndef SQLITE_API +#define SQLITE_API #endif +SQLITE_API int sqlite3_zipfile_init( sqlite3 *db, char **pzErrMsg, @@ -311526,7 +353459,7 @@ mcRegisterCodecExtensions(sqlite3* db, char** pzErrMsg, const sqlite3_api_routin if (rc == SQLITE_OK) { rc = sqlite3_create_function_v2(db, "sqlite3mc_config_table", 0, SQLITE_UTF8 | SQLITE_DETERMINISTIC, - codecParameterTable, sqlite3mcConfigTable, 0, 0, (void(*)(void*)) sqlite3mcFreeCodecParameterTable); + codecParameterTable, sqlite3mcConfigTable, 0, 0, sqlite3mcFreeCodecParameterTable); } rc = (codecParameterTable != NULL) ? SQLITE_OK : SQLITE_NOMEM; @@ -311826,6 +353759,12 @@ sqlite3mc_initialize(const char* arg) rc = sqlite3mcRegisterCipher(&mcAscon128Descriptor, mcAscon128Params, (CODEC_TYPE_ASCON128 == CODEC_TYPE)); } #endif +#if HAVE_CIPHER_AEGIS + if (rc == SQLITE_OK) + { + rc = sqlite3mcRegisterCipher(&mcAegisDescriptor, mcAegisParams, (CODEC_TYPE_AEGIS == CODEC_TYPE)); + } +#endif /* ** Initialize and register MultiCipher VFS as default VFS @@ -315974,12 +357913,15 @@ static const char *tclsh_main_loop(void){ #ifdef WIN32 "set new [list]\n" "foreach arg $argv {\n" - "if {[file exists $arg]} {\n" + "if {[string match -* $arg] || [file exists $arg]} {\n" "lappend new $arg\n" "} else {\n" + "set once 0\n" "foreach match [lsort [glob -nocomplain $arg]] {\n" "lappend new $match\n" + "set once 1\n" "}\n" + "if {!$once} {lappend new $arg}\n" "}\n" "}\n" "set argv $new\n" diff --git a/src/sqlite3mc_amalgamation.h b/src/sqlite3mc_amalgamation.h index c759b237..06d6de7c 100644 --- a/src/sqlite3mc_amalgamation.h +++ b/src/sqlite3mc_amalgamation.h @@ -29,11 +29,11 @@ #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 0 #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.0.0" #endif /* SQLITE3MC_VERSION_H_ */ /*** End of #include "sqlite3mc_version.h" ***/ @@ -192,9 +192,9 @@ 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.47.2" +#define SQLITE_VERSION_NUMBER 3047002 +#define SQLITE_SOURCE_ID "2024-12-07 20:39:59 2aabe05e2e8cae4847a802ee2daddc1d7413d8fc560254d93ee3e72c14685b6c" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -698,6 +698,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 @@ -714,6 +721,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 @@ -860,6 +868,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 @@ -13622,106 +13631,7 @@ struct fts5_api { #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 +13644,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 diff --git a/src/sqlite3mc_config.h b/src/sqlite3mc_config.h index 248efe4f..e4f2988e 100644 --- a/src/sqlite3mc_config.h +++ b/src/sqlite3mc_config.h @@ -3,7 +3,7 @@ ** Purpose: Header file for SQLite3 Multiple Ciphers compile-time configuration ** Author: Ulrich Telle ** Created: 2021-09-27 -** Copyright: (c) 2019-2023 Ulrich Telle +** Copyright: (c) 2019-2024 Ulrich Telle ** License: MIT */ @@ -41,6 +41,10 @@ #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 */ @@ -68,6 +72,18 @@ #define HAVE_CIPHER_ASCON128 1 #endif +#ifndef HAVE_CIPHER_AEGIS +#define HAVE_CIPHER_AEGIS 1 +#endif + +/* +** Define whether dynamic ciphers will be used +*/ + +#ifndef SQLITE3MC_HAVE_DYNAMIC_CIPHERS +#define SQLITE3MC_HAVE_DYNAMIC_CIPHERS 0 +#endif + /* ** Disable all built-in ciphers on request */ @@ -83,23 +99,27 @@ #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 /* ** Check that at least one cipher is be supported */ -#if HAVE_CIPHER_AES_128_CBC == 0 && \ +#if SQLITE3MC_HAVE_DYNAMIC_CIPHERS == 0 && \ + HAVE_CIPHER_AES_128_CBC == 0 && \ HAVE_CIPHER_AES_256_CBC == 0 && \ 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 diff --git a/src/wxsqlite3.cpp b/src/wxsqlite3.cpp index bd9d8f35..237448dc 100644 --- a/src/wxsqlite3.cpp +++ b/src/wxsqlite3.cpp @@ -3,7 +3,7 @@ ** Purpose: Implementation of wxSQLite3 classes ** Author: Ulrich Telle ** Created: 2005-07-06 -** Copyright: (c) 2005-2023 Ulrich Telle and the wxSQLite3 contributors +** Copyright: (c) 2005-2024 Ulrich Telle and the wxSQLite3 contributors ** SPDX-License-Identifier: LGPL-3.0+ WITH WxWindows-exception-3.1 */ @@ -55,9 +55,6 @@ typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*,const static int wxSQLite3FunctionContextExecAuthorizer(void* func, int type, const char* arg1, const char* arg2, const char* arg3, const char* arg4 -#if SQLITE_USER_AUTHENTICATION - , const char* arg5 -#endif ); // Error messages @@ -2514,11 +2511,7 @@ bool wxSQLite3Database::ms_hasMetaDataSupport = true; bool wxSQLite3Database::ms_hasMetaDataSupport = false; #endif -#if SQLITE_USER_AUTHENTICATION -bool wxSQLite3Database::ms_hasUserAuthentication = true; -#else bool wxSQLite3Database::ms_hasUserAuthentication = false; -#endif #if WXSQLITE3_HAVE_LOAD_EXTENSION bool wxSQLite3Database::ms_hasLoadExtSupport = true; @@ -4201,132 +4194,42 @@ wxString wxSQLite3Database::GetKeySalt(const wxString& schemaName) const bool wxSQLite3Database::UserLogin(const wxString& username, const wxString& password) { -#if SQLITE_USER_AUTHENTICATION - CheckDatabase(); - wxCharBuffer strUsername = username.ToUTF8(); - const char* localUsername = strUsername; - wxCharBuffer strPassword = password.ToUTF8(); - const char* localPassword = strPassword; - - int rc = sqlite3_user_authenticate(m_db->m_db, localUsername, localPassword, strlen(localPassword)); - bool authenticated = (rc == SQLITE_OK); - if (rc != SQLITE_OK && rc != SQLITE_AUTH) - { - const char* localError = sqlite3_errmsg(m_db->m_db); - throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); - } - return authenticated; -#else wxUnusedVar(username); wxUnusedVar(password); return true; -#endif } bool wxSQLite3Database::UserAdd(const wxString& username, const wxString& password, bool isAdmin) { -#if SQLITE_USER_AUTHENTICATION - CheckDatabase(); - wxCharBuffer strUsername = username.ToUTF8(); - const char* localUsername = strUsername; - wxCharBuffer strPassword = password.ToUTF8(); - const char* localPassword = strPassword; - int nIsAdmin = (isAdmin) ? 1 : 0; - int rc = sqlite3_user_add(m_db->m_db, localUsername, localPassword, strlen(localPassword), nIsAdmin); - bool authenticated = (rc == SQLITE_OK); - if (rc != SQLITE_OK && rc != SQLITE_AUTH) - { - const char* localError = sqlite3_errmsg(m_db->m_db); - throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); - } - return authenticated; -#else wxUnusedVar(username); wxUnusedVar(password); wxUnusedVar(isAdmin); return true; -#endif } bool wxSQLite3Database::UserChange(const wxString& username, const wxString& password, bool isAdmin) { -#if SQLITE_USER_AUTHENTICATION - CheckDatabase(); - wxCharBuffer strUsername = username.ToUTF8(); - const char* localUsername = strUsername; - wxCharBuffer strPassword = password.ToUTF8(); - const char* localPassword = strPassword; - int nIsAdmin = (isAdmin) ? 1 : 0; - int rc = sqlite3_user_change(m_db->m_db, localUsername, localPassword, strlen(localPassword), nIsAdmin); - bool authenticated = (rc == SQLITE_OK); - if (rc != SQLITE_OK && rc != SQLITE_AUTH) - { - const char* localError = sqlite3_errmsg(m_db->m_db); - throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); - } - return authenticated; -#else wxUnusedVar(username); wxUnusedVar(password); wxUnusedVar(isAdmin); return false; -#endif } bool wxSQLite3Database::UserDelete(const wxString& username) { -#if SQLITE_USER_AUTHENTICATION - CheckDatabase(); - wxCharBuffer strUsername = username.ToUTF8(); - const char* localUsername = strUsername; - - int rc = sqlite3_user_delete(m_db->m_db, localUsername); - bool authenticated = (rc == SQLITE_OK); - if (rc != SQLITE_OK && rc != SQLITE_AUTH) - { - const char* localError = sqlite3_errmsg(m_db->m_db); - throw wxSQLite3Exception(rc, wxString::FromUTF8(localError)); - } - return authenticated; -#else wxUnusedVar(username); return false; -#endif } bool wxSQLite3Database::UserIsPrivileged(const wxString& username) { -#if SQLITE_USER_AUTHENTICATION - CheckDatabase(); - bool isPrivileged = false; - wxString sql = wxS("select isAdmin from main.sqlite_user where uname=?;"); - wxSQLite3Statement stmt = PrepareStatement(sql); - stmt.Bind(1, username); - wxSQLite3ResultSet resultSet = stmt.ExecuteQuery(); - if (resultSet.NextRow()) - { - isPrivileged = resultSet.GetBool(0); - } - return isPrivileged; -#else wxUnusedVar(username); return false; -#endif } void wxSQLite3Database::GetUserList(wxArrayString& userList) { userList.Empty(); -#if SQLITE_USER_AUTHENTICATION - CheckDatabase(); - wxSQLite3ResultSet resultSet = ExecuteQuery("select uname from main.sqlite_user order by uname;"); - while (resultSet.NextRow()) - { - userList.Add(resultSet.GetString(0)); - } -#else - wxUnusedVar(userList); -#endif } int wxSQLite3Database::GetLimit(wxSQLite3LimitType id) const @@ -4779,20 +4682,13 @@ void wxSQLite3FunctionContext::ExecWindowInverse(void* ctx, int argc, void** arg static int wxSQLite3FunctionContextExecAuthorizer(void* func, int type, const char* arg1, const char* arg2, const char* arg3, const char* arg4 -#if SQLITE_USER_AUTHENTICATION - , const char* arg5 -#endif ) { wxString locArg1 = wxString::FromUTF8(arg1); wxString locArg2 = wxString::FromUTF8(arg2); wxString locArg3 = wxString::FromUTF8(arg3); wxString locArg4 = wxString::FromUTF8(arg4); -#if SQLITE_USER_AUTHENTICATION - wxString locArg5 = wxString::FromUTF8(arg5); -#else wxString locArg5 = wxEmptyString; -#endif wxSQLite3Authorizer::wxAuthorizationCode localType = (wxSQLite3Authorizer::wxAuthorizationCode) type; return (int) ((wxSQLite3Authorizer*) func)->Authorize(localType, locArg1, locArg2, locArg3, locArg4, locArg5); } @@ -6456,3 +6352,119 @@ wxSQLite3CipherAscon128::Apply(void* dbHandle) const throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_CIPHER_NOT_SUPPORTED); #endif } + +wxSQLite3CipherAegis::wxSQLite3CipherAegis() + : wxSQLite3Cipher(WXSQLITE_CIPHER_AEGIS), m_legacy(false), + m_tcost(2), m_mcost(19*1024), m_pcost(1), m_algorithm(ALGORITHM_AEGIS_256) +{ + SetInitialized(true); +} + +wxSQLite3CipherAegis::wxSQLite3CipherAegis(const wxSQLite3CipherAegis& cipher) + : wxSQLite3Cipher(cipher), m_legacy(cipher.m_legacy), + m_tcost(cipher.m_tcost), m_mcost(cipher.m_mcost), m_pcost(cipher.m_pcost), + m_algorithm(cipher.m_algorithm) +{ +} + +wxSQLite3CipherAegis::~wxSQLite3CipherAegis() +{ +} + +bool +wxSQLite3CipherAegis::InitializeFromGlobalDefault() +{ +#if HAVE_CIPHER_AEGIS +#if 0 + int legacy = sqlite3mc_config_cipher(0, "aegis", "legacy", -1); + m_legacy = legacy != 0; +#endif + m_tcost = sqlite3mc_config_cipher(0, "aegis", "tcost", -1); + m_mcost = sqlite3mc_config_cipher(0, "aegis", "mcost", -1); + m_pcost = sqlite3mc_config_cipher(0, "aegis", "pcost", -1); + int algorithm = (Algorithm)sqlite3mc_config_cipher(0, "aegis", "algorithm", -1); + if (algorithm > 0) m_algorithm = (Algorithm)algorithm; + bool initialized = m_tcost > 0 && m_mcost > 0 && m_pcost > 0 && m_algorithm > 0; + SetInitialized(initialized); + return initialized; +#else + throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_CIPHER_NOT_SUPPORTED); +#endif +} + +bool +wxSQLite3CipherAegis::InitializeFromCurrent(wxSQLite3Database& db) +{ +#if HAVE_CIPHER_AEGIS + sqlite3* dbHandle = (sqlite3*) GetDatabaseHandle(db); +#if 0 + int legacy = sqlite3mc_config_cipher(dbHandle, "aegis", "legacy", -1); + m_legacy = legacy != 0; +#endif + m_tcost = sqlite3mc_config_cipher(dbHandle, "aegis", "tcost", -1); + m_mcost = sqlite3mc_config_cipher(dbHandle, "aegis", "mcost", -1); + m_pcost = sqlite3mc_config_cipher(dbHandle, "aegis", "pcost", -1); + int algorithm = (Algorithm) sqlite3mc_config_cipher(dbHandle, "aegis", "algorithm", -1); + if (algorithm > 0) m_algorithm = (Algorithm) algorithm; + bool initialized = m_tcost > 0 && m_mcost > 0 && m_pcost > 0 && m_algorithm > 0; + SetInitialized(initialized); + return initialized; +#else + throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_CIPHER_NOT_SUPPORTED); +#endif +} + +bool +wxSQLite3CipherAegis::InitializeFromCurrentDefault(wxSQLite3Database& db) +{ +#if HAVE_CIPHER_AEGIS + sqlite3* dbHandle = (sqlite3*) GetDatabaseHandle(db); +#if 0 + int legacy = sqlite3mc_config_cipher(dbHandle, "aegis", "default:legacy", -1); + m_legacy = legacy != 0; +#endif + m_tcost = sqlite3mc_config_cipher(dbHandle, "aegis", "default:tcost", -1); + m_mcost = sqlite3mc_config_cipher(dbHandle, "aegis", "default:mcost", -1); + m_pcost = sqlite3mc_config_cipher(dbHandle, "aegis", "default:pcost", -1); + int algorithm = sqlite3mc_config_cipher(dbHandle, "aegis", "default:algorithm", -1); + if (algorithm > 0) m_algorithm = (Algorithm) algorithm; + bool initialized = m_tcost > 0 && m_mcost > 0 && m_pcost > 0 && m_algorithm > 0; + SetInitialized(initialized); + return initialized; +#else + throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_CIPHER_NOT_SUPPORTED); +#endif +} + +bool +wxSQLite3CipherAegis::Apply(wxSQLite3Database& db) const +{ + return Apply(GetDatabaseHandle(db)); +} + +bool +wxSQLite3CipherAegis::Apply(void* dbHandle) const +{ +#if HAVE_CIPHER_AEGIS + bool applied = false; + if (IsOk()) + { + if (dbHandle != NULL) + { + int newCipherType = sqlite3mc_config((sqlite3*) dbHandle, "cipher", sqlite3mc_cipher_index("aegis")); +#if 0 + int legacy = sqlite3mc_config_cipher((sqlite3*) dbHandle, "aegis", "legacy", (m_legacy) ? 1 : 0); + int legacyPageSize = sqlite3mc_config_cipher((sqlite3*) dbHandle, "aegis", "legacy_page_size", GetLegacyPageSize()); +#endif + int tcost = sqlite3mc_config_cipher((sqlite3*) dbHandle, "aegis", "tcost", m_tcost); + int mcost = sqlite3mc_config_cipher((sqlite3*) dbHandle, "aegis", "mcost", m_mcost); + int pcost = sqlite3mc_config_cipher((sqlite3*) dbHandle, "aegis", "pcost", m_pcost); + int algorithm = sqlite3mc_config_cipher((sqlite3*) dbHandle, "aegis", "algorithm", (int) m_algorithm); + applied = (newCipherType > 0) && (tcost > 0) && (mcost > 0) && (pcost > 0) && (algorithm > 0); + } + } + return applied; +#else + throw wxSQLite3Exception(WXSQLITE_ERROR, wxERRMSG_CIPHER_NOT_SUPPORTED); +#endif +}