mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-08-04 03:54:10 +02:00
Falcon: native wolfCrypt implementation (no liboqs)
Add a complete native Falcon post-quantum lattice signature implementation to
wolfCrypt, replacing the liboqs wrapper. Full key generation, signing and
verification for Falcon-512 (level 1) and Falcon-1024 (level 5).
- Public API wc_falcon_* / falcon_key in falcon.c wraps the native core
(falcon_native_* in wc_falcon.c) plus wc_falcon_{fpr,fft,poly,sampler,
codec,keygen,sign,bigint}.c. No liboqs dependency.
- Portable, constant-time integer-emulated floating-point (fpr) backend is
the default; opt-in per-architecture acceleration:
--enable-falcon-double inline native double
--enable-falcon-asm x86-64 SSE2 out-of-line fpr asm
--enable-falcon-avx2 x86-64 AVX2 (4-wide) FFT
- Division-free (Barrett) integer NTT on the verify path, so no hardware
divide is required on Cortex-M / embedded targets.
- Verify uses a cached twiddle-factor NTT; signing uses the FFT / ffLDL tree
and discrete Gaussian sampler over the abstract fpr seam.
- test.c falcon_test (KAT verify + native keygen/sign/verify roundtrip);
scripts/falcon-interop.c and a CI workflow cross-check native<->liboqs in
both directions.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
name: FN-DSA (Falcon) native<->liboqs interop Tests
|
||||
|
||||
# START OF COMMON SECTION
|
||||
on:
|
||||
push:
|
||||
branches: [ 'release/**' ]
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
branches: [ '*' ]
|
||||
# Daily run on master reseeds the shared cache (see save steps below).
|
||||
schedule:
|
||||
- cron: '40 4 * * *'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
# END OF COMMON SECTION
|
||||
|
||||
env:
|
||||
# liboqs version pinned for the differential/interop baseline.
|
||||
LIBOQS_REF: 0.10.1
|
||||
|
||||
jobs:
|
||||
build_liboqs:
|
||||
name: Build liboqs
|
||||
if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checking if we have liboqs in cache
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache
|
||||
with:
|
||||
path: oqs-install
|
||||
key: liboqs-${{ env.LIBOQS_REF }}-ubuntu-24.04
|
||||
lookup-only: true
|
||||
|
||||
- name: Checkout liboqs
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: open-quantum-safe/liboqs
|
||||
ref: ${{ env.LIBOQS_REF }}
|
||||
path: liboqs
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Compile and install liboqs
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
working-directory: liboqs
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -GNinja \
|
||||
-DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/oqs-install \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DOQS_USE_OPENSSL=OFF \
|
||||
-DOQS_BUILD_ONLY_LIB=ON \
|
||||
..
|
||||
ninja
|
||||
ninja install
|
||||
|
||||
# Only master (the daily schedule) saves, so all PRs share one entry.
|
||||
- name: Save liboqs cache
|
||||
if: github.ref == 'refs/heads/master' && steps.cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: oqs-install
|
||||
key: liboqs-${{ env.LIBOQS_REF }}-ubuntu-24.04
|
||||
|
||||
# On a cache miss, hand the freshly built liboqs to the test job via an
|
||||
# artifact so it is not compiled a second time in the same run.
|
||||
- name: tar liboqs
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: tar -zcf liboqs.tgz oqs-install
|
||||
|
||||
- name: Upload liboqs build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: liboqs
|
||||
path: liboqs.tgz
|
||||
retention-days: 1
|
||||
|
||||
falcon_interop:
|
||||
name: Interop (native FN-DSA vs liboqs Falcon)
|
||||
if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }}
|
||||
runs-on: ubuntu-24.04
|
||||
needs: build_liboqs
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Install build tools
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ninja-build
|
||||
|
||||
- name: Restore liboqs from cache
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache
|
||||
with:
|
||||
path: oqs-install
|
||||
key: liboqs-${{ env.LIBOQS_REF }}-ubuntu-24.04
|
||||
|
||||
# On a cache miss the build_liboqs job uploaded an artifact instead.
|
||||
- name: Download liboqs artifact
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: liboqs
|
||||
|
||||
- name: Untar liboqs artifact
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: tar -zxf liboqs.tgz
|
||||
|
||||
- name: Checkout wolfSSL
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Build wolfSSL with native FN-DSA
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --enable-falcon --enable-experimental --enable-static
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Build and run the interop harness (native FN-DSA vs liboqs)
|
||||
run: |
|
||||
gcc -O2 -I. -I$GITHUB_WORKSPACE/oqs-install/include \
|
||||
scripts/falcon-interop.c \
|
||||
src/.libs/libwolfssl.a \
|
||||
$GITHUB_WORKSPACE/oqs-install/lib/liboqs.a \
|
||||
-lm -lcrypto -lpthread -o falcon-interop
|
||||
./falcon-interop
|
||||
@@ -997,6 +997,22 @@ if (WOLFSSL_MLDSA OR WOLFSSL_DILITHIUM)
|
||||
set_wolfssl_definitions("WOLFSSL_SHAKE256" RESULT)
|
||||
endif()
|
||||
|
||||
# FN-DSA (native Falcon, FIPS 206 draft). Native implementation: no liboqs
|
||||
# dependency (unlike WOLFSSL_FALCON). Needs SHA-3 / SHAKE256 for hash-to-point.
|
||||
add_option(WOLFSSL_FALCON
|
||||
"Enable the native wolfSSL PQ FN-DSA/Falcon (FIPS 206) implementation (default: disabled)"
|
||||
"no" "yes;no")
|
||||
|
||||
if (WOLFSSL_FALCON)
|
||||
list(APPEND WOLFSSL_DEFINITIONS "-DHAVE_FALCON")
|
||||
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHA3")
|
||||
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHAKE256")
|
||||
|
||||
set_wolfssl_definitions("HAVE_FALCON" RESULT)
|
||||
set_wolfssl_definitions("WOLFSSL_SHA3" RESULT)
|
||||
set_wolfssl_definitions("WOLFSSL_SHAKE256" RESULT)
|
||||
endif()
|
||||
|
||||
# LMS
|
||||
add_option(WOLFSSL_LMS
|
||||
"Enable the PQ LMS Stateful Hash-based Signature Scheme (default: disabled)"
|
||||
|
||||
@@ -259,6 +259,9 @@ function(generate_build_flags)
|
||||
if(WOLFSSL_MLDSA OR WOLFSSL_DILITHIUM OR WOLFSSL_USER_SETTINGS)
|
||||
set(BUILD_MLDSA "yes" PARENT_SCOPE)
|
||||
endif()
|
||||
if(WOLFSSL_FALCON OR WOLFSSL_USER_SETTINGS)
|
||||
set(BUILD_FALCON "yes" PARENT_SCOPE)
|
||||
endif()
|
||||
if(WOLFSSL_FALCON OR WOLFSSL_USER_SETTINGS)
|
||||
set(BUILD_FALCON "yes" PARENT_SCOPE)
|
||||
set(BUILD_OQS_HELPER "yes" PARENT_SCOPE)
|
||||
@@ -1149,6 +1152,18 @@ function(generate_lib_src_list LIB_SOURCES)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_FALCON)
|
||||
list(APPEND LIB_SOURCES wolfcrypt/src/wc_falcon.c)
|
||||
list(APPEND LIB_SOURCES wolfcrypt/src/wc_falcon_fpr.c)
|
||||
list(APPEND LIB_SOURCES wolfcrypt/src/wc_falcon_fft.c)
|
||||
list(APPEND LIB_SOURCES wolfcrypt/src/wc_falcon_poly.c)
|
||||
list(APPEND LIB_SOURCES wolfcrypt/src/wc_falcon_sampler.c)
|
||||
list(APPEND LIB_SOURCES wolfcrypt/src/wc_falcon_codec.c)
|
||||
list(APPEND LIB_SOURCES wolfcrypt/src/wc_falcon_bigint.c)
|
||||
list(APPEND LIB_SOURCES wolfcrypt/src/wc_falcon_keygen.c)
|
||||
list(APPEND LIB_SOURCES wolfcrypt/src/wc_falcon_sign.c)
|
||||
endif()
|
||||
|
||||
if(BUILD_WC_MLKEM)
|
||||
list(APPEND LIB_SOURCES wolfcrypt/src/wc_mlkem.c)
|
||||
list(APPEND LIB_SOURCES wolfcrypt/src/wc_mlkem_poly.c)
|
||||
|
||||
+96
-10
@@ -1868,21 +1868,72 @@ AC_ARG_WITH([liboqs],
|
||||
]
|
||||
)
|
||||
|
||||
# Falcon (provided via liboqs)
|
||||
# Falcon (legacy name for FN-DSA, now provided by the native implementation)
|
||||
# Falcon post-quantum signatures. "Falcon" is the pre-standardization name; NIST
|
||||
# is standardizing this scheme as FN-DSA (FIPS 206, draft). This is the native
|
||||
# wolfCrypt implementation (no liboqs); it needs SHA-3 / SHAKE256 (forced on in
|
||||
# the CFLAG section below). Because the algorithm is not yet standardized and its
|
||||
# API name is subject to change, it requires --enable-experimental (checked in
|
||||
# the CFLAG section, once all backend sub-options have been resolved).
|
||||
AC_ARG_ENABLE([falcon],
|
||||
[AS_HELP_STRING([--enable-falcon],[Enable Falcon post-quantum signatures via liboqs (default: disabled)])],
|
||||
[AS_HELP_STRING([--enable-falcon],[Enable Falcon post-quantum signatures (native, no liboqs; pre-standardization name for FN-DSA; requires --enable-experimental) (default: disabled)])],
|
||||
[ ENABLED_FALCON=$enableval ],
|
||||
[ ENABLED_FALCON=no ])
|
||||
|
||||
if test "$ENABLED_FALCON" = "yes" && test "$ENABLED_LIBOQS" = "no"; then
|
||||
AC_MSG_ERROR([--enable-falcon requires --with-liboqs.])
|
||||
fi
|
||||
if test "$ENABLED_LIBOQS" = "yes" && test "$ENABLED_FALCON" != "yes"; then
|
||||
AC_MSG_ERROR([--with-liboqs requires --enable-falcon.])
|
||||
# --enable-falcon-asm selects the per-architecture assembly fpr backend for
|
||||
# FN-DSA (currently x86-64 SSE2 only); the portable constant-time integer
|
||||
# emulation remains the default. It implies --enable-falcon.
|
||||
AC_ARG_ENABLE([falcon-asm],
|
||||
[AS_HELP_STRING([--enable-falcon-asm],[Enable FN-DSA x86-64 assembly fpr backend (default: disabled)])],
|
||||
[ ENABLED_FALCON_ASM=$enableval ],
|
||||
[ ENABLED_FALCON_ASM=no ])
|
||||
if test "$ENABLED_FALCON_ASM" = "yes"; then
|
||||
case $host_cpu in
|
||||
*x86_64*|*amd64*) ENABLED_FALCON=yes ;;
|
||||
*) AC_MSG_WARN([--enable-falcon-asm is only supported on x86-64; ignoring.])
|
||||
ENABLED_FALCON_ASM=no ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test "$ENABLED_FALCON" = "yes"; then
|
||||
AM_CFLAGS="$AM_CFLAGS -DHAVE_FALCON"
|
||||
# --enable-falcon-double selects the inline native-double fpr backend: the fpr
|
||||
# ops become static-inline C double operations, so the FFT/sampler inline them
|
||||
# and keep values in FP registers (no per-op call). This is the fastest backend
|
||||
# on any platform with a constant-time hardware double FPU (signing ~2.5x faster
|
||||
# than the out-of-line asm backend, ~16x faster than the portable emulation),
|
||||
# but like --enable-falcon-asm it relies on the native FPU's rounding behavior.
|
||||
# It implies --enable-falcon and is mutually exclusive with --enable-falcon-asm.
|
||||
AC_ARG_ENABLE([falcon-double],
|
||||
[AS_HELP_STRING([--enable-falcon-double],[Enable FN-DSA inline native-double fpr backend (default: disabled)])],
|
||||
[ ENABLED_FALCON_DOUBLE=$enableval ],
|
||||
[ ENABLED_FALCON_DOUBLE=no ])
|
||||
if test "$ENABLED_FALCON_DOUBLE" = "yes"; then
|
||||
if test "$ENABLED_FALCON_ASM" = "yes"; then
|
||||
AC_MSG_ERROR([--enable-falcon-double and --enable-falcon-asm are mutually exclusive.])
|
||||
fi
|
||||
ENABLED_FALCON=yes
|
||||
fi
|
||||
|
||||
# --enable-falcon-avx2 adds the AVX2 (4-wide __m256d + FMA) vectorized FFT and
|
||||
# FFT-domain polynomial operations for the signing path (x86-64). It composes
|
||||
# with --enable-falcon-double (which it implies). The AVX2 functions carry
|
||||
# target("avx2,fma") attributes, so the TU builds under a baseline -march; the
|
||||
# host must support AVX2+FMA at run time. Signing is sampler-bound, so the FFT
|
||||
# vectorization yields a modest (~1.1x) end-to-end speedup.
|
||||
AC_ARG_ENABLE([falcon-avx2],
|
||||
[AS_HELP_STRING([--enable-falcon-avx2],[Enable FN-DSA x86-64 AVX2 vectorized FFT (default: disabled)])],
|
||||
[ ENABLED_FALCON_AVX2=$enableval ],
|
||||
[ ENABLED_FALCON_AVX2=no ])
|
||||
if test "$ENABLED_FALCON_AVX2" = "yes"; then
|
||||
case $host_cpu in
|
||||
*x86_64*|*amd64*)
|
||||
if test "$ENABLED_FALCON_ASM" = "yes"; then
|
||||
AC_MSG_ERROR([--enable-falcon-avx2 and --enable-falcon-asm are mutually exclusive.])
|
||||
fi
|
||||
ENABLED_FALCON=yes
|
||||
ENABLED_FALCON_DOUBLE=yes ;;
|
||||
*) AC_MSG_WARN([--enable-falcon-avx2 is only supported on x86-64; ignoring.])
|
||||
ENABLED_FALCON_AVX2=no ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
||||
@@ -7895,6 +7946,12 @@ then
|
||||
ENABLED_SHAKE128=yes
|
||||
ENABLED_SHAKE256=yes
|
||||
fi
|
||||
# FN-DSA (native Falcon) uses SHA-3 / SHAKE256 for hash-to-point.
|
||||
if test "$ENABLED_FALCON" != "no"
|
||||
then
|
||||
ENABLED_SHA3=yes
|
||||
ENABLED_SHAKE256=yes
|
||||
fi
|
||||
|
||||
# Set SHA-3 flags
|
||||
if test "$ENABLED_SHA3" != "no"
|
||||
@@ -8108,6 +8165,31 @@ then
|
||||
ENABLED_CERTS=yes
|
||||
fi
|
||||
|
||||
# Falcon CFLAG processing (after FIPS section for sandwich pattern; also after
|
||||
# all falcon-* backend sub-options, which may turn ENABLED_FALCON on). Native
|
||||
# implementation: no liboqs dependency.
|
||||
if test "$ENABLED_FALCON" != "no"
|
||||
then
|
||||
# Not standardized (API name subject to change) -> experimental only.
|
||||
AS_IF([ test "$ENABLED_EXPERIMENTAL" != "yes" ],
|
||||
[ AC_MSG_ERROR([Falcon is not standardized and its API name is subject to change; it requires --enable-experimental.]) ])
|
||||
AM_CFLAGS="$AM_CFLAGS -DHAVE_FALCON"
|
||||
AM_CCASFLAGS="$AM_CCASFLAGS -DHAVE_FALCON"
|
||||
fi
|
||||
if test "$ENABLED_FALCON_ASM" = "yes"
|
||||
then
|
||||
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FALCON_FPR_ASM"
|
||||
AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_FALCON_FPR_ASM"
|
||||
fi
|
||||
if test "$ENABLED_FALCON_DOUBLE" = "yes"
|
||||
then
|
||||
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FALCON_FPR_DOUBLE"
|
||||
fi
|
||||
if test "$ENABLED_FALCON_AVX2" = "yes"
|
||||
then
|
||||
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FALCON_FFT_AVX2"
|
||||
fi
|
||||
|
||||
# XMSS CFLAG processing (after FIPS section for sandwich pattern)
|
||||
if test "$ENABLED_XMSS" != "no"
|
||||
then
|
||||
@@ -12887,6 +12969,9 @@ AM_CONDITIONAL([BUILD_WC_SLHDSA],[test "x$ENABLED_SLHDSA" != "xno" || test "x$EN
|
||||
AM_CONDITIONAL([BUILD_WC_MLKEM],[test "x$ENABLED_MLKEM" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_WC_FRODOKEM],[test "x$ENABLED_FRODOKEM" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_MLDSA],[test "x$ENABLED_MLDSA" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_FALCON],[test "x$ENABLED_FALCON" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_FALCON_ASM],[test "x$ENABLED_FALCON_ASM" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_FALCON_AVX2],[test "x$ENABLED_FALCON_AVX2" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_ECCSI],[test "x$ENABLED_ECCSI" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_SAKKE],[test "x$ENABLED_SAKKE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_MEMORY],[test "x$ENABLED_MEMORY" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
@@ -13457,6 +13542,7 @@ echo " * XMSS: $ENABLED_XMSS"
|
||||
echo " * SLH-DSA $ENABLED_SLHDSA"
|
||||
echo " * MLKEM: $ENABLED_MLKEM"
|
||||
echo " * ML-DSA: $ENABLED_MLDSA"
|
||||
echo " * FN-DSA (native Falcon): $ENABLED_FALCON"
|
||||
echo " * ECCSI $ENABLED_ECCSI"
|
||||
echo " * SAKKE $ENABLED_SAKKE"
|
||||
echo " * ASN: $ENABLED_ASN"
|
||||
@@ -13515,7 +13601,7 @@ echo " * Persistent cert cache: $ENABLED_SAVECERT"
|
||||
echo " * Atomic User Record Layer: $ENABLED_ATOMICUSER"
|
||||
echo " * Public Key Callbacks: $ENABLED_PKCALLBACKS"
|
||||
echo " * liboqs: $ENABLED_LIBOQS"
|
||||
echo " * Falcon (via liboqs): $ENABLED_FALCON"
|
||||
echo " * Falcon (native FN-DSA): $ENABLED_FALCON"
|
||||
echo " * Whitewood netRandom: $ENABLED_WNR"
|
||||
echo " * Server Name Indication: $ENABLED_SNI"
|
||||
echo " * ALPN: $ENABLED_ALPN"
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/* falcon-interop.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* Phase-5 FN-DSA (Falcon) interop harness.
|
||||
*
|
||||
* Cross-checks the native wolfCrypt Falcon implementation (wc_falcon_*,
|
||||
* <wolfssl/wolfcrypt/falcon.h>) against liboqs (open-quantum-safe), called
|
||||
* DIRECTLY through its OQS_SIG_* API. (The legacy wc_falcon_* wrapper now maps
|
||||
* to the native code, so it is NOT used here as the "liboqs side".)
|
||||
*
|
||||
* Both encode Falcon identically (public key header 0x09/0x0A + 14-bit packed
|
||||
* h; signature header 0x39/0x3A + 40-byte nonce + compressed s2), so keys and
|
||||
* signatures are cross-usable. The interop matrix, run for both levels:
|
||||
*
|
||||
* (1) liboqs keygen+sign -> native verify
|
||||
* (2) liboqs keygen+sign -> liboqs verify (baseline)
|
||||
* (3) native keygen+sign -> native verify
|
||||
* (4) native keygen+sign -> liboqs verify
|
||||
*
|
||||
* Build wolfSSL with native FN-DSA (no liboqs needed by the library itself):
|
||||
* ./configure --enable-falcon && make
|
||||
* Then compile + run against the built lib + liboqs:
|
||||
* gcc -I. -I<oqs>/include scripts/falcon-interop.c \
|
||||
* src/.libs/libwolfssl.a <oqs>/lib/liboqs.a -lm -lcrypto -lpthread \
|
||||
* -o falcon-interop && ./falcon-interop
|
||||
*
|
||||
* Exit status is 0 only if every cell passes.
|
||||
*/
|
||||
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
#include <wolfssl/wolfcrypt/falcon.h>
|
||||
#include <wolfssl/wolfcrypt/random.h>
|
||||
|
||||
#include <oqs/oqs.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(HAVE_FALCON)
|
||||
#error "This harness requires wolfSSL built with --enable-falcon"
|
||||
#endif
|
||||
|
||||
static const char* kMsg = "wolfSSL FN-DSA native<->liboqs interop message";
|
||||
|
||||
typedef struct {
|
||||
byte level; /* FALCON_LEVEL1 / FALCON_LEVEL5 */
|
||||
const char* oqsAlg;
|
||||
} falcon_params;
|
||||
|
||||
static int oqs_verify(OQS_SIG* o, const byte* pub, const byte* sig,
|
||||
size_t sigLen) {
|
||||
return OQS_SIG_verify(o, (const uint8_t*)kMsg, strlen(kMsg), sig, sigLen,
|
||||
pub) == OQS_SUCCESS ? 0 : -1;
|
||||
}
|
||||
|
||||
static int native_verify(byte level, const byte* pub, word32 pubLen,
|
||||
const byte* sig, word32 sigLen) {
|
||||
falcon_key k;
|
||||
int res = 0, ret;
|
||||
if (wc_falcon_init(&k) != 0) return -1;
|
||||
ret = wc_falcon_set_level(&k, level);
|
||||
if (ret == 0) ret = wc_falcon_import_public(pub, pubLen, &k);
|
||||
if (ret == 0) ret = wc_falcon_verify_msg(sig, sigLen, (const byte*)kMsg,
|
||||
(word32)strlen(kMsg), &res, &k);
|
||||
wc_falcon_free(&k);
|
||||
return (ret == 0 && res == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int run_level(const falcon_params* p, WC_RNG* rng) {
|
||||
OQS_SIG* o = OQS_SIG_new(p->oqsAlg);
|
||||
int rc = 0;
|
||||
byte *oqsPub = NULL, *oqsSec = NULL, *oqsSig = NULL;
|
||||
size_t oqsSigLen = 0;
|
||||
word32 pubLen = (p->level == FALCON_LEVEL1) ?
|
||||
FALCON_LEVEL1_PUB_KEY_SIZE : FALCON_LEVEL5_PUB_KEY_SIZE;
|
||||
|
||||
if (o == NULL) { printf(" L%d: OQS_SIG_new failed\n", p->level); return -1; }
|
||||
oqsPub = malloc(o->length_public_key);
|
||||
oqsSec = malloc(o->length_secret_key);
|
||||
oqsSig = malloc(o->length_signature);
|
||||
if (!oqsPub || !oqsSec || !oqsSig) { rc = -1; goto done; }
|
||||
|
||||
/* liboqs keygen + sign (shared by cells 1 and 2). */
|
||||
if (OQS_SIG_keypair(o, oqsPub, oqsSec) != OQS_SUCCESS) { rc=-1; goto done; }
|
||||
if (OQS_SIG_sign(o, oqsSig, &oqsSigLen, (const uint8_t*)kMsg, strlen(kMsg),
|
||||
oqsSec) != OQS_SUCCESS) { rc=-1; goto done; }
|
||||
|
||||
/* (1) liboqs sign -> native verify */
|
||||
if (native_verify(p->level, oqsPub, pubLen, oqsSig, (word32)oqsSigLen) != 0) {
|
||||
printf(" L%d cell(1) liboqs->native FAIL\n", p->level); rc=-1;
|
||||
} else printf(" L%d cell(1) liboqs->native PASS\n", p->level);
|
||||
|
||||
/* (2) liboqs sign -> liboqs verify */
|
||||
if (oqs_verify(o, oqsPub, oqsSig, oqsSigLen) != 0) {
|
||||
printf(" L%d cell(2) liboqs->liboqs FAIL\n", p->level); rc=-1;
|
||||
} else printf(" L%d cell(2) liboqs->liboqs PASS\n", p->level);
|
||||
|
||||
#ifdef WC_FALCON_HAVE_NATIVE_SIGN
|
||||
{
|
||||
falcon_key nk;
|
||||
byte natPub[FALCON_MAX_PUB_KEY_SIZE];
|
||||
byte natSig[FALCON_MAX_SIG_SIZE];
|
||||
word32 natPubLen = sizeof(natPub), natSigLen = sizeof(natSig);
|
||||
int ret, res = 0;
|
||||
|
||||
ret = wc_falcon_init(&nk);
|
||||
if (ret == 0) ret = wc_falcon_set_level(&nk, p->level);
|
||||
if (ret == 0) ret = wc_falcon_make_key(&nk, rng);
|
||||
if (ret == 0) ret = wc_falcon_export_public(&nk, natPub, &natPubLen);
|
||||
if (ret == 0) ret = wc_falcon_sign_msg((const byte*)kMsg,
|
||||
(word32)strlen(kMsg), natSig, &natSigLen, &nk, rng);
|
||||
|
||||
/* (3) native sign -> native verify */
|
||||
res = 0;
|
||||
if (ret == 0) ret = wc_falcon_verify_msg(natSig, natSigLen,
|
||||
(const byte*)kMsg, (word32)strlen(kMsg), &res, &nk);
|
||||
if (ret != 0 || res != 1) {
|
||||
printf(" L%d cell(3) native->native FAIL\n", p->level); rc=-1;
|
||||
} else printf(" L%d cell(3) native->native PASS\n", p->level);
|
||||
|
||||
/* (4) native sign -> liboqs verify */
|
||||
if (ret == 0 && oqs_verify(o, natPub, natSig, natSigLen) == 0) {
|
||||
printf(" L%d cell(4) native->liboqs PASS\n", p->level);
|
||||
} else {
|
||||
printf(" L%d cell(4) native->liboqs FAIL\n", p->level); rc=-1;
|
||||
}
|
||||
wc_falcon_free(&nk);
|
||||
}
|
||||
#else
|
||||
printf(" L%d cell(3) native->native SKIP (native sign unavailable)\n", p->level);
|
||||
printf(" L%d cell(4) native->liboqs SKIP (native sign unavailable)\n", p->level);
|
||||
#endif
|
||||
|
||||
done:
|
||||
free(oqsPub); free(oqsSec); free(oqsSig);
|
||||
OQS_SIG_free(o);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
WC_RNG rng;
|
||||
int f = 0;
|
||||
falcon_params l1 = { FALCON_LEVEL1, OQS_SIG_alg_falcon_512 };
|
||||
falcon_params l5 = { FALCON_LEVEL5, OQS_SIG_alg_falcon_1024 };
|
||||
|
||||
printf("FN-DSA native<->liboqs interop matrix\n");
|
||||
if (wc_InitRng(&rng) != 0) { printf("rng init failed\n"); return 1; }
|
||||
f |= run_level(&l1, &rng);
|
||||
f |= run_level(&l5, &rng);
|
||||
wc_FreeRng(&rng);
|
||||
printf("%s\n", f == 0 ? "ALL PASS" : "FAIL");
|
||||
return f != 0;
|
||||
}
|
||||
+36
-1
@@ -1342,6 +1342,18 @@ endif BUILD_INTELASM
|
||||
endif !BUILD_X86_ASM
|
||||
endif
|
||||
|
||||
if BUILD_FALCON
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_fpr.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_fft.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_poly.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_sampler.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_codec.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_bigint.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_keygen.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_sign.c
|
||||
endif
|
||||
|
||||
if BUILD_WC_LMS
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_lms.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_lms_impl.c
|
||||
@@ -2133,6 +2145,18 @@ endif BUILD_INTELASM
|
||||
endif !BUILD_X86_ASM
|
||||
endif
|
||||
|
||||
if BUILD_FALCON
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_fpr.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_fft.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_poly.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_sampler.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_codec.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_bigint.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_keygen.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_sign.c
|
||||
endif
|
||||
|
||||
if BUILD_WC_LMS
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_lms.c
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_lms_impl.c
|
||||
@@ -2287,8 +2311,19 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fe_448.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if BUILD_LIBOQS
|
||||
if BUILD_FALCON
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/falcon.c
|
||||
endif
|
||||
|
||||
if BUILD_FALCON_ASM
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_fpr_x86_64_asm.S
|
||||
endif
|
||||
|
||||
if BUILD_FALCON_AVX2
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_falcon_fft_avx2.c
|
||||
endif
|
||||
|
||||
if BUILD_LIBOQS
|
||||
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/liboqs/liboqs.c
|
||||
endif
|
||||
|
||||
|
||||
+57
-80
@@ -27,10 +27,11 @@
|
||||
|
||||
#include <wolfssl/wolfcrypt/asn.h>
|
||||
|
||||
/* HAVE_FALCON implies HAVE_LIBOQS (enforced in settings.h and falcon.h). */
|
||||
#include <oqs/oqs.h>
|
||||
|
||||
/* The wc_falcon_* API here wraps the native implementation core
|
||||
* (falcon_native_*, in wc_falcon.c) with cryptocb dispatch and argument
|
||||
* checking. The core operates directly on falcon_key. No liboqs dependency. */
|
||||
#include <wolfssl/wolfcrypt/falcon.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
#ifdef NO_INLINE
|
||||
#include <wolfssl/wolfcrypt/misc.h>
|
||||
#else
|
||||
@@ -38,6 +39,51 @@
|
||||
#include <wolfcrypt/src/misc.c>
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
|
||||
/* Store a second copy of the public key in key->k immediately after the private
|
||||
* key, reproducing the historical concat(private,public) layout that
|
||||
* wc_falcon_check_key compares against. No-op unless both halves are set. */
|
||||
static void falcon_store_pub_behind_priv(falcon_key* key)
|
||||
{
|
||||
if (!key->pubKeySet || !key->prvKeySet) {
|
||||
return;
|
||||
}
|
||||
if (key->level == 1) {
|
||||
XMEMCPY(key->k + FALCON_LEVEL1_KEY_SIZE, key->p,
|
||||
FALCON_LEVEL1_PUB_KEY_SIZE);
|
||||
}
|
||||
else if (key->level == 5) {
|
||||
XMEMCPY(key->k + FALCON_LEVEL5_KEY_SIZE, key->p,
|
||||
FALCON_LEVEL5_PUB_KEY_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate a new Falcon key pair into key (key->level must be set first).
|
||||
*
|
||||
* key [in/out] Falcon key to populate.
|
||||
* rng [in] Random number generator.
|
||||
* returns BAD_FUNC_ARG when a parameter is NULL or level is unset,
|
||||
* 0 on success, other -ve value on failure.
|
||||
*/
|
||||
int wc_falcon_make_key(falcon_key* key, WC_RNG* rng)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((key == NULL) || (rng == NULL)) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if ((key->level != 1) && (key->level != 5)) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
ret = falcon_native_make_key(key, rng);
|
||||
if (ret == 0) {
|
||||
falcon_store_pub_behind_priv(key);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif /* !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
|
||||
/* Sign the message using the falcon private key.
|
||||
*
|
||||
* in [in] Message to sign.
|
||||
@@ -55,10 +101,6 @@ int wc_falcon_sign_msg(const byte* in, word32 inLen,
|
||||
falcon_key* key, WC_RNG* rng)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef HAVE_LIBOQS
|
||||
OQS_SIG *oqssig = NULL;
|
||||
size_t localOutLen = 0;
|
||||
#endif
|
||||
|
||||
/* sanity check on arguments */
|
||||
if ((in == NULL) || (out == NULL) || (outLen == NULL) || (key == NULL)) {
|
||||
@@ -79,53 +121,13 @@ int wc_falcon_sign_msg(const byte* in, word32 inLen,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBOQS
|
||||
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
|
||||
if ((ret == 0) && (!key->prvKeySet)) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
if (key->level == 1) {
|
||||
oqssig = OQS_SIG_new(OQS_SIG_alg_falcon_512);
|
||||
}
|
||||
else if (key->level == 5) {
|
||||
oqssig = OQS_SIG_new(OQS_SIG_alg_falcon_1024);
|
||||
}
|
||||
|
||||
if (oqssig == NULL) {
|
||||
ret = SIG_TYPE_E;
|
||||
}
|
||||
}
|
||||
|
||||
/* check and set up out length */
|
||||
if (ret == 0) {
|
||||
if ((key->level == 1) && (*outLen < FALCON_LEVEL1_SIG_SIZE)) {
|
||||
*outLen = FALCON_LEVEL1_SIG_SIZE;
|
||||
ret = BUFFER_E;
|
||||
}
|
||||
else if ((key->level == 5) && (*outLen < FALCON_LEVEL5_SIG_SIZE)) {
|
||||
*outLen = FALCON_LEVEL5_SIG_SIZE;
|
||||
ret = BUFFER_E;
|
||||
}
|
||||
localOutLen = *outLen;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = wolfSSL_liboqsRngMutexLock(rng);
|
||||
if (ret == 0) {
|
||||
if (OQS_SIG_sign(oqssig, out, &localOutLen, in, inLen, key->k)
|
||||
== OQS_ERROR) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
*outLen = (word32)localOutLen;
|
||||
}
|
||||
wolfSSL_liboqsRngMutexUnlock();
|
||||
}
|
||||
|
||||
if (oqssig != NULL) {
|
||||
OQS_SIG_free(oqssig);
|
||||
ret = falcon_native_sign_msg(in, inLen, out, outLen, key, rng);
|
||||
}
|
||||
#else
|
||||
ret = NOT_COMPILED_IN;
|
||||
@@ -149,9 +151,6 @@ int wc_falcon_verify_msg(const byte* sig, word32 sigLen, const byte* msg,
|
||||
word32 msgLen, int* res, falcon_key* key)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef HAVE_LIBOQS
|
||||
OQS_SIG *oqssig = NULL;
|
||||
#endif
|
||||
|
||||
if (key == NULL || sig == NULL || msg == NULL || res == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
@@ -171,41 +170,14 @@ int wc_falcon_verify_msg(const byte* sig, word32 sigLen, const byte* msg,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBOQS
|
||||
if ((ret == 0) && (!key->pubKeySet)) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
if (key->level == 1) {
|
||||
oqssig = OQS_SIG_new(OQS_SIG_alg_falcon_512);
|
||||
}
|
||||
else if (key->level == 5) {
|
||||
oqssig = OQS_SIG_new(OQS_SIG_alg_falcon_1024);
|
||||
}
|
||||
|
||||
if (oqssig == NULL) {
|
||||
ret = SIG_TYPE_E;
|
||||
}
|
||||
ret = falcon_native_verify_msg(sig, sigLen, msg, msgLen, res, key);
|
||||
}
|
||||
|
||||
if ((ret == 0) &&
|
||||
(OQS_SIG_verify(oqssig, msg, msgLen, sig, sigLen, key->p)
|
||||
== OQS_ERROR)) {
|
||||
ret = SIG_VERIFY_E;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
*res = 1;
|
||||
}
|
||||
|
||||
if (oqssig != NULL) {
|
||||
OQS_SIG_free(oqssig);
|
||||
}
|
||||
#else
|
||||
ret = NOT_COMPILED_IN;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -234,6 +206,8 @@ int wc_falcon_init_ex(falcon_key* key, void* heap, int devId)
|
||||
|
||||
ForceZero(key, sizeof(*key));
|
||||
|
||||
key->heap = heap;
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
key->devCtx = NULL;
|
||||
key->devId = devId;
|
||||
@@ -432,6 +406,8 @@ int wc_falcon_import_public(const byte* in, word32 inLen,
|
||||
|
||||
XMEMCPY(key->p, in, inLen);
|
||||
key->pubKeySet = 1;
|
||||
/* Keep the concat(private,public) copy in sync if a private key is loaded. */
|
||||
falcon_store_pub_behind_priv(key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -485,6 +461,7 @@ int wc_falcon_import_private_only(const byte* priv, word32 privSz,
|
||||
if (privSz == concatSz) {
|
||||
XMEMCPY(key->p, priv + keySz, concatSz - keySz);
|
||||
key->pubKeySet = 1;
|
||||
falcon_store_pub_behind_priv(key);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,720 @@
|
||||
/* wc_falcon.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* Native FN-DSA (FIPS 206 draft) / Falcon implementation for wolfCrypt.
|
||||
*
|
||||
* Phase 1: verification only (integer arithmetic, no floating point).
|
||||
* The signature/keygen paths and the floating-point primitive seam are added
|
||||
* in later phases. See wolfssl/wolfcrypt/falcon.h. */
|
||||
|
||||
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
||||
|
||||
#if defined(HAVE_FALCON)
|
||||
|
||||
#include <wolfssl/wolfcrypt/falcon.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
#include <wolfssl/wolfcrypt/sha3.h>
|
||||
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_keygen.h>
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_codec.h>
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_sign.h>
|
||||
#endif
|
||||
|
||||
#ifdef NO_INLINE
|
||||
#include <wolfssl/wolfcrypt/misc.h>
|
||||
#else
|
||||
#define WOLFSSL_MISC_INCLUDED
|
||||
#include <wolfcrypt/src/misc.c>
|
||||
#endif
|
||||
|
||||
/* Squared L2-norm acceptance bounds, indexed by logn. Values from the Falcon
|
||||
* specification / reference implementation (l2bound table). */
|
||||
static const word32 falcon_l2bound[] = {
|
||||
/* 0..8 unused */ 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
34034726u, /* logn = 9 (FN-DSA-512) */
|
||||
70265242u /* logn = 10 (FN-DSA-1024) */
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Small modular helpers (correctness-first; hot paths are accelerated by the
|
||||
* generated per-arch backends in a later phase). */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static word32 falcon_modpow(word32 b, word32 e)
|
||||
{
|
||||
word64 r = 1, bb = b % FALCON_Q;
|
||||
while (e != 0) {
|
||||
if ((e & 1) != 0) {
|
||||
r = (r * bb) % FALCON_Q;
|
||||
}
|
||||
bb = (bb * bb) % FALCON_Q;
|
||||
e >>= 1;
|
||||
}
|
||||
return (word32)r;
|
||||
}
|
||||
|
||||
/* q is prime, so a^(q-2) == a^-1 (mod q). */
|
||||
static word32 falcon_modinv(word32 a)
|
||||
{
|
||||
return falcon_modpow(a, FALCON_Q - 2);
|
||||
}
|
||||
|
||||
static unsigned int falcon_brv(unsigned int x, int bits)
|
||||
{
|
||||
unsigned int r = 0;
|
||||
int i;
|
||||
for (i = 0; i < bits; i++) {
|
||||
r = (r << 1) | (x & 1);
|
||||
x >>= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Build bit-reversed twiddle tables for a degree-n negacyclic NTT.
|
||||
* psi is a primitive 2n-th root of unity (psi^n == -1 mod q). */
|
||||
static void falcon_build_tables(int logn, word32 psi, word16* zetas,
|
||||
word16* izetas)
|
||||
{
|
||||
int n = 1 << logn;
|
||||
word32 ipsi = falcon_modinv(psi);
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
unsigned int e = falcon_brv((unsigned int)i, logn);
|
||||
zetas[i] = (word16)falcon_modpow(psi, e);
|
||||
izetas[i] = (word16)falcon_modpow(ipsi, e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Twiddle tables are identical for every verification at a given level, so
|
||||
* compute them once and cache them (the previous code rebuilt them per call
|
||||
* via O(n) modular exponentiations — the dominant verify cost). The lazy-init
|
||||
* race is benign: the values are deterministic, so concurrent first-callers
|
||||
* write identical data. */
|
||||
static word16 falcon_zetas_l1[FALCON_LEVEL1_N];
|
||||
static word16 falcon_izetas_l1[FALCON_LEVEL1_N];
|
||||
static word16 falcon_zetas_l5[FALCON_LEVEL5_N];
|
||||
static word16 falcon_izetas_l5[FALCON_LEVEL5_N];
|
||||
static volatile int falcon_tab_l1 = 0;
|
||||
static volatile int falcon_tab_l5 = 0;
|
||||
|
||||
static void falcon_get_tables(unsigned logn, const word16** zetas,
|
||||
const word16** izetas)
|
||||
{
|
||||
if (logn == FALCON_LEVEL1_LOGN) {
|
||||
if (!falcon_tab_l1) {
|
||||
word32 psi = falcon_modpow(11, (FALCON_Q - 1) /
|
||||
(2 * FALCON_LEVEL1_N));
|
||||
falcon_build_tables(FALCON_LEVEL1_LOGN, psi, falcon_zetas_l1,
|
||||
falcon_izetas_l1);
|
||||
falcon_tab_l1 = 1;
|
||||
}
|
||||
*zetas = falcon_zetas_l1;
|
||||
*izetas = falcon_izetas_l1;
|
||||
}
|
||||
else {
|
||||
if (!falcon_tab_l5) {
|
||||
word32 psi = falcon_modpow(11, (FALCON_Q - 1) /
|
||||
(2 * FALCON_LEVEL5_N));
|
||||
falcon_build_tables(FALCON_LEVEL5_LOGN, psi, falcon_zetas_l5,
|
||||
falcon_izetas_l5);
|
||||
falcon_tab_l5 = 1;
|
||||
}
|
||||
*zetas = falcon_zetas_l5;
|
||||
*izetas = falcon_izetas_l5;
|
||||
}
|
||||
}
|
||||
|
||||
/* Division-free modular reductions for the NTT. Hardware integer division is
|
||||
* absent on Cortex-M0/M3 (a slow library call) and multi-cycle elsewhere, so
|
||||
* the inner loops use a Barrett multiply + a conditional subtract instead of
|
||||
* '%'. Both are bit-identical to a mod q and constant-time.
|
||||
* falcon_barrett: a in [0, q^2) -> [0, q) (349496 = floor(2^32 / q)).
|
||||
* falcon_csub: a in [0, 2q) -> [0, q). */
|
||||
static WC_INLINE word32 falcon_barrett(word32 a)
|
||||
{
|
||||
word32 t = (word32)(((word64)a * 349496u) >> 32);
|
||||
a -= t * FALCON_Q;
|
||||
a -= FALCON_Q & (word32)((sword32)(FALCON_Q - 1 - a) >> 31);
|
||||
return a;
|
||||
}
|
||||
static WC_INLINE word32 falcon_csub(word32 a)
|
||||
{
|
||||
a -= FALCON_Q & (word32)((sword32)(FALCON_Q - 1 - a) >> 31);
|
||||
return a;
|
||||
}
|
||||
|
||||
/* Forward negacyclic NTT, Cooley-Tukey: natural -> bit-reversed order. */
|
||||
static void falcon_ntt(word16* a, int n, const word16* zetas)
|
||||
{
|
||||
int t = n, m, i, j;
|
||||
for (m = 1; m < n; m <<= 1) {
|
||||
t >>= 1;
|
||||
for (i = 0; i < m; i++) {
|
||||
word32 z = zetas[m + i];
|
||||
int start = 2 * i * t;
|
||||
for (j = start; j < start + t; j++) {
|
||||
word32 u = a[j];
|
||||
word32 v = falcon_barrett((word32)a[j + t] * z);
|
||||
a[j] = (word16)falcon_csub(u + v);
|
||||
a[j + t] = (word16)falcon_csub(u + FALCON_Q - v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Inverse negacyclic NTT, Gentleman-Sande: bit-reversed -> natural order. */
|
||||
static void falcon_intt(word16* a, int n, const word16* izetas)
|
||||
{
|
||||
int t = 1, m, i, j;
|
||||
word32 ninv;
|
||||
for (m = n; m > 1; m >>= 1) {
|
||||
int h = m >> 1;
|
||||
int j1 = 0;
|
||||
for (i = 0; i < h; i++) {
|
||||
word32 z = izetas[h + i];
|
||||
int start = j1;
|
||||
for (j = start; j < start + t; j++) {
|
||||
word32 u = a[j];
|
||||
word32 v = a[j + t];
|
||||
word32 w = falcon_csub(u + FALCON_Q - v);
|
||||
a[j] = (word16)falcon_csub(u + v);
|
||||
a[j + t] = (word16)falcon_barrett(w * z);
|
||||
}
|
||||
j1 += 2 * t;
|
||||
}
|
||||
t <<= 1;
|
||||
}
|
||||
ninv = falcon_modinv((word32)n);
|
||||
for (j = 0; j < n; j++) {
|
||||
a[j] = (word16)falcon_barrett((word32)a[j] * ninv);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Codec */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Decode the public key polynomial h: n coefficients packed 14 bits each,
|
||||
* most-significant bit first. Each coefficient must be < q. Returns the number
|
||||
* of input bytes consumed, or a negative wolfCrypt error. */
|
||||
static int falcon_modq_decode(const byte* in, word32 inLen, word16* x,
|
||||
unsigned logn)
|
||||
{
|
||||
size_t n = (size_t)1 << logn;
|
||||
size_t need = ((n * 14) + 7) >> 3;
|
||||
word32 acc = 0;
|
||||
int acc_bits = 0;
|
||||
size_t in_i = 0, out_i = 0;
|
||||
|
||||
if (inLen < need) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
while (out_i < n) {
|
||||
acc = (acc << 8) | in[in_i++];
|
||||
acc_bits += 8;
|
||||
if (acc_bits >= 14) {
|
||||
word32 w;
|
||||
acc_bits -= 14;
|
||||
w = (acc >> acc_bits) & 0x3FFF;
|
||||
if (w >= FALCON_Q) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
x[out_i++] = (word16)w;
|
||||
}
|
||||
}
|
||||
/* Unused trailing bits in the final byte must be zero. */
|
||||
if ((acc & (((word32)1 << acc_bits) - 1)) != 0) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
return (int)need;
|
||||
}
|
||||
|
||||
/* Decode the compressed signature polynomial s2 (Golomb-Rice, k=7). Returns
|
||||
* the number of input bytes consumed, or a negative wolfCrypt error. Ported
|
||||
* from the Falcon reference comp_decode. */
|
||||
static int falcon_comp_decode(const byte* in, word32 inLen, sword16* x,
|
||||
unsigned logn)
|
||||
{
|
||||
size_t n = (size_t)1 << logn;
|
||||
word32 acc = 0;
|
||||
unsigned int acc_len = 0;
|
||||
size_t v = 0, u;
|
||||
|
||||
for (u = 0; u < n; u++) {
|
||||
unsigned int b, s, mag;
|
||||
|
||||
if (v >= inLen) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
acc = (acc << 8) | (word32)in[v++];
|
||||
b = acc >> acc_len;
|
||||
s = b & 128;
|
||||
mag = b & 127;
|
||||
|
||||
/* High bits: unary-coded run of zeros terminated by a one bit. */
|
||||
for (;;) {
|
||||
if (acc_len == 0) {
|
||||
if (v >= inLen) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
acc = (acc << 8) | (word32)in[v++];
|
||||
acc_len = 8;
|
||||
}
|
||||
acc_len--;
|
||||
if (((acc >> acc_len) & 1) != 0) {
|
||||
break;
|
||||
}
|
||||
mag += 128;
|
||||
if (mag > 2047) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
}
|
||||
/* Negative zero is not a valid encoding. */
|
||||
if (s != 0 && mag == 0) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
x[u] = (sword16)(s != 0 ? -(int)mag : (int)mag);
|
||||
}
|
||||
/* Unused trailing bits must be zero. */
|
||||
if ((acc & (((word32)1 << acc_len) - 1)) != 0) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
return (int)v;
|
||||
}
|
||||
|
||||
/* hash-to-point (variable time; inputs are public). Absorbs nonce||msg into a
|
||||
* fresh SHAKE256 context and samples n coefficients in [0,q) by rejection. */
|
||||
static int falcon_hash_to_point(const byte* nonce, const byte* msg,
|
||||
word32 msgLen, word16* c, unsigned logn, void* heap)
|
||||
{
|
||||
wc_Shake shake;
|
||||
byte block[WC_SHA3_256_BLOCK_SIZE];
|
||||
byte* absorbBuf;
|
||||
size_t n = (size_t)1 << logn;
|
||||
size_t i = 0;
|
||||
int bi = WC_SHA3_256_BLOCK_SIZE; /* force an initial squeeze */
|
||||
int ret;
|
||||
int shakeInit = 0;
|
||||
|
||||
/* Guard against size_t wrap of (nonce || msg) on 32-bit targets. */
|
||||
if (msgLen > (word32)(0xFFFFFFFFUL - FALCON_NONCE_SIZE)) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
absorbBuf = (byte*)XMALLOC((size_t)FALCON_NONCE_SIZE + msgLen, heap,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (absorbBuf == NULL) {
|
||||
return MEMORY_E;
|
||||
}
|
||||
XMEMCPY(absorbBuf, nonce, FALCON_NONCE_SIZE);
|
||||
if (msgLen > 0) {
|
||||
XMEMCPY(absorbBuf + FALCON_NONCE_SIZE, msg, msgLen);
|
||||
}
|
||||
|
||||
ret = wc_InitShake256(&shake, heap, INVALID_DEVID);
|
||||
if (ret == 0) {
|
||||
shakeInit = 1;
|
||||
ret = wc_Shake256_Absorb(&shake, absorbBuf,
|
||||
(word32)(FALCON_NONCE_SIZE + msgLen));
|
||||
}
|
||||
|
||||
while (ret == 0 && i < n) {
|
||||
word32 w;
|
||||
if (bi >= WC_SHA3_256_BLOCK_SIZE) {
|
||||
ret = wc_Shake256_SqueezeBlocks(&shake, block, 1);
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
bi = 0;
|
||||
}
|
||||
w = ((word32)block[bi] << 8) | (word32)block[bi + 1];
|
||||
bi += 2;
|
||||
/* 61445 == 5 * q: keeps the distribution uniform mod q. */
|
||||
if (w < 61445u) {
|
||||
while (w >= FALCON_Q) {
|
||||
w -= FALCON_Q;
|
||||
}
|
||||
c[i++] = (word16)w;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only free the SHAKE context if it was successfully initialized
|
||||
* (wc_Shake256_Free touches device state in async builds). */
|
||||
if (shakeInit) {
|
||||
wc_Shake256_Free(&shake);
|
||||
}
|
||||
/* nonce || msg are public; no zeroization needed. */
|
||||
XFREE(absorbBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Center x (given in [0,q)) into (-q/2, q/2]. */
|
||||
static WC_INLINE sword32 falcon_center(word32 x)
|
||||
{
|
||||
sword32 r = (sword32)x;
|
||||
if (r > (FALCON_Q >> 1)) {
|
||||
r -= FALCON_Q;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Public API */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static int falcon_level_params(byte level, unsigned* logn, int* n, word32* pubSz)
|
||||
{
|
||||
switch (level) {
|
||||
case FALCON_LEVEL1:
|
||||
*logn = FALCON_LEVEL1_LOGN;
|
||||
*n = FALCON_LEVEL1_N;
|
||||
*pubSz = FALCON_LEVEL1_PUB_KEY_SIZE;
|
||||
return 0;
|
||||
case FALCON_LEVEL5:
|
||||
*logn = FALCON_LEVEL5_LOGN;
|
||||
*n = FALCON_LEVEL5_N;
|
||||
*pubSz = FALCON_LEVEL5_PUB_KEY_SIZE;
|
||||
return 0;
|
||||
default:
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
|
||||
int falcon_native_make_key(falcon_key* key, WC_RNG* rng)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned logn = 0;
|
||||
int n = 0;
|
||||
word32 pubSz = 0, keySz = 0;
|
||||
sword8 *f = NULL, *g = NULL, *F = NULL, *G = NULL;
|
||||
word16* h = NULL;
|
||||
void* heap;
|
||||
|
||||
if (key == NULL || rng == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (falcon_level_params(key->level, &logn, &n, &pubSz) != 0) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
keySz = (key->level == FALCON_LEVEL1) ? FALCON_LEVEL1_KEY_SIZE
|
||||
: FALCON_LEVEL5_KEY_SIZE;
|
||||
heap = key->heap;
|
||||
|
||||
f = (sword8*)XMALLOC((size_t)n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
g = (sword8*)XMALLOC((size_t)n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
F = (sword8*)XMALLOC((size_t)n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
G = (sword8*)XMALLOC((size_t)n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
h = (word16*)XMALLOC(sizeof(word16) * (size_t)n, heap,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (f == NULL || g == NULL || F == NULL || G == NULL || h == NULL) {
|
||||
ret = MEMORY_E;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = falcon_keygen(rng, f, g, F, G, h, logn);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Encode the public key: header byte then 14-bit packed h. */
|
||||
key->p[0] = (byte)(FALCON_PUB_HEAD | logn);
|
||||
if (falcon_modq_encode(key->p + 1, (size_t)(pubSz - 1), h, logn) == 0) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Encode the secret key (header | f | g | F) into key->k. */
|
||||
if (falcon_privkey_encode(key->k, keySz, f, g, F, logn) != (size_t)keySz) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
key->pubKeySet = 1;
|
||||
key->prvKeySet = 1;
|
||||
|
||||
out:
|
||||
if (f != NULL) { ForceZero(f, (word32)n); XFREE(f, heap, DYNAMIC_TYPE_TMP_BUFFER); }
|
||||
if (g != NULL) { ForceZero(g, (word32)n); XFREE(g, heap, DYNAMIC_TYPE_TMP_BUFFER); }
|
||||
if (F != NULL) { ForceZero(F, (word32)n); XFREE(F, heap, DYNAMIC_TYPE_TMP_BUFFER); }
|
||||
if (G != NULL) { ForceZero(G, (word32)n); XFREE(G, heap, DYNAMIC_TYPE_TMP_BUFFER); }
|
||||
if (h != NULL) { XFREE(h, heap, DYNAMIC_TYPE_TMP_BUFFER); }
|
||||
return ret;
|
||||
}
|
||||
|
||||
int falcon_native_sign_msg(const byte* in, word32 inLen, byte* out, word32* outLen,
|
||||
falcon_key* key, WC_RNG* rng)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned logn = 0;
|
||||
int n = 0;
|
||||
word32 pubSz = 0, keySz = 0, sigMax = 0;
|
||||
sword8 *f = NULL, *g = NULL, *F = NULL, *G = NULL;
|
||||
word16* c = NULL;
|
||||
sword16* s2 = NULL;
|
||||
fpr *expanded = NULL, *tmp = NULL;
|
||||
falcon_sampler_ctx spc;
|
||||
byte nonce[FALCON_NONCE_SIZE];
|
||||
void* heap;
|
||||
int attempt, haveSpc = 0;
|
||||
size_t clen = 0;
|
||||
|
||||
if ((in == NULL && inLen != 0) || out == NULL || outLen == NULL ||
|
||||
key == NULL || rng == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (!key->prvKeySet) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (falcon_level_params(key->level, &logn, &n, &pubSz) != 0) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
keySz = (key->level == FALCON_LEVEL1) ? FALCON_LEVEL1_KEY_SIZE
|
||||
: FALCON_LEVEL5_KEY_SIZE;
|
||||
sigMax = (key->level == FALCON_LEVEL1) ? FALCON_LEVEL1_SIG_SIZE
|
||||
: FALCON_LEVEL5_SIG_SIZE;
|
||||
if (*outLen < sigMax) {
|
||||
*outLen = sigMax;
|
||||
return BUFFER_E;
|
||||
}
|
||||
heap = key->heap;
|
||||
|
||||
f = (sword8*)XMALLOC((size_t)n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
g = (sword8*)XMALLOC((size_t)n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
F = (sword8*)XMALLOC((size_t)n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
G = (sword8*)XMALLOC((size_t)n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
c = (word16*)XMALLOC(sizeof(word16) * (size_t)n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
s2 = (sword16*)XMALLOC(sizeof(sword16) * (size_t)n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
expanded = (fpr*)XMALLOC(sizeof(fpr) * FALCON_EXPANDED_KEY_FPR(logn), heap,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
tmp = (fpr*)XMALLOC(sizeof(fpr) * FALCON_SIGN_TMP_FPR(logn), heap,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (f == NULL || g == NULL || F == NULL || G == NULL || c == NULL ||
|
||||
s2 == NULL || expanded == NULL || tmp == NULL) {
|
||||
ret = MEMORY_E;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Decode the secret basis, recompute G, expand to the ffLDL tree. */
|
||||
ret = falcon_privkey_decode(key->k, keySz, f, g, F, logn);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = falcon_complete_private(G, f, g, F, logn);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = falcon_expand_privkey(expanded, f, g, F, G, logn);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = falcon_sampler_init(&spc, (int)logn, rng);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
haveSpc = 1;
|
||||
|
||||
/* Each attempt draws a fresh nonce and samples a signature; retry if the
|
||||
* compressed form does not fit the level's maximum length. */
|
||||
for (attempt = 0; attempt < 32; attempt++) {
|
||||
ret = wc_RNG_GenerateBlock(rng, nonce, FALCON_NONCE_SIZE);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = falcon_hash_to_point(nonce, in, inLen, c, logn, heap);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = falcon_sign_core(&spc, expanded, c, s2, tmp, logn);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
out[0] = (byte)(FALCON_SIG_HEAD_COMPRESSED | logn);
|
||||
XMEMCPY(out + 1, nonce, FALCON_NONCE_SIZE);
|
||||
clen = falcon_comp_encode(out + 1 + FALCON_NONCE_SIZE,
|
||||
(size_t)(*outLen - 1 - FALCON_NONCE_SIZE), s2, logn);
|
||||
if (clen != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (clen == 0) {
|
||||
ret = BUFFER_E;
|
||||
goto out;
|
||||
}
|
||||
*outLen = (word32)(1 + FALCON_NONCE_SIZE + clen);
|
||||
|
||||
out:
|
||||
/* Always zeroize: the SHAKE sponge may hold seed-derived state even if
|
||||
* falcon_sampler_init failed after absorbing the seed. */
|
||||
(void)haveSpc;
|
||||
ForceZero(&spc, sizeof(spc));
|
||||
if (f != NULL) { ForceZero(f, (word32)n); XFREE(f, heap, DYNAMIC_TYPE_TMP_BUFFER); }
|
||||
if (g != NULL) { ForceZero(g, (word32)n); XFREE(g, heap, DYNAMIC_TYPE_TMP_BUFFER); }
|
||||
if (F != NULL) { ForceZero(F, (word32)n); XFREE(F, heap, DYNAMIC_TYPE_TMP_BUFFER); }
|
||||
if (G != NULL) { ForceZero(G, (word32)n); XFREE(G, heap, DYNAMIC_TYPE_TMP_BUFFER); }
|
||||
if (s2 != NULL) XFREE(s2, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (c != NULL) XFREE(c, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (expanded != NULL) {
|
||||
ForceZero(expanded, (word32)(sizeof(fpr) * FALCON_EXPANDED_KEY_FPR(logn)));
|
||||
XFREE(expanded, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
if (tmp != NULL) {
|
||||
ForceZero(tmp, (word32)(sizeof(fpr) * FALCON_SIGN_TMP_FPR(logn)));
|
||||
XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif /* !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
|
||||
int falcon_native_verify_msg(const byte* sig, word32 sigLen, const byte* msg,
|
||||
word32 msgLen, int* res, falcon_key* key)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned logn = 0;
|
||||
int n = 0;
|
||||
word32 pubSz = 0;
|
||||
const byte* sigData;
|
||||
word32 sigDataLen;
|
||||
word16* h = NULL;
|
||||
word16* c = NULL;
|
||||
word16* t = NULL;
|
||||
const word16* zetas = NULL;
|
||||
const word16* izetas = NULL;
|
||||
sword16* s2 = NULL;
|
||||
void* heap;
|
||||
|
||||
if (sig == NULL || res == NULL || key == NULL ||
|
||||
(msg == NULL && msgLen != 0)) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
*res = 0;
|
||||
if (!key->pubKeySet) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (falcon_level_params(key->level, &logn, &n, &pubSz) != 0) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
heap = key->heap;
|
||||
|
||||
/* Signature framing: 1 header byte | 40-byte nonce | compressed s2. The
|
||||
* compressed encoding is variable length but bounded by the level's max. */
|
||||
if (sigLen < (word32)(1 + FALCON_NONCE_SIZE + 1)) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
if (sigLen > (word32)(key->level == FALCON_LEVEL1 ?
|
||||
FALCON_LEVEL1_SIG_SIZE : FALCON_LEVEL5_SIG_SIZE)) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
if (sig[0] != (byte)(FALCON_SIG_HEAD_COMPRESSED | logn)) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
sigData = sig + 1 + FALCON_NONCE_SIZE;
|
||||
sigDataLen = sigLen - 1 - FALCON_NONCE_SIZE;
|
||||
|
||||
h = (word16*)XMALLOC(sizeof(word16) * n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
c = (word16*)XMALLOC(sizeof(word16) * n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
t = (word16*)XMALLOC(sizeof(word16) * n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
s2 = (sword16*)XMALLOC(sizeof(sword16) * n, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (h == NULL || c == NULL || t == NULL || s2 == NULL) {
|
||||
ret = MEMORY_E;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Decode public key h (skip the 0x0n header byte). */
|
||||
if (key->p[0] != (byte)(FALCON_PUB_HEAD | logn)) {
|
||||
ret = ASN_PARSE_E;
|
||||
goto out;
|
||||
}
|
||||
{
|
||||
int rc = falcon_modq_decode(key->p + 1, pubSz - 1, h, logn);
|
||||
if (rc < 0) {
|
||||
ret = rc;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode compressed s2; the encoding must consume the whole buffer. */
|
||||
{
|
||||
int rc = falcon_comp_decode(sigData, sigDataLen, s2, logn);
|
||||
if (rc < 0) {
|
||||
ret = rc;
|
||||
goto out;
|
||||
}
|
||||
if ((word32)rc != sigDataLen) {
|
||||
ret = ASN_PARSE_E;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* c = HashToPoint(nonce || msg). */
|
||||
ret = falcon_hash_to_point(sig + 1, msg, msgLen, c, logn, heap);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* t = s2 * h mod (x^n + 1) mod q, via NTT. Twiddle tables are cached. */
|
||||
falcon_get_tables(logn, &zetas, &izetas);
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
sword32 v = s2[i];
|
||||
if (v < 0) {
|
||||
v += FALCON_Q;
|
||||
}
|
||||
t[i] = (word16)v;
|
||||
}
|
||||
}
|
||||
falcon_ntt(t, n, zetas);
|
||||
falcon_ntt(h, n, zetas);
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
t[i] = (word16)falcon_barrett((word32)t[i] * h[i]);
|
||||
}
|
||||
}
|
||||
falcon_intt(t, n, izetas);
|
||||
|
||||
/* s1 = c - s2*h mod q (centered); accept iff ||(s1,s2)||^2 <= bound. */
|
||||
{
|
||||
word64 norm = 0;
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
word32 d = falcon_csub(c[i] + FALCON_Q - t[i]);
|
||||
sword32 s1c = falcon_center(d);
|
||||
sword32 s2c = s2[i];
|
||||
norm += (word64)((sword64)s1c * s1c);
|
||||
norm += (word64)((sword64)s2c * s2c);
|
||||
}
|
||||
if (norm <= (word64)falcon_l2bound[logn]) {
|
||||
*res = 1;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (h != NULL) XFREE(h, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (c != NULL) XFREE(c, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (t != NULL) XFREE(t, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
/* zetas/izetas point at static caches; not freed. */
|
||||
if (s2 != NULL) XFREE(s2, heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif /* HAVE_FALCON */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,359 @@
|
||||
/* wc_falcon_codec.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* FN-DSA (FIPS 206 draft) / Falcon encode/decode routines for the signing and
|
||||
* key-generation paths. These are faithful ports of the Falcon reference
|
||||
* implementation (codec.c): modq_encode, comp_encode, trim_i8_encode and
|
||||
* trim_i8_decode, plus the secret-key decoder that drives them.
|
||||
*
|
||||
* The verification-side decoders (modq_decode, comp_decode) are statics in
|
||||
* wc_falcon.c and are deliberately not duplicated here. */
|
||||
|
||||
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#include <wolfssl/wolfcrypt/falcon.h>
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_codec.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
|
||||
/* Maximum bit width used to encode f and g, indexed by logn (0..10).
|
||||
* From the Falcon reference (codec.c). */
|
||||
static const byte falcon_max_fg_bits[] = {
|
||||
0, /* unused */
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
7,
|
||||
6,
|
||||
6,
|
||||
5
|
||||
};
|
||||
|
||||
/* Maximum bit width used to encode F (and G), indexed by logn (0..10).
|
||||
* From the Falcon reference (codec.c). */
|
||||
static const byte falcon_max_FG_bits[] = {
|
||||
0, /* unused */
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Pack the public key polynomial h: n coefficients, 14 bits each, packed
|
||||
* most-significant bit first. Inverse of falcon_modq_decode. Returns the number
|
||||
* of bytes written, or 0 on a coefficient >= q or output overflow. */
|
||||
size_t falcon_modq_encode(byte* out, size_t max_out, const word16* x,
|
||||
unsigned logn)
|
||||
{
|
||||
size_t n = (size_t)1 << logn;
|
||||
size_t out_len = ((n * 14) + 7) >> 3;
|
||||
size_t u, v;
|
||||
word32 acc = 0;
|
||||
int acc_len = 0;
|
||||
|
||||
for (u = 0; u < n; u++) {
|
||||
if (x[u] >= FALCON_Q) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (out_len > max_out) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
v = 0;
|
||||
for (u = 0; u < n; u++) {
|
||||
acc = (acc << 14) | (word32)x[u];
|
||||
acc_len += 14;
|
||||
while (acc_len >= 8) {
|
||||
acc_len -= 8;
|
||||
out[v++] = (byte)(acc >> acc_len);
|
||||
}
|
||||
}
|
||||
if (acc_len > 0) {
|
||||
out[v++] = (byte)(acc << (8 - acc_len));
|
||||
}
|
||||
return out_len;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Compress the signature polynomial s2 with Golomb-Rice coding (k=7). Exact
|
||||
* inverse of the reference comp_decode. Returns the number of bytes written, or
|
||||
* 0 if any |x[i]| > 2047 or the output buffer overflows. */
|
||||
size_t falcon_comp_encode(byte* out, size_t max_out, const sword16* x,
|
||||
unsigned logn)
|
||||
{
|
||||
size_t n = (size_t)1 << logn;
|
||||
size_t u, v;
|
||||
word32 acc = 0;
|
||||
unsigned acc_len = 0;
|
||||
|
||||
/* All coefficients must fit in the -2047..+2047 range. */
|
||||
for (u = 0; u < n; u++) {
|
||||
if (x[u] < -2047 || x[u] > 2047) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
v = 0;
|
||||
for (u = 0; u < n; u++) {
|
||||
int t;
|
||||
unsigned w;
|
||||
|
||||
/* Sign bit (1 for negative), then the low 7 bits of |x|. */
|
||||
acc <<= 1;
|
||||
t = (int)x[u];
|
||||
if (t < 0) {
|
||||
t = -t;
|
||||
acc |= 1;
|
||||
}
|
||||
w = (unsigned)t;
|
||||
|
||||
acc <<= 7;
|
||||
acc |= w & 127u;
|
||||
w >>= 7;
|
||||
acc_len += 8;
|
||||
|
||||
/* Unary high part: w zero bits then a terminating one. The absolute
|
||||
* value is at most 2047, so w <= 15 here and at most 16 bits are added;
|
||||
* combined with the 8 bits above and up to 7 carried bits, the 32-bit
|
||||
* accumulator never overflows. */
|
||||
acc <<= (w + 1);
|
||||
acc |= 1;
|
||||
acc_len += w + 1;
|
||||
|
||||
while (acc_len >= 8) {
|
||||
acc_len -= 8;
|
||||
if (v >= max_out) {
|
||||
return 0;
|
||||
}
|
||||
out[v++] = (byte)(acc >> acc_len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Flush any remaining bits, left-aligned in the final byte. */
|
||||
if (acc_len > 0) {
|
||||
if (v >= max_out) {
|
||||
return 0;
|
||||
}
|
||||
out[v++] = (byte)(acc << (8 - acc_len));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Pack n signed 8-bit coefficients, each in 'bits' bits, MSB first. The valid
|
||||
* range is -(2^(bits-1)-1) .. +(2^(bits-1)-1); the most-negative value is not
|
||||
* representable. Returns bytes written, or 0 on range violation / overflow. */
|
||||
size_t falcon_trim_i8_encode(byte* out, size_t max_out, const sword8* x,
|
||||
unsigned logn, unsigned bits)
|
||||
{
|
||||
size_t n = (size_t)1 << logn;
|
||||
size_t out_len = ((n * bits) + 7) >> 3;
|
||||
size_t u, v;
|
||||
int minv, maxv;
|
||||
word32 acc = 0, mask;
|
||||
unsigned acc_len = 0;
|
||||
|
||||
maxv = (1 << (bits - 1)) - 1;
|
||||
minv = -maxv;
|
||||
for (u = 0; u < n; u++) {
|
||||
if (x[u] < minv || x[u] > maxv) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (out_len > max_out) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mask = ((word32)1 << bits) - 1;
|
||||
v = 0;
|
||||
for (u = 0; u < n; u++) {
|
||||
acc = (acc << bits) | ((word32)(byte)x[u] & mask);
|
||||
acc_len += bits;
|
||||
while (acc_len >= 8) {
|
||||
acc_len -= 8;
|
||||
out[v++] = (byte)(acc >> acc_len);
|
||||
}
|
||||
}
|
||||
if (acc_len > 0) {
|
||||
out[v++] = (byte)(acc << (8 - acc_len));
|
||||
}
|
||||
return out_len;
|
||||
}
|
||||
|
||||
/* Unpack n signed 8-bit coefficients packed at 'bits' bits each (MSB first).
|
||||
* The most-negative value -2^(bits-1) is rejected. Trailing pad bits in the
|
||||
* final byte must be zero. Returns bytes consumed, or 0 on any violation. */
|
||||
size_t falcon_trim_i8_decode(sword8* x, unsigned logn, unsigned bits,
|
||||
const byte* in, size_t max_in)
|
||||
{
|
||||
size_t n = (size_t)1 << logn;
|
||||
size_t in_len = ((n * bits) + 7) >> 3;
|
||||
size_t u, v;
|
||||
word32 acc = 0, mask1, mask2;
|
||||
unsigned acc_len = 0;
|
||||
|
||||
if (in_len > max_in) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mask1 = ((word32)1 << bits) - 1;
|
||||
mask2 = (word32)1 << (bits - 1);
|
||||
u = 0;
|
||||
v = 0;
|
||||
while (u < n) {
|
||||
acc = (acc << 8) | (word32)in[v++];
|
||||
acc_len += 8;
|
||||
while (acc_len >= bits && u < n) {
|
||||
word32 w;
|
||||
|
||||
acc_len -= bits;
|
||||
w = (acc >> acc_len) & mask1;
|
||||
/* Sign-extend from the high bit. */
|
||||
w |= (word32)(-(sword32)(w & mask2));
|
||||
if (w == (word32)(-(sword32)mask2)) {
|
||||
/* The -2^(bits-1) value is forbidden. */
|
||||
return 0;
|
||||
}
|
||||
x[u++] = (sword8)(sword32)w;
|
||||
}
|
||||
}
|
||||
/* Extra bits in the last consumed byte must be zero. */
|
||||
if ((acc & (((word32)1 << acc_len) - 1)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return in_len;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Decode a Falcon secret key into its (f, g, F) basis polynomials. The encoding
|
||||
* is: header byte (0x50 | logn), then trim_i8(f, max_fg_bits[logn]),
|
||||
* trim_i8(g, max_fg_bits[logn]), trim_i8(F, max_FG_bits[logn]). G is not stored
|
||||
* (it is recomputed from f, g, F at use time). The header and an exact length
|
||||
* match are both validated. */
|
||||
int falcon_privkey_decode(const byte* sk, size_t sklen, sword8* f, sword8* g,
|
||||
sword8* F, unsigned logn)
|
||||
{
|
||||
size_t u, v;
|
||||
|
||||
if (sk == NULL || f == NULL || g == NULL || F == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (logn < 1 || logn > 10) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (sklen < 1) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
if (sk[0] != (byte)(0x50 | logn)) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
|
||||
u = 1;
|
||||
v = falcon_trim_i8_decode(f, logn, falcon_max_fg_bits[logn],
|
||||
sk + u, sklen - u);
|
||||
if (v == 0) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
u += v;
|
||||
|
||||
v = falcon_trim_i8_decode(g, logn, falcon_max_fg_bits[logn],
|
||||
sk + u, sklen - u);
|
||||
if (v == 0) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
u += v;
|
||||
|
||||
v = falcon_trim_i8_decode(F, logn, falcon_max_FG_bits[logn],
|
||||
sk + u, sklen - u);
|
||||
if (v == 0) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
u += v;
|
||||
|
||||
/* The whole secret key must be consumed exactly. */
|
||||
if (u != sklen) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Encode a Falcon secret key from its (f, g, F) basis: header byte
|
||||
* (0x50 | logn), then trim_i8(f), trim_i8(g) at max_fg_bits[logn] and
|
||||
* trim_i8(F) at max_FG_bits[logn]. Returns the number of bytes written, or 0 on
|
||||
* range violation / output overflow. */
|
||||
size_t falcon_privkey_encode(byte* sk, size_t max_sk, const sword8* f,
|
||||
const sword8* g, const sword8* F, unsigned logn)
|
||||
{
|
||||
size_t u, v;
|
||||
|
||||
if (sk == NULL || f == NULL || g == NULL || F == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (logn < 1 || logn > 10) {
|
||||
return 0;
|
||||
}
|
||||
if (max_sk < 1) {
|
||||
return 0;
|
||||
}
|
||||
sk[0] = (byte)(0x50 | logn);
|
||||
u = 1;
|
||||
|
||||
v = falcon_trim_i8_encode(sk + u, max_sk - u, f, logn,
|
||||
falcon_max_fg_bits[logn]);
|
||||
if (v == 0) {
|
||||
return 0;
|
||||
}
|
||||
u += v;
|
||||
|
||||
v = falcon_trim_i8_encode(sk + u, max_sk - u, g, logn,
|
||||
falcon_max_fg_bits[logn]);
|
||||
if (v == 0) {
|
||||
return 0;
|
||||
}
|
||||
u += v;
|
||||
|
||||
v = falcon_trim_i8_encode(sk + u, max_sk - u, F, logn,
|
||||
falcon_max_FG_bits[logn]);
|
||||
if (v == 0) {
|
||||
return 0;
|
||||
}
|
||||
u += v;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
@@ -0,0 +1,635 @@
|
||||
/* wc_falcon_fft.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* FN-DSA / Falcon FFT over the fpr seam. See wolfssl/wolfcrypt/wc_falcon_fft.h.
|
||||
* Algorithm and twiddle-table layout validated against a schoolbook negacyclic
|
||||
* reference (round-trip and FFT-based multiplication) for n in {8,512,1024}. */
|
||||
|
||||
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_fft.h>
|
||||
|
||||
/* Complex helpers over the fpr seam. d may alias a/b inputs only via temps. */
|
||||
#define FPC_ADD(d_re, d_im, a_re, a_im, b_re, b_im) do { \
|
||||
fpr _ar = (a_re), _ai = (a_im), _br = (b_re), _bi = (b_im); \
|
||||
(d_re) = fpr_add(_ar, _br); \
|
||||
(d_im) = fpr_add(_ai, _bi); \
|
||||
} while (0)
|
||||
#define FPC_SUB(d_re, d_im, a_re, a_im, b_re, b_im) do { \
|
||||
fpr _ar = (a_re), _ai = (a_im), _br = (b_re), _bi = (b_im); \
|
||||
(d_re) = fpr_sub(_ar, _br); \
|
||||
(d_im) = fpr_sub(_ai, _bi); \
|
||||
} while (0)
|
||||
/* (a_re + i a_im) * (b_re + i b_im) */
|
||||
#define FPC_MUL(d_re, d_im, a_re, a_im, b_re, b_im) do { \
|
||||
fpr _ar = (a_re), _ai = (a_im), _br = (b_re), _bi = (b_im); \
|
||||
(d_re) = fpr_sub(fpr_mul(_ar, _br), fpr_mul(_ai, _bi)); \
|
||||
(d_im) = fpr_add(fpr_mul(_ar, _bi), fpr_mul(_ai, _br)); \
|
||||
} while (0)
|
||||
|
||||
/* falcon_gm_tab[2*p+0]=cos, [2*p+1]=sin; angle=pi*(2*brev_u(i)+1)/(2m).
|
||||
* Generated table of correctly-rounded IEEE-754 twiddle factors, n<=1024.
|
||||
* Exported (declared in wc_falcon_fft.h) for use by the poly_split/merge ops. */
|
||||
const fpr falcon_gm_tab[2048] = {
|
||||
0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL,
|
||||
0x3FE6A09E667F3BCDULL, 0x3FE6A09E667F3BCCULL, 0xBFE6A09E667F3BCCULL, 0x3FE6A09E667F3BCDULL,
|
||||
0x3FED906BCF328D46ULL, 0x3FD87DE2A6AEA963ULL, 0xBFD87DE2A6AEA962ULL, 0x3FED906BCF328D46ULL,
|
||||
0x3FD87DE2A6AEA964ULL, 0x3FED906BCF328D46ULL, 0xBFED906BCF328D46ULL, 0x3FD87DE2A6AEA965ULL,
|
||||
0x3FEF6297CFF75CB0ULL, 0x3FC8F8B83C69A60AULL, 0xBFC8F8B83C69A608ULL, 0x3FEF6297CFF75CB0ULL,
|
||||
0x3FE1C73B39AE68C9ULL, 0x3FEA9B66290EA1A3ULL, 0xBFEA9B66290EA1A4ULL, 0x3FE1C73B39AE68C8ULL,
|
||||
0x3FEA9B66290EA1A3ULL, 0x3FE1C73B39AE68C8ULL, 0xBFE1C73B39AE68C6ULL, 0x3FEA9B66290EA1A5ULL,
|
||||
0x3FC8F8B83C69A60DULL, 0x3FEF6297CFF75CB0ULL, 0xBFEF6297CFF75CB0ULL, 0x3FC8F8B83C69A617ULL,
|
||||
0x3FEFD88DA3D12526ULL, 0x3FB917A6BC29B42CULL, 0xBFB917A6BC29B42FULL, 0x3FEFD88DA3D12526ULL,
|
||||
0x3FE44CF325091DD6ULL, 0x3FE8BC806B151741ULL, 0xBFE8BC806B151741ULL, 0x3FE44CF325091DD6ULL,
|
||||
0x3FEC38B2F180BDB1ULL, 0x3FDE2B5D3806F63BULL, 0xBFDE2B5D3806F63CULL, 0x3FEC38B2F180BDB1ULL,
|
||||
0x3FD294062ED59F05ULL, 0x3FEE9F4156C62DDBULL, 0xBFEE9F4156C62DDAULL, 0x3FD294062ED59F06ULL,
|
||||
0x3FEE9F4156C62DDAULL, 0x3FD294062ED59F05ULL, 0xBFD294062ED59F02ULL, 0x3FEE9F4156C62DDBULL,
|
||||
0x3FDE2B5D3806F63EULL, 0x3FEC38B2F180BDB0ULL, 0xBFEC38B2F180BDB0ULL, 0x3FDE2B5D3806F63FULL,
|
||||
0x3FE8BC806B151741ULL, 0x3FE44CF325091DD6ULL, 0xBFE44CF325091DD5ULL, 0x3FE8BC806B151742ULL,
|
||||
0x3FB917A6BC29B438ULL, 0x3FEFD88DA3D12525ULL, 0xBFEFD88DA3D12525ULL, 0x3FB917A6BC29B43CULL,
|
||||
0x3FEFF621E3796D7EULL, 0x3FA91F65F10DD814ULL, 0xBFA91F65F10DD813ULL, 0x3FEFF621E3796D7EULL,
|
||||
0x3FE57D69348CEC9FULL, 0x3FE7B5DF226AAFAFULL, 0xBFE7B5DF226AAFADULL, 0x3FE57D69348CECA1ULL,
|
||||
0x3FECED7AF43CC773ULL, 0x3FDB5D1009E15CC0ULL, 0xBFDB5D1009E15CBCULL, 0x3FECED7AF43CC774ULL,
|
||||
0x3FD58F9A75AB1FDDULL, 0x3FEE212104F686E5ULL, 0xBFEE212104F686E4ULL, 0x3FD58F9A75AB1FE2ULL,
|
||||
0x3FEF0A7EFB9230D7ULL, 0x3FCF19F97B215F1AULL, 0xBFCF19F97B215F1AULL, 0x3FEF0A7EFB9230D7ULL,
|
||||
0x3FE073879922FFEDULL, 0x3FEB728345196E3EULL, 0xBFEB728345196E3DULL, 0x3FE073879922FFEEULL,
|
||||
0x3FE9B3E047F38741ULL, 0x3FE30FF7FCE17035ULL, 0xBFE30FF7FCE17035ULL, 0x3FE9B3E047F38741ULL,
|
||||
0x3FC2C8106E8E613AULL, 0x3FEFA7557F08A517ULL, 0xBFEFA7557F08A517ULL, 0x3FC2C8106E8E613CULL,
|
||||
0x3FEFA7557F08A517ULL, 0x3FC2C8106E8E613AULL, 0xBFC2C8106E8E6136ULL, 0x3FEFA7557F08A517ULL,
|
||||
0x3FE30FF7FCE17036ULL, 0x3FE9B3E047F38740ULL, 0xBFE9B3E047F38740ULL, 0x3FE30FF7FCE17036ULL,
|
||||
0x3FEB728345196E3EULL, 0x3FE073879922FFEDULL, 0xBFE073879922FFEDULL, 0x3FEB728345196E3EULL,
|
||||
0x3FCF19F97B215F1EULL, 0x3FEF0A7EFB9230D7ULL, 0xBFEF0A7EFB9230D7ULL, 0x3FCF19F97B215F21ULL,
|
||||
0x3FEE212104F686E5ULL, 0x3FD58F9A75AB1FDDULL, 0xBFD58F9A75AB1FDBULL, 0x3FEE212104F686E5ULL,
|
||||
0x3FDB5D1009E15CC2ULL, 0x3FECED7AF43CC773ULL, 0xBFECED7AF43CC773ULL, 0x3FDB5D1009E15CBFULL,
|
||||
0x3FE7B5DF226AAFAFULL, 0x3FE57D69348CEC9FULL, 0xBFE57D69348CECA0ULL, 0x3FE7B5DF226AAFAEULL,
|
||||
0x3FA91F65F10DD824ULL, 0x3FEFF621E3796D7EULL, 0xBFEFF621E3796D7EULL, 0x3FA91F65F10DD80DULL,
|
||||
0x3FEFFD886084CD0DULL, 0x3F992155F7A3667EULL, 0xBF992155F7A36654ULL, 0x3FEFFD886084CD0DULL,
|
||||
0x3FE610B7551D2CDFULL, 0x3FE72D0837EFFF96ULL, 0xBFE72D0837EFFF95ULL, 0x3FE610B7551D2CE0ULL,
|
||||
0x3FED4134D14DC93AULL, 0x3FD9EF7943A8ED8AULL, 0xBFD9EF7943A8ED88ULL, 0x3FED4134D14DC93AULL,
|
||||
0x3FD7088530FA45A1ULL, 0x3FEDDB13B6CCC23CULL, 0xBFEDDB13B6CCC23CULL, 0x3FD7088530FA45A2ULL,
|
||||
0x3FEF38F3AC64E589ULL, 0x3FCC0B826A7E4F63ULL, 0xBFCC0B826A7E4F5EULL, 0x3FEF38F3AC64E589ULL,
|
||||
0x3FE11EB3541B4B23ULL, 0x3FEB090A581501FFULL, 0xBFEB090A58150200ULL, 0x3FE11EB3541B4B22ULL,
|
||||
0x3FEA29A7A0462782ULL, 0x3FE26D054CDD12DFULL, 0xBFE26D054CDD12DFULL, 0x3FEA29A7A0462782ULL,
|
||||
0x3FC5E214448B3FCBULL, 0x3FEF8764FA714BA9ULL, 0xBFEF8764FA714BA9ULL, 0x3FC5E214448B3FC6ULL,
|
||||
0x3FEFC26470E19FD3ULL, 0x3FBF564E56A9730EULL, 0xBFBF564E56A9730BULL, 0x3FEFC26470E19FD3ULL,
|
||||
0x3FE3AFFA292050B9ULL, 0x3FE93A22499263FBULL, 0xBFE93A22499263FBULL, 0x3FE3AFFA292050BAULL,
|
||||
0x3FEBD7C0AC6F952AULL, 0x3FDF8BA4DBF89ABAULL, 0xBFDF8BA4DBF89AB9ULL, 0x3FEBD7C0AC6F952AULL,
|
||||
0x3FD111D262B1F678ULL, 0x3FEED740E7684963ULL, 0xBFEED740E7684963ULL, 0x3FD111D262B1F679ULL,
|
||||
0x3FEE6288EC48E112ULL, 0x3FD4135C94176602ULL, 0xBFD4135C94176600ULL, 0x3FEE6288EC48E112ULL,
|
||||
0x3FDCC66E9931C45EULL, 0x3FEC954B213411F5ULL, 0xBFEC954B213411F4ULL, 0x3FDCC66E9931C463ULL,
|
||||
0x3FE83B0E0BFF976EULL, 0x3FE4E6CABBE3E5E9ULL, 0xBFE4E6CABBE3E5E7ULL, 0x3FE83B0E0BFF976FULL,
|
||||
0x3FB2D52092CE19F8ULL, 0x3FEFE9CDAD01883AULL, 0xBFEFE9CDAD01883AULL, 0x3FB2D52092CE1A0CULL,
|
||||
0x3FEFE9CDAD01883AULL, 0x3FB2D52092CE19F6ULL, 0xBFB2D52092CE19EFULL, 0x3FEFE9CDAD01883AULL,
|
||||
0x3FE4E6CABBE3E5E9ULL, 0x3FE83B0E0BFF976DULL, 0xBFE83B0E0BFF976EULL, 0x3FE4E6CABBE3E5E8ULL,
|
||||
0x3FEC954B213411F5ULL, 0x3FDCC66E9931C45DULL, 0xBFDCC66E9931C460ULL, 0x3FEC954B213411F4ULL,
|
||||
0x3FD4135C94176603ULL, 0x3FEE6288EC48E112ULL, 0xBFEE6288EC48E112ULL, 0x3FD4135C94176600ULL,
|
||||
0x3FEED740E7684963ULL, 0x3FD111D262B1F677ULL, 0xBFD111D262B1F676ULL, 0x3FEED740E7684963ULL,
|
||||
0x3FDF8BA4DBF89ABBULL, 0x3FEBD7C0AC6F9529ULL, 0xBFEBD7C0AC6F9529ULL, 0x3FDF8BA4DBF89ABCULL,
|
||||
0x3FE93A22499263FCULL, 0x3FE3AFFA292050B9ULL, 0xBFE3AFFA292050B8ULL, 0x3FE93A22499263FCULL,
|
||||
0x3FBF564E56A97314ULL, 0x3FEFC26470E19FD3ULL, 0xBFEFC26470E19FD3ULL, 0x3FBF564E56A97319ULL,
|
||||
0x3FEF8764FA714BA9ULL, 0x3FC5E214448B3FC6ULL, 0xBFC5E214448B3FC7ULL, 0x3FEF8764FA714BA9ULL,
|
||||
0x3FE26D054CDD12DFULL, 0x3FEA29A7A0462782ULL, 0xBFEA29A7A0462781ULL, 0x3FE26D054CDD12E0ULL,
|
||||
0x3FEB090A58150200ULL, 0x3FE11EB3541B4B22ULL, 0xBFE11EB3541B4B21ULL, 0x3FEB090A58150201ULL,
|
||||
0x3FCC0B826A7E4F62ULL, 0x3FEF38F3AC64E589ULL, 0xBFEF38F3AC64E588ULL, 0x3FCC0B826A7E4F6CULL,
|
||||
0x3FEDDB13B6CCC23DULL, 0x3FD7088530FA459EULL, 0xBFD7088530FA459FULL, 0x3FEDDB13B6CCC23CULL,
|
||||
0x3FD9EF7943A8ED8AULL, 0x3FED4134D14DC93AULL, 0xBFED4134D14DC93AULL, 0x3FD9EF7943A8ED8BULL,
|
||||
0x3FE72D0837EFFF97ULL, 0x3FE610B7551D2CDEULL, 0xBFE610B7551D2CDFULL, 0x3FE72D0837EFFF96ULL,
|
||||
0x3F992155F7A36677ULL, 0x3FEFFD886084CD0DULL, 0xBFEFFD886084CD0DULL, 0x3F992155F7A36689ULL,
|
||||
0x3FEFFF62169B92DBULL, 0x3F8921D1FCDEC784ULL, 0xBF8921D1FCDEC749ULL, 0x3FEFFF62169B92DBULL,
|
||||
0x3FE6591925F0783EULL, 0x3FE6E74454EAA8AEULL, 0xBFE6E74454EAA8AEULL, 0x3FE6591925F0783EULL,
|
||||
0x3FED696173C9E68BULL, 0x3FD9372A63BC93D7ULL, 0xBFD9372A63BC93D5ULL, 0x3FED696173C9E68BULL,
|
||||
0x3FD7C3A9311DCCE8ULL, 0x3FEDB6526238A09AULL, 0xBFEDB6526238A09AULL, 0x3FD7C3A9311DCCEAULL,
|
||||
0x3FEF4E603B0B2F2DULL, 0x3FCA82A025B00451ULL, 0xBFCA82A025B0044DULL, 0x3FEF4E603B0B2F2DULL,
|
||||
0x3FE1734D63DEDB49ULL, 0x3FEAD2BC9E21D510ULL, 0xBFEAD2BC9E21D511ULL, 0x3FE1734D63DEDB48ULL,
|
||||
0x3FEA63091B02FAE2ULL, 0x3FE21A799933EB58ULL, 0xBFE21A799933EB59ULL, 0x3FEA63091B02FAE1ULL,
|
||||
0x3FC76DD9DE50BF35ULL, 0x3FEF7599A3A12077ULL, 0xBFEF7599A3A12077ULL, 0x3FC76DD9DE50BF2FULL,
|
||||
0x3FEFCE15FD6DA67BULL, 0x3FBC3785C79EC2D5ULL, 0xBFBC3785C79EC2D5ULL, 0x3FEFCE15FD6DA67BULL,
|
||||
0x3FE3FED9534556D5ULL, 0x3FE8FBCCA3EF940CULL, 0xBFE8FBCCA3EF940DULL, 0x3FE3FED9534556D4ULL,
|
||||
0x3FEC08C426725549ULL, 0x3FDEDC1952EF78D5ULL, 0xBFDEDC1952EF78D5ULL, 0x3FEC08C426725549ULL,
|
||||
0x3FD1D3443F4CDB3DULL, 0x3FEEBBD8C8DF0B74ULL, 0xBFEEBBD8C8DF0B74ULL, 0x3FD1D3443F4CDB3FULL,
|
||||
0x3FEE817BAB4CD10DULL, 0x3FD35410C2E18152ULL, 0xBFD35410C2E18152ULL, 0x3FEE817BAB4CD10DULL,
|
||||
0x3FDD79775B86E389ULL, 0x3FEC678B3488739BULL, 0xBFEC678B3488739AULL, 0x3FDD79775B86E38DULL,
|
||||
0x3FE87C400FBA2EBFULL, 0x3FE49A449B9B0938ULL, 0xBFE49A449B9B0937ULL, 0x3FE87C400FBA2EC0ULL,
|
||||
0x3FB5F6D00A9AA418ULL, 0x3FEFE1CAFCBD5B09ULL, 0xBFEFE1CAFCBD5B09ULL, 0x3FB5F6D00A9AA42CULL,
|
||||
0x3FEFF095658E71ADULL, 0x3FAF656E79F820E0ULL, 0xBFAF656E79F820D9ULL, 0x3FEFF095658E71ADULL,
|
||||
0x3FE5328292A35596ULL, 0x3FE7F8ECE3571770ULL, 0xBFE7F8ECE357176FULL, 0x3FE5328292A35598ULL,
|
||||
0x3FECC1F0F3FCFC5CULL, 0x3FDC1249D8011EE7ULL, 0xBFDC1249D8011EE2ULL, 0x3FECC1F0F3FCFC5DULL,
|
||||
0x3FD4D1E24278E76BULL, 0x3FEE426A4B2BC17EULL, 0xBFEE426A4B2BC17DULL, 0x3FD4D1E24278E770ULL,
|
||||
0x3FEEF178A3E473C2ULL, 0x3FD04FB80E37FDAEULL, 0xBFD04FB80E37FDADULL, 0x3FEEF178A3E473C2ULL,
|
||||
0x3FE01CFC874C3EB7ULL, 0x3FEBA5AA673590D2ULL, 0xBFEBA5AA673590D2ULL, 0x3FE01CFC874C3EB8ULL,
|
||||
0x3FE9777EF4C7D742ULL, 0x3FE36058B10659F3ULL, 0xBFE36058B10659F2ULL, 0x3FE9777EF4C7D742ULL,
|
||||
0x3FC139F0CEDAF578ULL, 0x3FEFB5797195D741ULL, 0xBFEFB5797195D741ULL, 0x3FC139F0CEDAF57AULL,
|
||||
0x3FEF97F924C9099BULL, 0x3FC45576B1293E5AULL, 0xBFC45576B1293E54ULL, 0x3FEF97F924C9099BULL,
|
||||
0x3FE2BEDB25FAF3EAULL, 0x3FE9EF43EF29AF94ULL, 0xBFE9EF43EF29AF93ULL, 0x3FE2BEDB25FAF3EBULL,
|
||||
0x3FEB3E4D3EF55712ULL, 0x3FE0C9704D5D898FULL, 0xBFE0C9704D5D898DULL, 0x3FEB3E4D3EF55712ULL,
|
||||
0x3FCD934FE5454317ULL, 0x3FEF2252F7763AD9ULL, 0xBFEF2252F7763AD9ULL, 0x3FCD934FE5454319ULL,
|
||||
0x3FEDFEAE622DBE2BULL, 0x3FD64C7DDD3F27C6ULL, 0xBFD64C7DDD3F27C3ULL, 0x3FEDFEAE622DBE2BULL,
|
||||
0x3FDAA6C82B6D3FCCULL, 0x3FED17E7743E35DBULL, 0xBFED17E7743E35DCULL, 0x3FDAA6C82B6D3FC9ULL,
|
||||
0x3FE771E75F037261ULL, 0x3FE5C77BBE65018CULL, 0xBFE5C77BBE65018CULL, 0x3FE771E75F037261ULL,
|
||||
0x3FA2D865759455E4ULL, 0x3FEFFA72EFFEF75DULL, 0xBFEFFA72EFFEF75DULL, 0x3FA2D865759455CDULL,
|
||||
0x3FEFFA72EFFEF75DULL, 0x3FA2D865759455CDULL, 0xBFA2D865759455D2ULL, 0x3FEFFA72EFFEF75DULL,
|
||||
0x3FE5C77BBE65018DULL, 0x3FE771E75F037261ULL, 0xBFE771E75F037260ULL, 0x3FE5C77BBE65018EULL,
|
||||
0x3FED17E7743E35DCULL, 0x3FDAA6C82B6D3FC9ULL, 0xBFDAA6C82B6D3FC6ULL, 0x3FED17E7743E35DDULL,
|
||||
0x3FD64C7DDD3F27C5ULL, 0x3FEDFEAE622DBE2BULL, 0xBFEDFEAE622DBE2AULL, 0x3FD64C7DDD3F27CAULL,
|
||||
0x3FEF2252F7763ADAULL, 0x3FCD934FE5454311ULL, 0xBFCD934FE5454312ULL, 0x3FEF2252F7763ADAULL,
|
||||
0x3FE0C9704D5D898EULL, 0x3FEB3E4D3EF55712ULL, 0xBFEB3E4D3EF55712ULL, 0x3FE0C9704D5D898FULL,
|
||||
0x3FE9EF43EF29AF94ULL, 0x3FE2BEDB25FAF3EAULL, 0xBFE2BEDB25FAF3EAULL, 0x3FE9EF43EF29AF94ULL,
|
||||
0x3FC45576B1293E58ULL, 0x3FEF97F924C9099BULL, 0xBFEF97F924C9099BULL, 0x3FC45576B1293E5BULL,
|
||||
0x3FEFB5797195D741ULL, 0x3FC139F0CEDAF576ULL, 0xBFC139F0CEDAF574ULL, 0x3FEFB5797195D741ULL,
|
||||
0x3FE36058B10659F3ULL, 0x3FE9777EF4C7D741ULL, 0xBFE9777EF4C7D741ULL, 0x3FE36058B10659F4ULL,
|
||||
0x3FEBA5AA673590D3ULL, 0x3FE01CFC874C3EB7ULL, 0xBFE01CFC874C3EB6ULL, 0x3FEBA5AA673590D3ULL,
|
||||
0x3FD04FB80E37FDAFULL, 0x3FEEF178A3E473C2ULL, 0xBFEEF178A3E473C2ULL, 0x3FD04FB80E37FDB0ULL,
|
||||
0x3FEE426A4B2BC17EULL, 0x3FD4D1E24278E76AULL, 0xBFD4D1E24278E769ULL, 0x3FEE426A4B2BC17FULL,
|
||||
0x3FDC1249D8011EE8ULL, 0x3FECC1F0F3FCFC5CULL, 0xBFECC1F0F3FCFC5DULL, 0x3FDC1249D8011EE5ULL,
|
||||
0x3FE7F8ECE3571771ULL, 0x3FE5328292A35596ULL, 0xBFE5328292A35597ULL, 0x3FE7F8ECE3571770ULL,
|
||||
0x3FAF656E79F820EAULL, 0x3FEFF095658E71ADULL, 0xBFEFF095658E71ADULL, 0x3FAF656E79F820D3ULL,
|
||||
0x3FEFE1CAFCBD5B09ULL, 0x3FB5F6D00A9AA419ULL, 0xBFB5F6D00A9AA40FULL, 0x3FEFE1CAFCBD5B09ULL,
|
||||
0x3FE49A449B9B0939ULL, 0x3FE87C400FBA2EBFULL, 0xBFE87C400FBA2EBFULL, 0x3FE49A449B9B0938ULL,
|
||||
0x3FEC678B3488739BULL, 0x3FDD79775B86E389ULL, 0xBFDD79775B86E38AULL, 0x3FEC678B3488739BULL,
|
||||
0x3FD35410C2E18154ULL, 0x3FEE817BAB4CD10CULL, 0xBFEE817BAB4CD10DULL, 0x3FD35410C2E18151ULL,
|
||||
0x3FEEBBD8C8DF0B74ULL, 0x3FD1D3443F4CDB3DULL, 0xBFD1D3443F4CDB3BULL, 0x3FEEBBD8C8DF0B75ULL,
|
||||
0x3FDEDC1952EF78D7ULL, 0x3FEC08C426725549ULL, 0xBFEC08C426725548ULL, 0x3FDEDC1952EF78D8ULL,
|
||||
0x3FE8FBCCA3EF940DULL, 0x3FE3FED9534556D4ULL, 0xBFE3FED9534556D3ULL, 0x3FE8FBCCA3EF940EULL,
|
||||
0x3FBC3785C79EC2DEULL, 0x3FEFCE15FD6DA67BULL, 0xBFEFCE15FD6DA67BULL, 0x3FBC3785C79EC2E2ULL,
|
||||
0x3FEF7599A3A12077ULL, 0x3FC76DD9DE50BF31ULL, 0xBFC76DD9DE50BF30ULL, 0x3FEF7599A3A12077ULL,
|
||||
0x3FE21A799933EB59ULL, 0x3FEA63091B02FAE2ULL, 0xBFEA63091B02FAE0ULL, 0x3FE21A799933EB5BULL,
|
||||
0x3FEAD2BC9E21D511ULL, 0x3FE1734D63DEDB49ULL, 0xBFE1734D63DEDB47ULL, 0x3FEAD2BC9E21D512ULL,
|
||||
0x3FCA82A025B00451ULL, 0x3FEF4E603B0B2F2DULL, 0xBFEF4E603B0B2F2CULL, 0x3FCA82A025B0045BULL,
|
||||
0x3FEDB6526238A09BULL, 0x3FD7C3A9311DCCE7ULL, 0xBFD7C3A9311DCCE6ULL, 0x3FEDB6526238A09BULL,
|
||||
0x3FD9372A63BC93D7ULL, 0x3FED696173C9E68BULL, 0xBFED696173C9E68BULL, 0x3FD9372A63BC93D8ULL,
|
||||
0x3FE6E74454EAA8AEULL, 0x3FE6591925F0783EULL, 0xBFE6591925F0783DULL, 0x3FE6E74454EAA8AFULL,
|
||||
0x3F8921D1FCDEC78FULL, 0x3FEFFF62169B92DBULL, 0xBFEFFF62169B92DBULL, 0x3F8921D1FCDEC7B3ULL,
|
||||
0x3FEFFFD8858E8A92ULL, 0x3F7921F0FE670071ULL, 0xBF7921F0FE670012ULL, 0x3FEFFFD8858E8A92ULL,
|
||||
0x3FE67CF78491AF10ULL, 0x3FE6C40D73C18275ULL, 0xBFE6C40D73C18276ULL, 0x3FE67CF78491AF0FULL,
|
||||
0x3FED7D0B02B8ECFAULL, 0x3FD8DAA52EC8A4AFULL, 0xBFD8DAA52EC8A4AEULL, 0x3FED7D0B02B8ECFAULL,
|
||||
0x3FD820E3B04EAAC5ULL, 0x3FEDA383A9668987ULL, 0xBFEDA383A9668988ULL, 0x3FD820E3B04EAAC2ULL,
|
||||
0x3FEF58A2B1789E84ULL, 0x3FC9BDCBF2DC4366ULL, 0xBFC9BDCBF2DC4363ULL, 0x3FEF58A2B1789E84ULL,
|
||||
0x3FE19D5A09F2B9B8ULL, 0x3FEAB7325916C0D4ULL, 0xBFEAB7325916C0D4ULL, 0x3FE19D5A09F2B9B9ULL,
|
||||
0x3FEA7F58529FE69DULL, 0x3FE1F0F08BBC861BULL, 0xBFE1F0F08BBC861AULL, 0x3FEA7F58529FE69DULL,
|
||||
0x3FC83366E89C64C8ULL, 0x3FEF6C3F7DF5BBB7ULL, 0xBFEF6C3F7DF5BBB7ULL, 0x3FC83366E89C64CBULL,
|
||||
0x3FEFD37914220B84ULL, 0x3FBAA7B724495C04ULL, 0xBFBAA7B724495C05ULL, 0x3FEFD37914220B84ULL,
|
||||
0x3FE425FF178E6BB2ULL, 0x3FE8DC45331698CCULL, 0xBFE8DC45331698CBULL, 0x3FE425FF178E6BB3ULL,
|
||||
0x3FEC20DE3FA971B0ULL, 0x3FDE83E0EAF85113ULL, 0xBFDE83E0EAF85110ULL, 0x3FEC20DE3FA971B0ULL,
|
||||
0x3FD233BBABC3BB71ULL, 0x3FEEADB2E8E7A88EULL, 0xBFEEADB2E8E7A88DULL, 0x3FD233BBABC3BB76ULL,
|
||||
0x3FEE9084361DF7F3ULL, 0x3FD2F422DAEC0386ULL, 0xBFD2F422DAEC0387ULL, 0x3FEE9084361DF7F2ULL,
|
||||
0x3FDDD28F1481CC57ULL, 0x3FEC5042012B6907ULL, 0xBFEC5042012B6907ULL, 0x3FDDD28F1481CC58ULL,
|
||||
0x3FE89C7E9A4DD4ABULL, 0x3FE473B51B987347ULL, 0xBFE473B51B987347ULL, 0x3FE89C7E9A4DD4AAULL,
|
||||
0x3FB787586A5D5B1FULL, 0x3FEFDD539FF1F456ULL, 0xBFEFDD539FF1F456ULL, 0x3FB787586A5D5B23ULL,
|
||||
0x3FEFF3830F8D575CULL, 0x3FAC428D12C0D7E2ULL, 0xBFAC428D12C0D7DFULL, 0x3FEFF3830F8D575CULL,
|
||||
0x3FE5581038975137ULL, 0x3FE7D7836CC33DB2ULL, 0xBFE7D7836CC33DB2ULL, 0x3FE5581038975138ULL,
|
||||
0x3FECD7D9898B32F6ULL, 0x3FDBB7CF2304BD01ULL, 0xBFDBB7CF2304BD00ULL, 0x3FECD7D9898B32F6ULL,
|
||||
0x3FD530D880AF3C24ULL, 0x3FEE31EAE870CE25ULL, 0xBFEE31EAE870CE25ULL, 0x3FD530D880AF3C25ULL,
|
||||
0x3FEEFE220C0B95EDULL, 0x3FCFDCDC1ADFEDF8ULL, 0xBFCFDCDC1ADFEDF7ULL, 0x3FEEFE220C0B95EDULL,
|
||||
0x3FE0485626AE221AULL, 0x3FEB8C38D27504E9ULL, 0xBFEB8C38D27504E7ULL, 0x3FE0485626AE221DULL,
|
||||
0x3FE995CF2ED80D22ULL, 0x3FE338400D0C8E57ULL, 0xBFE338400D0C8E55ULL, 0x3FE995CF2ED80D24ULL,
|
||||
0x3FC20116D4EC7BCFULL, 0x3FEFAE8E8E46CFBBULL, 0xBFEFAE8E8E46CFBAULL, 0x3FC20116D4EC7BDAULL,
|
||||
0x3FEF9FCE55ADB2C8ULL, 0x3FC38EDBB0CD8D14ULL, 0xBFC38EDBB0CD8D0FULL, 0x3FEF9FCE55ADB2C8ULL,
|
||||
0x3FE2E780E3E8EA17ULL, 0x3FE9D1B1F5EA80D5ULL, 0xBFE9D1B1F5EA80D6ULL, 0x3FE2E780E3E8EA16ULL,
|
||||
0x3FEB5889FE921405ULL, 0x3FE09E907417C5E1ULL, 0xBFE09E907417C5E1ULL, 0x3FEB5889FE921405ULL,
|
||||
0x3FCE56CA1E101A20ULL, 0x3FEF168F53F7205DULL, 0xBFEF168F53F7205DULL, 0x3FCE56CA1E101A1AULL,
|
||||
0x3FEE100CCA2980ACULL, 0x3FD5EE27379EA693ULL, 0xBFD5EE27379EA691ULL, 0x3FEE100CCA2980ACULL,
|
||||
0x3FDB020D6C7F400BULL, 0x3FED02D4FEB2BD92ULL, 0xBFED02D4FEB2BD92ULL, 0x3FDB020D6C7F400CULL,
|
||||
0x3FE79400574F55E5ULL, 0x3FE5A28D2A5D7250ULL, 0xBFE5A28D2A5D724FULL, 0x3FE79400574F55E6ULL,
|
||||
0x3FA5FC00D290CD57ULL, 0x3FEFF871DADB81DFULL, 0xBFEFF871DADB81DFULL, 0x3FA5FC00D290CD60ULL,
|
||||
0x3FEFFC251DF1D3F8ULL, 0x3F9F693731D1CF01ULL, 0xBF9F693731D1CED1ULL, 0x3FEFFC251DF1D3F8ULL,
|
||||
0x3FE5EC3495837074ULL, 0x3FE74F948DA8D28DULL, 0xBFE74F948DA8D28DULL, 0x3FE5EC3495837074ULL,
|
||||
0x3FED2CB220E0EF9FULL, 0x3FDA4B4127DEA1E4ULL, 0xBFDA4B4127DEA1E2ULL, 0x3FED2CB220E0EF9FULL,
|
||||
0x3FD6AA9D7DC77E19ULL, 0x3FEDED05F7DE47D9ULL, 0xBFEDED05F7DE47DAULL, 0x3FD6AA9D7DC77E17ULL,
|
||||
0x3FEF2DC9C9089A9DULL, 0x3FCCCF8CB312B286ULL, 0xBFCCCF8CB312B280ULL, 0x3FEF2DC9C9089A9DULL,
|
||||
0x3FE0F426BB2A8E7FULL, 0x3FEB23CD470013B3ULL, 0xBFEB23CD470013B3ULL, 0x3FE0F426BB2A8E7FULL,
|
||||
0x3FEA0C95EABAF937ULL, 0x3FE2960727629CA8ULL, 0xBFE2960727629CA7ULL, 0x3FEA0C95EABAF938ULL,
|
||||
0x3FC51BDF8597C5F8ULL, 0x3FEF8FD5FFAE41DBULL, 0xBFEF8FD5FFAE41DAULL, 0x3FC51BDF8597C5FAULL,
|
||||
0x3FEFBC1617E44186ULL, 0x3FC072A047BA831DULL, 0xBFC072A047BA831BULL, 0x3FEFBC1617E44186ULL,
|
||||
0x3FE3884185DFEB22ULL, 0x3FE958EFE48E6DD7ULL, 0xBFE958EFE48E6DD5ULL, 0x3FE3884185DFEB24ULL,
|
||||
0x3FEBBED7C49380EAULL, 0x3FDFE2F64BE71210ULL, 0xBFDFE2F64BE7120BULL, 0x3FEBBED7C49380EBULL,
|
||||
0x3FD0B0D9CFDBDB91ULL, 0x3FEEE482E25A9DBCULL, 0xBFEEE482E25A9DBBULL, 0x3FD0B0D9CFDBDB96ULL,
|
||||
0x3FEE529F04729FFCULL, 0x3FD472B8A5571054ULL, 0xBFD472B8A5571053ULL, 0x3FEE529F04729FFDULL,
|
||||
0x3FDC6C7F4997000BULL, 0x3FECABC169A0B900ULL, 0xBFECABC169A0B900ULL, 0x3FDC6C7F4997000CULL,
|
||||
0x3FE81A1B33B57ACCULL, 0x3FE50CC09F59A09BULL, 0xBFE50CC09F59A09BULL, 0x3FE81A1B33B57ACCULL,
|
||||
0x3FB1440134D709B6ULL, 0x3FEFED58ECB673C4ULL, 0xBFEFED58ECB673C4ULL, 0x3FB1440134D709BBULL,
|
||||
0x3FEFE5F3AF2E3940ULL, 0x3FB4661179272096ULL, 0xBFB466117927208EULL, 0x3FEFE5F3AF2E3941ULL,
|
||||
0x3FE4C0A145EC0005ULL, 0x3FE85BC51AE958CCULL, 0xBFE85BC51AE958CBULL, 0x3FE4C0A145EC0005ULL,
|
||||
0x3FEC7E8E52233CF3ULL, 0x3FDD2016E8E9DB5BULL, 0xBFDD2016E8E9DB59ULL, 0x3FEC7E8E52233CF4ULL,
|
||||
0x3FD3B3CEFA0414B9ULL, 0x3FEE7227DB6A9744ULL, 0xBFEE7227DB6A9744ULL, 0x3FD3B3CEFA0414BAULL,
|
||||
0x3FEEC9B2D3C3BF84ULL, 0x3FD172A0D7765177ULL, 0xBFD172A0D7765175ULL, 0x3FEEC9B2D3C3BF84ULL,
|
||||
0x3FDF3405963FD069ULL, 0x3FEBF064E15377DDULL, 0xBFEBF064E15377DDULL, 0x3FDF3405963FD066ULL,
|
||||
0x3FE91B166FD49DA2ULL, 0x3FE3D78238C58343ULL, 0xBFE3D78238C58344ULL, 0x3FE91B166FD49DA1ULL,
|
||||
0x3FBDC70ECBAE9FD1ULL, 0x3FEFC8646CFEB721ULL, 0xBFEFC8646CFEB721ULL, 0x3FBDC70ECBAE9FC5ULL,
|
||||
0x3FEF7EA629E63D6EULL, 0x3FC6A81304F64AB2ULL, 0xBFC6A81304F64AB2ULL, 0x3FEF7EA629E63D6EULL,
|
||||
0x3FE243D5FB98AC20ULL, 0x3FEA4678C8119AC8ULL, 0xBFEA4678C8119AC8ULL, 0x3FE243D5FB98AC1FULL,
|
||||
0x3FEAEE04B43C1474ULL, 0x3FE14915AF336CEBULL, 0xBFE14915AF336CEBULL, 0x3FEAEE04B43C1474ULL,
|
||||
0x3FCB4732EF3D6722ULL, 0x3FEF43D085FF92DDULL, 0xBFEF43D085FF92DDULL, 0x3FCB4732EF3D6724ULL,
|
||||
0x3FEDC8D7CB410260ULL, 0x3FD766340F2418F6ULL, 0xBFD766340F2418F6ULL, 0x3FEDC8D7CB410260ULL,
|
||||
0x3FD993716141BDFEULL, 0x3FED556F52E93EB1ULL, 0xBFED556F52E93EB0ULL, 0x3FD993716141BE03ULL,
|
||||
0x3FE70A42B3176D7AULL, 0x3FE63503A31C1BE9ULL, 0xBFE63503A31C1BE7ULL, 0x3FE70A42B3176D7BULL,
|
||||
0x3F92D936BBE30EFDULL, 0x3FEFFE9CB44B51A1ULL, 0xBFEFFE9CB44B51A1ULL, 0x3F92D936BBE30F4EULL,
|
||||
0x3FEFFE9CB44B51A1ULL, 0x3F92D936BBE30EFDULL, 0xBF92D936BBE30ED9ULL, 0x3FEFFE9CB44B51A1ULL,
|
||||
0x3FE63503A31C1BE9ULL, 0x3FE70A42B3176D7AULL, 0xBFE70A42B3176D7AULL, 0x3FE63503A31C1BE9ULL,
|
||||
0x3FED556F52E93EB1ULL, 0x3FD993716141BDFEULL, 0xBFD993716141BDFCULL, 0x3FED556F52E93EB1ULL,
|
||||
0x3FD766340F2418F8ULL, 0x3FEDC8D7CB410260ULL, 0xBFEDC8D7CB410260ULL, 0x3FD766340F2418F5ULL,
|
||||
0x3FEF43D085FF92DDULL, 0x3FCB4732EF3D6722ULL, 0xBFCB4732EF3D671EULL, 0x3FEF43D085FF92DDULL,
|
||||
0x3FE14915AF336CECULL, 0x3FEAEE04B43C1473ULL, 0xBFEAEE04B43C1473ULL, 0x3FE14915AF336CECULL,
|
||||
0x3FEA4678C8119AC8ULL, 0x3FE243D5FB98AC1FULL, 0xBFE243D5FB98AC1EULL, 0x3FEA4678C8119AC9ULL,
|
||||
0x3FC6A81304F64AB6ULL, 0x3FEF7EA629E63D6EULL, 0xBFEF7EA629E63D6EULL, 0x3FC6A81304F64AB9ULL,
|
||||
0x3FEFC8646CFEB721ULL, 0x3FBDC70ECBAE9FC8ULL, 0xBFBDC70ECBAE9FC8ULL, 0x3FEFC8646CFEB721ULL,
|
||||
0x3FE3D78238C58344ULL, 0x3FE91B166FD49DA2ULL, 0xBFE91B166FD49DA0ULL, 0x3FE3D78238C58346ULL,
|
||||
0x3FEBF064E15377DDULL, 0x3FDF3405963FD068ULL, 0xBFDF3405963FD063ULL, 0x3FEBF064E15377DEULL,
|
||||
0x3FD172A0D7765177ULL, 0x3FEEC9B2D3C3BF84ULL, 0xBFEEC9B2D3C3BF83ULL, 0x3FD172A0D776517CULL,
|
||||
0x3FEE7227DB6A9744ULL, 0x3FD3B3CEFA0414B7ULL, 0xBFD3B3CEFA0414B7ULL, 0x3FEE7227DB6A9744ULL,
|
||||
0x3FDD2016E8E9DB5BULL, 0x3FEC7E8E52233CF3ULL, 0xBFEC7E8E52233CF3ULL, 0x3FDD2016E8E9DB5CULL,
|
||||
0x3FE85BC51AE958CCULL, 0x3FE4C0A145EC0004ULL, 0xBFE4C0A145EC0004ULL, 0x3FE85BC51AE958CDULL,
|
||||
0x3FB4661179272096ULL, 0x3FEFE5F3AF2E3940ULL, 0xBFEFE5F3AF2E3940ULL, 0x3FB466117927209BULL,
|
||||
0x3FEFED58ECB673C4ULL, 0x3FB1440134D709B2ULL, 0xBFB1440134D709ADULL, 0x3FEFED58ECB673C4ULL,
|
||||
0x3FE50CC09F59A09BULL, 0x3FE81A1B33B57ACBULL, 0xBFE81A1B33B57ACBULL, 0x3FE50CC09F59A09CULL,
|
||||
0x3FECABC169A0B901ULL, 0x3FDC6C7F4997000AULL, 0xBFDC6C7F49970009ULL, 0x3FECABC169A0B901ULL,
|
||||
0x3FD472B8A5571055ULL, 0x3FEE529F04729FFCULL, 0xBFEE529F04729FFCULL, 0x3FD472B8A5571056ULL,
|
||||
0x3FEEE482E25A9DBCULL, 0x3FD0B0D9CFDBDB90ULL, 0xBFD0B0D9CFDBDB8FULL, 0x3FEEE482E25A9DBCULL,
|
||||
0x3FDFE2F64BE71210ULL, 0x3FEBBED7C49380EAULL, 0xBFEBBED7C49380EBULL, 0x3FDFE2F64BE7120EULL,
|
||||
0x3FE958EFE48E6DD7ULL, 0x3FE3884185DFEB22ULL, 0xBFE3884185DFEB23ULL, 0x3FE958EFE48E6DD6ULL,
|
||||
0x3FC072A047BA831FULL, 0x3FEFBC1617E44186ULL, 0xBFEFBC1617E44186ULL, 0x3FC072A047BA831AULL,
|
||||
0x3FEF8FD5FFAE41DBULL, 0x3FC51BDF8597C5F2ULL, 0xBFC51BDF8597C5F3ULL, 0x3FEF8FD5FFAE41DBULL,
|
||||
0x3FE2960727629CA8ULL, 0x3FEA0C95EABAF936ULL, 0xBFEA0C95EABAF937ULL, 0x3FE2960727629CA8ULL,
|
||||
0x3FEB23CD470013B4ULL, 0x3FE0F426BB2A8E7DULL, 0xBFE0F426BB2A8E7EULL, 0x3FEB23CD470013B4ULL,
|
||||
0x3FCCCF8CB312B284ULL, 0x3FEF2DC9C9089A9DULL, 0xBFEF2DC9C9089A9DULL, 0x3FCCCF8CB312B286ULL,
|
||||
0x3FEDED05F7DE47DAULL, 0x3FD6AA9D7DC77E16ULL, 0xBFD6AA9D7DC77E17ULL, 0x3FEDED05F7DE47DAULL,
|
||||
0x3FDA4B4127DEA1E4ULL, 0x3FED2CB220E0EF9FULL, 0xBFED2CB220E0EF9EULL, 0x3FDA4B4127DEA1E8ULL,
|
||||
0x3FE74F948DA8D28DULL, 0x3FE5EC3495837074ULL, 0xBFE5EC3495837073ULL, 0x3FE74F948DA8D28EULL,
|
||||
0x3F9F693731D1CEF4ULL, 0x3FEFFC251DF1D3F8ULL, 0xBFEFFC251DF1D3F8ULL, 0x3F9F693731D1CF46ULL,
|
||||
0x3FEFF871DADB81DFULL, 0x3FA5FC00D290CD43ULL, 0xBFA5FC00D290CD45ULL, 0x3FEFF871DADB81DFULL,
|
||||
0x3FE5A28D2A5D7251ULL, 0x3FE79400574F55E4ULL, 0xBFE79400574F55E5ULL, 0x3FE5A28D2A5D7250ULL,
|
||||
0x3FED02D4FEB2BD92ULL, 0x3FDB020D6C7F4009ULL, 0xBFDB020D6C7F4009ULL, 0x3FED02D4FEB2BD92ULL,
|
||||
0x3FD5EE27379EA693ULL, 0x3FEE100CCA2980ACULL, 0xBFEE100CCA2980ACULL, 0x3FD5EE27379EA694ULL,
|
||||
0x3FEF168F53F7205DULL, 0x3FCE56CA1E101A1BULL, 0xBFCE56CA1E101A1CULL, 0x3FEF168F53F7205DULL,
|
||||
0x3FE09E907417C5E0ULL, 0x3FEB5889FE921405ULL, 0xBFEB5889FE921404ULL, 0x3FE09E907417C5E2ULL,
|
||||
0x3FE9D1B1F5EA80D6ULL, 0x3FE2E780E3E8EA16ULL, 0xBFE2E780E3E8EA15ULL, 0x3FE9D1B1F5EA80D7ULL,
|
||||
0x3FC38EDBB0CD8D13ULL, 0x3FEF9FCE55ADB2C8ULL, 0xBFEF9FCE55ADB2C8ULL, 0x3FC38EDBB0CD8D1DULL,
|
||||
0x3FEFAE8E8E46CFBBULL, 0x3FC20116D4EC7BCEULL, 0xBFC20116D4EC7BCBULL, 0x3FEFAE8E8E46CFBBULL,
|
||||
0x3FE338400D0C8E57ULL, 0x3FE995CF2ED80D22ULL, 0xBFE995CF2ED80D23ULL, 0x3FE338400D0C8E56ULL,
|
||||
0x3FEB8C38D27504E9ULL, 0x3FE0485626AE221AULL, 0xBFE0485626AE221BULL, 0x3FEB8C38D27504E8ULL,
|
||||
0x3FCFDCDC1ADFEDFCULL, 0x3FEEFE220C0B95ECULL, 0xBFEEFE220C0B95EDULL, 0x3FCFDCDC1ADFEDF6ULL,
|
||||
0x3FEE31EAE870CE25ULL, 0x3FD530D880AF3C24ULL, 0xBFD530D880AF3C22ULL, 0x3FEE31EAE870CE25ULL,
|
||||
0x3FDBB7CF2304BD02ULL, 0x3FECD7D9898B32F6ULL, 0xBFECD7D9898B32F5ULL, 0x3FDBB7CF2304BD03ULL,
|
||||
0x3FE7D7836CC33DB3ULL, 0x3FE5581038975137ULL, 0xBFE5581038975136ULL, 0x3FE7D7836CC33DB3ULL,
|
||||
0x3FAC428D12C0D7F0ULL, 0x3FEFF3830F8D575CULL, 0xBFEFF3830F8D575CULL, 0x3FAC428D12C0D7F9ULL,
|
||||
0x3FEFDD539FF1F456ULL, 0x3FB787586A5D5B21ULL, 0xBFB787586A5D5B16ULL, 0x3FEFDD539FF1F456ULL,
|
||||
0x3FE473B51B987347ULL, 0x3FE89C7E9A4DD4AAULL, 0xBFE89C7E9A4DD4A9ULL, 0x3FE473B51B987348ULL,
|
||||
0x3FEC5042012B6907ULL, 0x3FDDD28F1481CC58ULL, 0xBFDDD28F1481CC55ULL, 0x3FEC5042012B6908ULL,
|
||||
0x3FD2F422DAEC0389ULL, 0x3FEE9084361DF7F2ULL, 0xBFEE9084361DF7F2ULL, 0x3FD2F422DAEC038AULL,
|
||||
0x3FEEADB2E8E7A88EULL, 0x3FD233BBABC3BB72ULL, 0xBFD233BBABC3BB6FULL, 0x3FEEADB2E8E7A88EULL,
|
||||
0x3FDE83E0EAF85116ULL, 0x3FEC20DE3FA971AFULL, 0xBFEC20DE3FA971B0ULL, 0x3FDE83E0EAF85113ULL,
|
||||
0x3FE8DC45331698CCULL, 0x3FE425FF178E6BB1ULL, 0xBFE425FF178E6BB2ULL, 0x3FE8DC45331698CCULL,
|
||||
0x3FBAA7B724495C0EULL, 0x3FEFD37914220B84ULL, 0xBFEFD37914220B84ULL, 0x3FBAA7B724495C03ULL,
|
||||
0x3FEF6C3F7DF5BBB7ULL, 0x3FC83366E89C64C5ULL, 0xBFC83366E89C64C4ULL, 0x3FEF6C3F7DF5BBB7ULL,
|
||||
0x3FE1F0F08BBC861BULL, 0x3FEA7F58529FE69DULL, 0xBFEA7F58529FE69CULL, 0x3FE1F0F08BBC861CULL,
|
||||
0x3FEAB7325916C0D4ULL, 0x3FE19D5A09F2B9B8ULL, 0xBFE19D5A09F2B9B7ULL, 0x3FEAB7325916C0D5ULL,
|
||||
0x3FC9BDCBF2DC4368ULL, 0x3FEF58A2B1789E84ULL, 0xBFEF58A2B1789E84ULL, 0x3FC9BDCBF2DC436AULL,
|
||||
0x3FEDA383A9668988ULL, 0x3FD820E3B04EAAC4ULL, 0xBFD820E3B04EAAC3ULL, 0x3FEDA383A9668988ULL,
|
||||
0x3FD8DAA52EC8A4B0ULL, 0x3FED7D0B02B8ECF9ULL, 0xBFED7D0B02B8ECF8ULL, 0x3FD8DAA52EC8A4B5ULL,
|
||||
0x3FE6C40D73C18275ULL, 0x3FE67CF78491AF10ULL, 0xBFE67CF78491AF0EULL, 0x3FE6C40D73C18277ULL,
|
||||
0x3F7921F0FE67009FULL, 0x3FEFFFD8858E8A92ULL, 0xBFEFFFD8858E8A92ULL, 0x3F7921F0FE6701E6ULL,
|
||||
0x3FEFFFF621621D02ULL, 0x3F6921F8BECCA4BAULL, 0xBF6921F8BECCA515ULL, 0x3FEFFFF621621D02ULL,
|
||||
0x3FE68ED1EAA19C72ULL, 0x3FE6B25CED2FE29BULL, 0xBFE6B25CED2FE29AULL, 0x3FE68ED1EAA19C73ULL,
|
||||
0x3FED86C48445A450ULL, 0x3FD8AC4B86D5ED44ULL, 0xBFD8AC4B86D5ED45ULL, 0x3FED86C48445A44FULL,
|
||||
0x3FD84F6AAAF3903EULL, 0x3FED9A00DD8B3D46ULL, 0xBFED9A00DD8B3D45ULL, 0x3FD84F6AAAF39043ULL,
|
||||
0x3FEF5DA6ED43685DULL, 0x3FC95B49E9B62AF9ULL, 0xBFC95B49E9B62AFBULL, 0x3FEF5DA6ED43685DULL,
|
||||
0x3FE1B250171373BFULL, 0x3FEAA9547A2CB98EULL, 0xBFEAA9547A2CB98EULL, 0x3FE1B250171373BFULL,
|
||||
0x3FEA8D676E545AD2ULL, 0x3FE1DC1B64DC4872ULL, 0xBFE1DC1B64DC4872ULL, 0x3FEA8D676E545AD2ULL,
|
||||
0x3FC8961727C41802ULL, 0x3FEF677556883CEEULL, 0xBFEF677556883CEEULL, 0x3FC8961727C41805ULL,
|
||||
0x3FEFD60D2DA75C9EULL, 0x3FB9DFB6EB24A85CULL, 0xBFB9DFB6EB24A857ULL, 0x3FEFD60D2DA75C9EULL,
|
||||
0x3FE4397F5B2A4380ULL, 0x3FE8CC6A75184654ULL, 0xBFE8CC6A75184654ULL, 0x3FE4397F5B2A4380ULL,
|
||||
0x3FEC2CD14931E3F1ULL, 0x3FDE57A86D3CD824ULL, 0xBFDE57A86D3CD823ULL, 0x3FEC2CD14931E3F2ULL,
|
||||
0x3FD263E6995554BBULL, 0x3FEEA68393E65800ULL, 0xBFEEA68393E65800ULL, 0x3FD263E6995554BCULL,
|
||||
0x3FEE97EC36016B30ULL, 0x3FD2C41A4E954520ULL, 0xBFD2C41A4E95451FULL, 0x3FEE97EC36016B31ULL,
|
||||
0x3FDDFEFF66A941DEULL, 0x3FEC44833141C004ULL, 0xBFEC44833141C005ULL, 0x3FDDFEFF66A941DCULL,
|
||||
0x3FE8AC871EDE1D88ULL, 0x3FE4605A692B32A2ULL, 0xBFE4605A692B32A3ULL, 0x3FE8AC871EDE1D87ULL,
|
||||
0x3FB84F8712C130A5ULL, 0x3FEFDAFA7514538CULL, 0xBFEFDAFA7514538CULL, 0x3FB84F8712C1309AULL,
|
||||
0x3FEFF4DC54B1BED3ULL, 0x3FAAB101BD5F8317ULL, 0xBFAAB101BD5F8304ULL, 0x3FEFF4DC54B1BED3ULL,
|
||||
0x3FE56AC35197649EULL, 0x3FE7C6B89CE2D333ULL, 0xBFE7C6B89CE2D333ULL, 0x3FE56AC35197649EULL,
|
||||
0x3FECE2B32799A060ULL, 0x3FDB8A7814FD5693ULL, 0xBFDB8A7814FD5695ULL, 0x3FECE2B32799A060ULL,
|
||||
0x3FD5604012F467B6ULL, 0x3FEE298F4439197AULL, 0xBFEE298F4439197AULL, 0x3FD5604012F467B4ULL,
|
||||
0x3FEF045A14CF738CULL, 0x3FCF7B7480BD3801ULL, 0xBFCF7B7480BD37FDULL, 0x3FEF045A14CF738CULL,
|
||||
0x3FE05DF3EC31B8B8ULL, 0x3FEB7F6686E792E9ULL, 0xBFEB7F6686E792E9ULL, 0x3FE05DF3EC31B8B8ULL,
|
||||
0x3FE9A4DFA42B06B2ULL, 0x3FE32421EC49A61FULL, 0xBFE32421EC49A61EULL, 0x3FE9A4DFA42B06B3ULL,
|
||||
0x3FC264994DFD340EULL, 0x3FEFAAFBCB0CFDDBULL, 0xBFEFAAFBCB0CFDDBULL, 0x3FC264994DFD3410ULL,
|
||||
0x3FEFA39BAC7A1791ULL, 0x3FC32B7BF94516A7ULL, 0xBFC32B7BF94516A7ULL, 0x3FEFA39BAC7A1791ULL,
|
||||
0x3FE2FBC24B441015ULL, 0x3FE9C2D110F075C3ULL, 0xBFE9C2D110F075C1ULL, 0x3FE2FBC24B441017ULL,
|
||||
0x3FEB658F14FDBC47ULL, 0x3FE089112032B08CULL, 0xBFE089112032B08AULL, 0x3FEB658F14FDBC48ULL,
|
||||
0x3FCEB86B462DE348ULL, 0x3FEF1090BC898F5FULL, 0xBFEF1090BC898F5EULL, 0x3FCEB86B462DE352ULL,
|
||||
0x3FEE18A02FDC66D9ULL, 0x3FD5BEE78B9DB3B6ULL, 0xBFD5BEE78B9DB3B6ULL, 0x3FEE18A02FDC66D9ULL,
|
||||
0x3FDB2F971DB31972ULL, 0x3FECF830E8CE467BULL, 0xBFECF830E8CE467AULL, 0x3FDB2F971DB31973ULL,
|
||||
0x3FE7A4F707BF97D2ULL, 0x3FE59001D5F723DFULL, 0xBFE59001D5F723DFULL, 0x3FE7A4F707BF97D3ULL,
|
||||
0x3FA78DBAA5874688ULL, 0x3FEFF753BB1B9164ULL, 0xBFEFF753BB1B9164ULL, 0x3FA78DBAA5874691ULL,
|
||||
0x3FEFFCE09CE2A679ULL, 0x3F9C454F4CE53B1CULL, 0xBF9C454F4CE53B10ULL, 0x3FEFFCE09CE2A679ULL,
|
||||
0x3FE5FE7CBDE56A10ULL, 0x3FE73E558E079942ULL, 0xBFE73E558E079940ULL, 0x3FE5FE7CBDE56A11ULL,
|
||||
0x3FED36FC7BCBFBDCULL, 0x3FDA1D6543B50AC0ULL, 0xBFDA1D6543B50ABFULL, 0x3FED36FC7BCBFBDCULL,
|
||||
0x3FD6D998638A0CB6ULL, 0x3FEDE4160F6D8D81ULL, 0xBFEDE4160F6D8D80ULL, 0x3FD6D998638A0CBBULL,
|
||||
0x3FEF33685A3AAEF0ULL, 0x3FCC6D90535D74DCULL, 0xBFCC6D90535D74DBULL, 0x3FEF33685A3AAEF0ULL,
|
||||
0x3FE1097248D0A957ULL, 0x3FEB16742A4CA2F4ULL, 0xBFEB16742A4CA2F4ULL, 0x3FE1097248D0A957ULL,
|
||||
0x3FEA1B26D2C0A75EULL, 0x3FE2818BEF4D3CBAULL, 0xBFE2818BEF4D3CB9ULL, 0x3FEA1B26D2C0A75EULL,
|
||||
0x3FC57F008654CBE0ULL, 0x3FEF8BA737CB4B77ULL, 0xBFEF8BA737CB4B77ULL, 0x3FC57F008654CBE2ULL,
|
||||
0x3FEFBF470F0A8D88ULL, 0x3FC00EE8AD6FB85BULL, 0xBFC00EE8AD6FB855ULL, 0x3FEFBF470F0A8D88ULL,
|
||||
0x3FE39C23E3D63029ULL, 0x3FE94990E3AC4A6CULL, 0xBFE94990E3AC4A6BULL, 0x3FE39C23E3D6302AULL,
|
||||
0x3FEBCB54CB0D2327ULL, 0x3FDFB7575C24D2DEULL, 0xBFDFB7575C24D2DBULL, 0x3FEBCB54CB0D2328ULL,
|
||||
0x3FD0E15B4E1749D0ULL, 0x3FEEDDEB6A078650ULL, 0xBFEEDDEB6A078650ULL, 0x3FD0E15B4E1749D1ULL,
|
||||
0x3FEE5A9D550467D3ULL, 0x3FD44310DC8936F0ULL, 0xBFD44310DC8936EEULL, 0x3FEE5A9D550467D4ULL,
|
||||
0x3FDC997FC386538BULL, 0x3FECA08F19B9C448ULL, 0xBFECA08F19B9C449ULL, 0x3FDC997FC3865388ULL,
|
||||
0x3FE82A9C13F545FFULL, 0x3FE4F9CC25CCA486ULL, 0xBFE4F9CC25CCA487ULL, 0x3FE82A9C13F545FFULL,
|
||||
0x3FB20C9674ED4457ULL, 0x3FEFEB9D2530410FULL, 0xBFEFEB9D2530410FULL, 0x3FB20C9674ED444CULL,
|
||||
0x3FEFE7EA85482D60ULL, 0x3FB39D9F12C5A299ULL, 0xBFB39D9F12C5A29AULL, 0x3FEFE7EA85482D60ULL,
|
||||
0x3FE4D3BC6D589F80ULL, 0x3FE84B7111AF83F9ULL, 0xBFE84B7111AF83FAULL, 0x3FE4D3BC6D589F80ULL,
|
||||
0x3FEC89F587029C13ULL, 0x3FDCF34BAEE1CD21ULL, 0xBFDCF34BAEE1CD21ULL, 0x3FEC89F587029C13ULL,
|
||||
0x3FD3E39BE96EC271ULL, 0x3FEE6A61C55D53A7ULL, 0xBFEE6A61C55D53A7ULL, 0x3FD3E39BE96EC272ULL,
|
||||
0x3FEED0835E999009ULL, 0x3FD1423EEFC69378ULL, 0xBFD1423EEFC69378ULL, 0x3FEED0835E999009ULL,
|
||||
0x3FDF5FDEE656CDA2ULL, 0x3FEBE41B611154C1ULL, 0xBFEBE41B611154BFULL, 0x3FDF5FDEE656CDA7ULL,
|
||||
0x3FE92AA41FC5A815ULL, 0x3FE3C3C44981C517ULL, 0xBFE3C3C44981C516ULL, 0x3FE92AA41FC5A816ULL,
|
||||
0x3FBE8EB7FDE4AA3EULL, 0x3FEFC56E3B7D9AF6ULL, 0xBFEFC56E3B7D9AF6ULL, 0x3FBE8EB7FDE4AA52ULL,
|
||||
0x3FEF830F4A40C60CULL, 0x3FC6451A831D830DULL, 0xBFC6451A831D8309ULL, 0x3FEF830F4A40C60CULL,
|
||||
0x3FE258734CBB7111ULL, 0x3FEA38184A593BC5ULL, 0xBFEA38184A593BC6ULL, 0x3FE258734CBB710FULL,
|
||||
0x3FEAFB8FD89F57B6ULL, 0x3FE133E9CFEE254EULL, 0xBFE133E9CFEE2550ULL, 0x3FEAFB8FD89F57B6ULL,
|
||||
0x3FCBA96334F15DB0ULL, 0x3FEF3E6BBC1BBC65ULL, 0xBFEF3E6BBC1BBC65ULL, 0x3FCBA96334F15DAAULL,
|
||||
0x3FEDD1FEF38A915AULL, 0x3FD73763C9261092ULL, 0xBFD73763C9261090ULL, 0x3FEDD1FEF38A915AULL,
|
||||
0x3FD9C17D440DF9F4ULL, 0x3FED4B5B1B187524ULL, 0xBFED4B5B1B187523ULL, 0x3FD9C17D440DF9F5ULL,
|
||||
0x3FE71BAC960E41BFULL, 0x3FE622E44FEC22FFULL, 0xBFE622E44FEC22FEULL, 0x3FE71BAC960E41C0ULL,
|
||||
0x3F95FD4D21FAB242ULL, 0x3FEFFE1C6870CB77ULL, 0xBFEFFE1C6870CB77ULL, 0x3F95FD4D21FAB254ULL,
|
||||
0x3FEFFF0943C53BD1ULL, 0x3F8F6A296AB997CAULL, 0xBF8F6A296AB997C9ULL, 0x3FEFFF0943C53BD1ULL,
|
||||
0x3FE64715437F535BULL, 0x3FE6F8CA99C95B75ULL, 0xBFE6F8CA99C95B74ULL, 0x3FE64715437F535CULL,
|
||||
0x3FED5F7172888A7FULL, 0x3FD96555B7AB948FULL, 0xBFD96555B7AB948FULL, 0x3FED5F7172888A7FULL,
|
||||
0x3FD794F5E613DFAEULL, 0x3FEDBF9E4395759BULL, 0xBFEDBF9E4395759AULL, 0x3FD794F5E613DFB3ULL,
|
||||
0x3FEF492206BCABB4ULL, 0x3FCAE4F1D5F3B9ABULL, 0xBFCAE4F1D5F3B9ABULL, 0x3FEF492206BCABB4ULL,
|
||||
0x3FE15E36E4DBE2BDULL, 0x3FEAE068F345ECEEULL, 0xBFEAE068F345ECEFULL, 0x3FE15E36E4DBE2BCULL,
|
||||
0x3FEA54C91090F524ULL, 0x3FE22F2D662C13E1ULL, 0xBFE22F2D662C13E1ULL, 0x3FEA54C91090F523ULL,
|
||||
0x3FC70AFD8D08C4FFULL, 0x3FEF7A299C1A322AULL, 0xBFEF7A299C1A322AULL, 0x3FC70AFD8D08C501ULL,
|
||||
0x3FEFCB4703914354ULL, 0x3FBCFF533B307DC1ULL, 0xBFBCFF533B307DB9ULL, 0x3FEFCB4703914354ULL,
|
||||
0x3FE3EB33EABE0681ULL, 0x3FE90B7943575EFEULL, 0xBFE90B7943575EFDULL, 0x3FE3EB33EABE0681ULL,
|
||||
0x3FEBFC9D25A1B147ULL, 0x3FDF081906BFF7FDULL, 0xBFDF081906BFF7FCULL, 0x3FEBFC9D25A1B148ULL,
|
||||
0x3FD1A2F7FBE8F245ULL, 0x3FEEC2CF4B1AF6B2ULL, 0xBFEEC2CF4B1AF6B2ULL, 0x3FD1A2F7FBE8F246ULL,
|
||||
0x3FEE79DB29A5165AULL, 0x3FD383F5E353B6AAULL, 0xBFD383F5E353B6A8ULL, 0x3FEE79DB29A5165AULL,
|
||||
0x3FDD4CD02BA8609EULL, 0x3FEC7315899EAAD7ULL, 0xBFEC7315899EAAD7ULL, 0x3FDD4CD02BA8609CULL,
|
||||
0x3FE86C0A1D9AA195ULL, 0x3FE4AD79516722F0ULL, 0xBFE4AD79516722F1ULL, 0x3FE86C0A1D9AA195ULL,
|
||||
0x3FB52E774A4D4D12ULL, 0x3FEFE3E92BE9D886ULL, 0xBFEFE3E92BE9D886ULL, 0x3FB52E774A4D4D06ULL,
|
||||
0x3FEFEF0102826191ULL, 0x3FB07B614E463064ULL, 0xBFB07B614E463057ULL, 0x3FEFEF0102826191ULL,
|
||||
0x3FE51FA81CD99AA6ULL, 0x3FE8098B756E52FAULL, 0xBFE8098B756E52FBULL, 0x3FE51FA81CD99AA6ULL,
|
||||
0x3FECB6E20A00DA99ULL, 0x3FDC3F6D47263129ULL, 0xBFDC3F6D4726312AULL, 0x3FECB6E20A00DA99ULL,
|
||||
0x3FD4A253D11B82F6ULL, 0x3FEE4A8DFF81CE5EULL, 0xBFEE4A8DFF81CE5EULL, 0x3FD4A253D11B82F3ULL,
|
||||
0x3FEEEB074C50A544ULL, 0x3FD0804E05EB661EULL, 0xBFD0804E05EB661BULL, 0x3FEEEB074C50A545ULL,
|
||||
0x3FE00740C82B82E2ULL, 0x3FEBB249A0B6C40CULL, 0xBFEBB249A0B6C40CULL, 0x3FE00740C82B82E2ULL,
|
||||
0x3FE9683F42BD7FE1ULL, 0x3FE374531B817F8DULL, 0xBFE374531B817F8CULL, 0x3FE9683F42BD7FE2ULL,
|
||||
0x3FC0D64DBCB2678CULL, 0x3FEFB8D18D66ADB7ULL, 0xBFEFB8D18D66ADB7ULL, 0x3FC0D64DBCB2678EULL,
|
||||
0x3FEF93F14F85AC08ULL, 0x3FC4B8B17F79FA88ULL, 0xBFC4B8B17F79FA86ULL, 0x3FEF93F14F85AC08ULL,
|
||||
0x3FE2AA76E87AEB58ULL, 0x3FE9FDF4F13149DEULL, 0xBFE9FDF4F13149DDULL, 0x3FE2AA76E87AEB5AULL,
|
||||
0x3FEB3115A5F37BF4ULL, 0x3FE0DED0B84BC4B5ULL, 0xBFE0DED0B84BC4B3ULL, 0x3FEB3115A5F37BF5ULL,
|
||||
0x3FCD31774D2CBDF0ULL, 0x3FEF2817FC4609CDULL, 0xBFEF2817FC4609CDULL, 0x3FCD31774D2CBDFAULL,
|
||||
0x3FEDF5E36A9BA59CULL, 0x3FD67B949CAD63CAULL, 0xBFD67B949CAD63C9ULL, 0x3FEDF5E36A9BA59CULL,
|
||||
0x3FDA790CD3DBF31BULL, 0x3FED2255C6E5A4E0ULL, 0xBFED2255C6E5A4E0ULL, 0x3FDA790CD3DBF31CULL,
|
||||
0x3FE760C52C304764ULL, 0x3FE5D9DEE73E345CULL, 0xBFE5D9DEE73E345BULL, 0x3FE760C52C304764ULL,
|
||||
0x3FA14685DB42C187ULL, 0x3FEFFB55E425FDAEULL, 0xBFEFFB55E425FDAEULL, 0x3FA14685DB42C190ULL,
|
||||
0x3FEFF97C4208C014ULL, 0x3FA46A396FF86179ULL, 0xBFA46A396FF8616DULL, 0x3FEFF97C4208C014ULL,
|
||||
0x3FE5B50B264F7449ULL, 0x3FE782FB1B90B35AULL, 0xBFE782FB1B90B35BULL, 0x3FE5B50B264F7447ULL,
|
||||
0x3FED0D672F59D2B9ULL, 0x3FDAD473125CDC08ULL, 0xBFDAD473125CDC0BULL, 0x3FED0D672F59D2B8ULL,
|
||||
0x3FD61D595C88C204ULL, 0x3FEE0766D9280F54ULL, 0xBFEE0766D9280F55ULL, 0x3FD61D595C88C201ULL,
|
||||
0x3FEF1C7ABE284708ULL, 0x3FCDF5163F01099AULL, 0xBFCDF5163F010996ULL, 0x3FEF1C7ABE284709ULL,
|
||||
0x3FE0B405878F85ECULL, 0x3FEB4B7409DE7925ULL, 0xBFEB4B7409DE7925ULL, 0x3FE0B405878F85EDULL,
|
||||
0x3FE9E082EDB42472ULL, 0x3FE2D333D34E9BB7ULL, 0xBFE2D333D34E9BB7ULL, 0x3FE9E082EDB42473ULL,
|
||||
0x3FC3F22F57DB4896ULL, 0x3FEF9BED7CFBDE29ULL, 0xBFEF9BED7CFBDE29ULL, 0x3FC3F22F57DB4898ULL,
|
||||
0x3FEFB20DC681D54DULL, 0x3FC19D8940BE24E7ULL, 0xBFC19D8940BE24E8ULL, 0x3FEFB20DC681D54CULL,
|
||||
0x3FE34C5252C14DE2ULL, 0x3FE986AEF1457593ULL, 0xBFE986AEF1457592ULL, 0x3FE34C5252C14DE3ULL,
|
||||
0x3FEB98FA1FD9155FULL, 0x3FE032AE55EDBD95ULL, 0xBFE032AE55EDBD94ULL, 0x3FEB98FA1FD9155FULL,
|
||||
0x3FD01F1806B9FDD1ULL, 0x3FEEF7D6E51CA3C0ULL, 0xBFEEF7D6E51CA3BFULL, 0x3FD01F1806B9FDD6ULL,
|
||||
0x3FEE3A33EC75CE85ULL, 0x3FD50163DC197047ULL, 0xBFD50163DC197048ULL, 0x3FEE3A33EC75CE85ULL,
|
||||
0x3FDBE51517FFC0D9ULL, 0x3FECCCEE20C2DEA0ULL, 0xBFECCCEE20C2DE9FULL, 0x3FDBE51517FFC0DAULL,
|
||||
0x3FE7E83F87B03686ULL, 0x3FE5454FF5159DFBULL, 0xBFE5454FF5159DFCULL, 0x3FE7E83F87B03686ULL,
|
||||
0x3FADD406F9808EC5ULL, 0x3FEFF21614E131EDULL, 0xBFEFF21614E131EDULL, 0x3FADD406F9808ECEULL,
|
||||
0x3FEFDF9922F73307ULL, 0x3FB6BF1B3E79B129ULL, 0xBFB6BF1B3E79B126ULL, 0x3FEFDF9922F73307ULL,
|
||||
0x3FE48703306091FFULL, 0x3FE88C66E7481BA1ULL, 0xBFE88C66E7481BA0ULL, 0x3FE48703306091FFULL,
|
||||
0x3FEC5BEF59FEF85AULL, 0x3FDDA60C5CFA10D8ULL, 0xBFDDA60C5CFA10D8ULL, 0x3FEC5BEF59FEF85AULL,
|
||||
0x3FD3241FB638BAAFULL, 0x3FEE89095BAD6025ULL, 0xBFEE89095BAD6024ULL, 0x3FD3241FB638BAB0ULL,
|
||||
0x3FEEB4CF515B8811ULL, 0x3FD2038583D727BDULL, 0xBFD2038583D727BDULL, 0x3FEEB4CF515B8811ULL,
|
||||
0x3FDEB00695F25620ULL, 0x3FEC14D9DC465E57ULL, 0xBFEC14D9DC465E56ULL, 0x3FDEB00695F25625ULL,
|
||||
0x3FE8EC109B486C49ULL, 0x3FE41272663D108CULL, 0xBFE41272663D108AULL, 0x3FE8EC109B486C4AULL,
|
||||
0x3FBB6FA6EC38F64EULL, 0x3FEFD0D158D86087ULL, 0xBFEFD0D158D86087ULL, 0x3FBB6FA6EC38F663ULL,
|
||||
0x3FEF70F6434B7EB7ULL, 0x3FC7D0A7BBD2CB1BULL, 0xBFC7D0A7BBD2CB16ULL, 0x3FEF70F6434B7EB7ULL,
|
||||
0x3FE205BAA17560D6ULL, 0x3FEA7138DE9D60F4ULL, 0xBFEA7138DE9D60F5ULL, 0x3FE205BAA17560D6ULL,
|
||||
0x3FEAC4FFBD3EFAC8ULL, 0x3FE188591F3A46E5ULL, 0xBFE188591F3A46E5ULL, 0x3FEAC4FFBD3EFAC8ULL,
|
||||
0x3FCA203E1B1831DFULL, 0x3FEF538B1FAF2D07ULL, 0xBFEF538B1FAF2D07ULL, 0x3FCA203E1B1831D9ULL,
|
||||
0x3FEDACF42CE68AB9ULL, 0x3FD7F24DD37341E3ULL, 0xBFD7F24DD37341E2ULL, 0x3FEDACF42CE68AB9ULL,
|
||||
0x3FD908EF81EF7BD3ULL, 0x3FED733F508C0DFEULL, 0xBFED733F508C0DFEULL, 0x3FD908EF81EF7BD4ULL,
|
||||
0x3FE6D5AFEF4AAFCDULL, 0x3FE66B0F3F52B386ULL, 0xBFE66B0F3F52B385ULL, 0x3FE6D5AFEF4AAFCEULL,
|
||||
0x3F82D96B0E509754ULL, 0x3FEFFFA72C978C4FULL, 0xBFEFFFA72C978C4FULL, 0x3F82D96B0E509777ULL,
|
||||
0x3FEFFFA72C978C4FULL, 0x3F82D96B0E509703ULL, 0xBF82D96B0E50970DULL, 0x3FEFFFA72C978C4FULL,
|
||||
0x3FE66B0F3F52B387ULL, 0x3FE6D5AFEF4AAFCCULL, 0xBFE6D5AFEF4AAFCDULL, 0x3FE66B0F3F52B386ULL,
|
||||
0x3FED733F508C0DFFULL, 0x3FD908EF81EF7BD1ULL, 0xBFD908EF81EF7BD1ULL, 0x3FED733F508C0DFFULL,
|
||||
0x3FD7F24DD37341E4ULL, 0x3FEDACF42CE68AB9ULL, 0xBFEDACF42CE68AB9ULL, 0x3FD7F24DD37341E5ULL,
|
||||
0x3FEF538B1FAF2D07ULL, 0x3FCA203E1B1831DAULL, 0xBFCA203E1B1831DBULL, 0x3FEF538B1FAF2D07ULL,
|
||||
0x3FE188591F3A46E5ULL, 0x3FEAC4FFBD3EFAC7ULL, 0xBFEAC4FFBD3EFAC7ULL, 0x3FE188591F3A46E7ULL,
|
||||
0x3FEA7138DE9D60F5ULL, 0x3FE205BAA17560D6ULL, 0xBFE205BAA17560D5ULL, 0x3FEA7138DE9D60F6ULL,
|
||||
0x3FC7D0A7BBD2CB1BULL, 0x3FEF70F6434B7EB7ULL, 0xBFEF70F6434B7EB7ULL, 0x3FC7D0A7BBD2CB25ULL,
|
||||
0x3FEFD0D158D86087ULL, 0x3FBB6FA6EC38F64CULL, 0xBFBB6FA6EC38F646ULL, 0x3FEFD0D158D86087ULL,
|
||||
0x3FE41272663D108DULL, 0x3FE8EC109B486C48ULL, 0xBFE8EC109B486C49ULL, 0x3FE41272663D108CULL,
|
||||
0x3FEC14D9DC465E58ULL, 0x3FDEB00695F25620ULL, 0xBFDEB00695F25622ULL, 0x3FEC14D9DC465E57ULL,
|
||||
0x3FD2038583D727BFULL, 0x3FEEB4CF515B8811ULL, 0xBFEEB4CF515B8811ULL, 0x3FD2038583D727BCULL,
|
||||
0x3FEE89095BAD6025ULL, 0x3FD3241FB638BAAFULL, 0xBFD3241FB638BAADULL, 0x3FEE89095BAD6025ULL,
|
||||
0x3FDDA60C5CFA10DAULL, 0x3FEC5BEF59FEF85AULL, 0xBFEC5BEF59FEF859ULL, 0x3FDDA60C5CFA10DBULL,
|
||||
0x3FE88C66E7481BA1ULL, 0x3FE48703306091FFULL, 0xBFE48703306091FEULL, 0x3FE88C66E7481BA2ULL,
|
||||
0x3FB6BF1B3E79B12FULL, 0x3FEFDF9922F73307ULL, 0xBFEFDF9922F73307ULL, 0x3FB6BF1B3E79B134ULL,
|
||||
0x3FEFF21614E131EDULL, 0x3FADD406F9808EC8ULL, 0xBFADD406F9808EB3ULL, 0x3FEFF21614E131EDULL,
|
||||
0x3FE5454FF5159DFCULL, 0x3FE7E83F87B03686ULL, 0xBFE7E83F87B03685ULL, 0x3FE5454FF5159DFDULL,
|
||||
0x3FECCCEE20C2DEA0ULL, 0x3FDBE51517FFC0D9ULL, 0xBFDBE51517FFC0D7ULL, 0x3FECCCEE20C2DEA0ULL,
|
||||
0x3FD50163DC19704AULL, 0x3FEE3A33EC75CE85ULL, 0xBFEE3A33EC75CE84ULL, 0x3FD50163DC19704BULL,
|
||||
0x3FEEF7D6E51CA3C0ULL, 0x3FD01F1806B9FDD2ULL, 0xBFD01F1806B9FDCFULL, 0x3FEEF7D6E51CA3C0ULL,
|
||||
0x3FE032AE55EDBD97ULL, 0x3FEB98FA1FD9155EULL, 0xBFEB98FA1FD9155EULL, 0x3FE032AE55EDBD95ULL,
|
||||
0x3FE986AEF1457594ULL, 0x3FE34C5252C14DE1ULL, 0xBFE34C5252C14DE2ULL, 0x3FE986AEF1457593ULL,
|
||||
0x3FC19D8940BE24ECULL, 0x3FEFB20DC681D54CULL, 0xBFEFB20DC681D54DULL, 0x3FC19D8940BE24E7ULL,
|
||||
0x3FEF9BED7CFBDE29ULL, 0x3FC3F22F57DB4893ULL, 0xBFC3F22F57DB4892ULL, 0x3FEF9BED7CFBDE29ULL,
|
||||
0x3FE2D333D34E9BB8ULL, 0x3FE9E082EDB42472ULL, 0xBFE9E082EDB42472ULL, 0x3FE2D333D34E9BB8ULL,
|
||||
0x3FEB4B7409DE7925ULL, 0x3FE0B405878F85ECULL, 0xBFE0B405878F85EBULL, 0x3FEB4B7409DE7926ULL,
|
||||
0x3FCDF5163F01099BULL, 0x3FEF1C7ABE284708ULL, 0xBFEF1C7ABE284708ULL, 0x3FCDF5163F01099DULL,
|
||||
0x3FEE0766D9280F54ULL, 0x3FD61D595C88C203ULL, 0xBFD61D595C88C202ULL, 0x3FEE0766D9280F55ULL,
|
||||
0x3FDAD473125CDC09ULL, 0x3FED0D672F59D2B8ULL, 0xBFED0D672F59D2B7ULL, 0x3FDAD473125CDC0EULL,
|
||||
0x3FE782FB1B90B35BULL, 0x3FE5B50B264F7448ULL, 0xBFE5B50B264F7446ULL, 0x3FE782FB1B90B35CULL,
|
||||
0x3FA46A396FF8617EULL, 0x3FEFF97C4208C014ULL, 0xBFEFF97C4208C014ULL, 0x3FA46A396FF861A7ULL,
|
||||
0x3FEFFB55E425FDAEULL, 0x3FA14685DB42C17EULL, 0xBFA14685DB42C175ULL, 0x3FEFFB55E425FDAEULL,
|
||||
0x3FE5D9DEE73E345CULL, 0x3FE760C52C304764ULL, 0xBFE760C52C304763ULL, 0x3FE5D9DEE73E345DULL,
|
||||
0x3FED2255C6E5A4E1ULL, 0x3FDA790CD3DBF31AULL, 0xBFDA790CD3DBF319ULL, 0x3FED2255C6E5A4E1ULL,
|
||||
0x3FD67B949CAD63CBULL, 0x3FEDF5E36A9BA59CULL, 0xBFEDF5E36A9BA59CULL, 0x3FD67B949CAD63CCULL,
|
||||
0x3FEF2817FC4609CEULL, 0x3FCD31774D2CBDEEULL, 0xBFCD31774D2CBDECULL, 0x3FEF2817FC4609CEULL,
|
||||
0x3FE0DED0B84BC4B6ULL, 0x3FEB3115A5F37BF3ULL, 0xBFEB3115A5F37BF4ULL, 0x3FE0DED0B84BC4B5ULL,
|
||||
0x3FE9FDF4F13149DEULL, 0x3FE2AA76E87AEB58ULL, 0xBFE2AA76E87AEB59ULL, 0x3FE9FDF4F13149DEULL,
|
||||
0x3FC4B8B17F79FA8AULL, 0x3FEF93F14F85AC07ULL, 0xBFEF93F14F85AC08ULL, 0x3FC4B8B17F79FA85ULL,
|
||||
0x3FEFB8D18D66ADB7ULL, 0x3FC0D64DBCB26786ULL, 0xBFC0D64DBCB26787ULL, 0x3FEFB8D18D66ADB7ULL,
|
||||
0x3FE374531B817F8EULL, 0x3FE9683F42BD7FE1ULL, 0xBFE9683F42BD7FE1ULL, 0x3FE374531B817F8DULL,
|
||||
0x3FEBB249A0B6C40DULL, 0x3FE00740C82B82E0ULL, 0xBFE00740C82B82E1ULL, 0x3FEBB249A0B6C40DULL,
|
||||
0x3FD0804E05EB661DULL, 0x3FEEEB074C50A545ULL, 0xBFEEEB074C50A544ULL, 0x3FD0804E05EB661EULL,
|
||||
0x3FEE4A8DFF81CE5EULL, 0x3FD4A253D11B82F3ULL, 0xBFD4A253D11B82F3ULL, 0x3FEE4A8DFF81CE5EULL,
|
||||
0x3FDC3F6D47263128ULL, 0x3FECB6E20A00DA99ULL, 0xBFECB6E20A00DA98ULL, 0x3FDC3F6D4726312DULL,
|
||||
0x3FE8098B756E52FBULL, 0x3FE51FA81CD99AA6ULL, 0xBFE51FA81CD99AA5ULL, 0x3FE8098B756E52FCULL,
|
||||
0x3FB07B614E463060ULL, 0x3FEFEF0102826191ULL, 0xBFEFEF0102826191ULL, 0x3FB07B614E463075ULL,
|
||||
0x3FEFE3E92BE9D886ULL, 0x3FB52E774A4D4D0AULL, 0xBFB52E774A4D4D09ULL, 0x3FEFE3E92BE9D886ULL,
|
||||
0x3FE4AD79516722F1ULL, 0x3FE86C0A1D9AA195ULL, 0xBFE86C0A1D9AA193ULL, 0x3FE4AD79516722F3ULL,
|
||||
0x3FEC7315899EAAD7ULL, 0x3FDD4CD02BA8609CULL, 0xBFDD4CD02BA86099ULL, 0x3FEC7315899EAAD8ULL,
|
||||
0x3FD383F5E353B6ABULL, 0x3FEE79DB29A5165AULL, 0xBFEE79DB29A51659ULL, 0x3FD383F5E353B6AFULL,
|
||||
0x3FEEC2CF4B1AF6B2ULL, 0x3FD1A2F7FBE8F243ULL, 0xBFD1A2F7FBE8F243ULL, 0x3FEEC2CF4B1AF6B2ULL,
|
||||
0x3FDF081906BFF7FEULL, 0x3FEBFC9D25A1B147ULL, 0xBFEBFC9D25A1B147ULL, 0x3FDF081906BFF7FEULL,
|
||||
0x3FE90B7943575EFEULL, 0x3FE3EB33EABE0680ULL, 0xBFE3EB33EABE0680ULL, 0x3FE90B7943575EFEULL,
|
||||
0x3FBCFF533B307DC2ULL, 0x3FEFCB4703914354ULL, 0xBFEFCB4703914354ULL, 0x3FBCFF533B307DC6ULL,
|
||||
0x3FEF7A299C1A322AULL, 0x3FC70AFD8D08C4FFULL, 0xBFC70AFD8D08C4FBULL, 0x3FEF7A299C1A322AULL,
|
||||
0x3FE22F2D662C13E1ULL, 0x3FEA54C91090F523ULL, 0xBFEA54C91090F522ULL, 0x3FE22F2D662C13E3ULL,
|
||||
0x3FEAE068F345ECEFULL, 0x3FE15E36E4DBE2BCULL, 0xBFE15E36E4DBE2BBULL, 0x3FEAE068F345ECF0ULL,
|
||||
0x3FCAE4F1D5F3B9AFULL, 0x3FEF492206BCABB4ULL, 0xBFEF492206BCABB4ULL, 0x3FCAE4F1D5F3B9B2ULL,
|
||||
0x3FEDBF9E4395759BULL, 0x3FD794F5E613DFAEULL, 0xBFD794F5E613DFACULL, 0x3FEDBF9E4395759BULL,
|
||||
0x3FD96555B7AB9491ULL, 0x3FED5F7172888A7EULL, 0xBFED5F7172888A7FULL, 0x3FD96555B7AB948EULL,
|
||||
0x3FE6F8CA99C95B75ULL, 0x3FE64715437F535BULL, 0xBFE64715437F535BULL, 0x3FE6F8CA99C95B75ULL,
|
||||
0x3F8F6A296AB9980FULL, 0x3FEFFF0943C53BD1ULL, 0xBFEFFF0943C53BD1ULL, 0x3F8F6A296AB997B3ULL,
|
||||
0x3FEFFE1C6870CB77ULL, 0x3F95FD4D21FAB226ULL, 0xBF95FD4D21FAB21FULL, 0x3FEFFE1C6870CB77ULL,
|
||||
0x3FE622E44FEC22FFULL, 0x3FE71BAC960E41BFULL, 0xBFE71BAC960E41BEULL, 0x3FE622E44FEC2300ULL,
|
||||
0x3FED4B5B1B187524ULL, 0x3FD9C17D440DF9F2ULL, 0xBFD9C17D440DF9F2ULL, 0x3FED4B5B1B187524ULL,
|
||||
0x3FD73763C9261092ULL, 0x3FEDD1FEF38A915AULL, 0xBFEDD1FEF38A9159ULL, 0x3FD73763C9261093ULL,
|
||||
0x3FEF3E6BBC1BBC65ULL, 0x3FCBA96334F15DADULL, 0xBFCBA96334F15DACULL, 0x3FEF3E6BBC1BBC65ULL,
|
||||
0x3FE133E9CFEE254FULL, 0x3FEAFB8FD89F57B6ULL, 0xBFEAFB8FD89F57B5ULL, 0x3FE133E9CFEE2551ULL,
|
||||
0x3FEA38184A593BC5ULL, 0x3FE258734CBB7110ULL, 0xBFE258734CBB710EULL, 0x3FEA38184A593BC7ULL,
|
||||
0x3FC6451A831D830EULL, 0x3FEF830F4A40C60CULL, 0xBFEF830F4A40C60CULL, 0x3FC6451A831D8318ULL,
|
||||
0x3FEFC56E3B7D9AF6ULL, 0x3FBE8EB7FDE4AA3EULL, 0xBFBE8EB7FDE4AA35ULL, 0x3FEFC56E3B7D9AF6ULL,
|
||||
0x3FE3C3C44981C518ULL, 0x3FE92AA41FC5A815ULL, 0xBFE92AA41FC5A815ULL, 0x3FE3C3C44981C517ULL,
|
||||
0x3FEBE41B611154C0ULL, 0x3FDF5FDEE656CDA3ULL, 0xBFDF5FDEE656CDA4ULL, 0x3FEBE41B611154C0ULL,
|
||||
0x3FD1423EEFC6937AULL, 0x3FEED0835E999009ULL, 0xBFEED0835E999009ULL, 0x3FD1423EEFC69378ULL,
|
||||
0x3FEE6A61C55D53A7ULL, 0x3FD3E39BE96EC271ULL, 0xBFD3E39BE96EC26FULL, 0x3FEE6A61C55D53A8ULL,
|
||||
0x3FDCF34BAEE1CD23ULL, 0x3FEC89F587029C13ULL, 0xBFEC89F587029C12ULL, 0x3FDCF34BAEE1CD24ULL,
|
||||
0x3FE84B7111AF83FAULL, 0x3FE4D3BC6D589F7FULL, 0xBFE4D3BC6D589F7EULL, 0x3FE84B7111AF83FBULL,
|
||||
0x3FB39D9F12C5A2A2ULL, 0x3FEFE7EA85482D60ULL, 0xBFEFE7EA85482D60ULL, 0x3FB39D9F12C5A2A7ULL,
|
||||
0x3FEFEB9D2530410FULL, 0x3FB20C9674ED444CULL, 0xBFB20C9674ED444FULL, 0x3FEFEB9D2530410FULL,
|
||||
0x3FE4F9CC25CCA487ULL, 0x3FE82A9C13F545FFULL, 0xBFE82A9C13F545FEULL, 0x3FE4F9CC25CCA488ULL,
|
||||
0x3FECA08F19B9C449ULL, 0x3FDC997FC3865388ULL, 0xBFDC997FC3865385ULL, 0x3FECA08F19B9C44AULL,
|
||||
0x3FD44310DC8936F0ULL, 0x3FEE5A9D550467D3ULL, 0xBFEE5A9D550467D3ULL, 0x3FD44310DC8936F4ULL,
|
||||
0x3FEEDDEB6A078651ULL, 0x3FD0E15B4E1749CDULL, 0xBFD0E15B4E1749CEULL, 0x3FEEDDEB6A078651ULL,
|
||||
0x3FDFB7575C24D2DDULL, 0x3FEBCB54CB0D2327ULL, 0xBFEBCB54CB0D2327ULL, 0x3FDFB7575C24D2DEULL,
|
||||
0x3FE94990E3AC4A6CULL, 0x3FE39C23E3D63029ULL, 0xBFE39C23E3D63029ULL, 0x3FE94990E3AC4A6CULL,
|
||||
0x3FC00EE8AD6FB85AULL, 0x3FEFBF470F0A8D88ULL, 0xBFEFBF470F0A8D88ULL, 0x3FC00EE8AD6FB85CULL,
|
||||
0x3FEF8BA737CB4B78ULL, 0x3FC57F008654CBDEULL, 0xBFC57F008654CBDBULL, 0x3FEF8BA737CB4B78ULL,
|
||||
0x3FE2818BEF4D3CBAULL, 0x3FEA1B26D2C0A75EULL, 0xBFEA1B26D2C0A75DULL, 0x3FE2818BEF4D3CBBULL,
|
||||
0x3FEB16742A4CA2F5ULL, 0x3FE1097248D0A956ULL, 0xBFE1097248D0A956ULL, 0x3FEB16742A4CA2F5ULL,
|
||||
0x3FCC6D90535D74DFULL, 0x3FEF33685A3AAEF0ULL, 0xBFEF33685A3AAEF0ULL, 0x3FCC6D90535D74E1ULL,
|
||||
0x3FEDE4160F6D8D82ULL, 0x3FD6D998638A0CB5ULL, 0xBFD6D998638A0CB4ULL, 0x3FEDE4160F6D8D82ULL,
|
||||
0x3FDA1D6543B50AC1ULL, 0x3FED36FC7BCBFBDBULL, 0xBFED36FC7BCBFBDCULL, 0x3FDA1D6543B50ABEULL,
|
||||
0x3FE73E558E079942ULL, 0x3FE5FE7CBDE56A0FULL, 0xBFE5FE7CBDE56A10ULL, 0x3FE73E558E079941ULL,
|
||||
0x3F9C454F4CE53B33ULL, 0x3FEFFCE09CE2A679ULL, 0xBFEFFCE09CE2A679ULL, 0x3F9C454F4CE53B05ULL,
|
||||
0x3FEFF753BB1B9164ULL, 0x3FA78DBAA5874685ULL, 0xBFA78DBAA5874676ULL, 0x3FEFF753BB1B9164ULL,
|
||||
0x3FE59001D5F723E0ULL, 0x3FE7A4F707BF97D2ULL, 0xBFE7A4F707BF97D1ULL, 0x3FE59001D5F723E0ULL,
|
||||
0x3FECF830E8CE467BULL, 0x3FDB2F971DB31972ULL, 0xBFDB2F971DB31970ULL, 0x3FECF830E8CE467BULL,
|
||||
0x3FD5BEE78B9DB3B8ULL, 0x3FEE18A02FDC66D9ULL, 0xBFEE18A02FDC66D9ULL, 0x3FD5BEE78B9DB3B9ULL,
|
||||
0x3FEF1090BC898F5FULL, 0x3FCEB86B462DE348ULL, 0xBFCEB86B462DE344ULL, 0x3FEF1090BC898F5FULL,
|
||||
0x3FE089112032B08DULL, 0x3FEB658F14FDBC47ULL, 0xBFEB658F14FDBC47ULL, 0x3FE089112032B08BULL,
|
||||
0x3FE9C2D110F075C3ULL, 0x3FE2FBC24B441015ULL, 0xBFE2FBC24B441016ULL, 0x3FE9C2D110F075C2ULL,
|
||||
0x3FC32B7BF94516ABULL, 0x3FEFA39BAC7A1791ULL, 0xBFEFA39BAC7A1791ULL, 0x3FC32B7BF94516A5ULL,
|
||||
0x3FEFAAFBCB0CFDDCULL, 0x3FC264994DFD340AULL, 0xBFC264994DFD3409ULL, 0x3FEFAAFBCB0CFDDCULL,
|
||||
0x3FE32421EC49A620ULL, 0x3FE9A4DFA42B06B1ULL, 0xBFE9A4DFA42B06B2ULL, 0x3FE32421EC49A620ULL,
|
||||
0x3FEB7F6686E792EAULL, 0x3FE05DF3EC31B8B6ULL, 0xBFE05DF3EC31B8B7ULL, 0x3FEB7F6686E792E9ULL,
|
||||
0x3FCF7B7480BD3801ULL, 0x3FEF045A14CF738CULL, 0xBFEF045A14CF738BULL, 0x3FCF7B7480BD3803ULL,
|
||||
0x3FEE298F4439197AULL, 0x3FD5604012F467B4ULL, 0xBFD5604012F467B4ULL, 0x3FEE298F4439197AULL,
|
||||
0x3FDB8A7814FD5693ULL, 0x3FECE2B32799A060ULL, 0xBFECE2B32799A05FULL, 0x3FDB8A7814FD5698ULL,
|
||||
0x3FE7C6B89CE2D333ULL, 0x3FE56AC35197649EULL, 0xBFE56AC35197649DULL, 0x3FE7C6B89CE2D334ULL,
|
||||
0x3FAAB101BD5F8316ULL, 0x3FEFF4DC54B1BED3ULL, 0xBFEFF4DC54B1BED2ULL, 0x3FAAB101BD5F833EULL,
|
||||
0x3FEFDAFA7514538CULL, 0x3FB84F8712C130A0ULL, 0xBFB84F8712C1309DULL, 0x3FEFDAFA7514538CULL,
|
||||
0x3FE4605A692B32A2ULL, 0x3FE8AC871EDE1D87ULL, 0xBFE8AC871EDE1D86ULL, 0x3FE4605A692B32A4ULL,
|
||||
0x3FEC44833141C004ULL, 0x3FDDFEFF66A941DDULL, 0xBFDDFEFF66A941D9ULL, 0x3FEC44833141C005ULL,
|
||||
0x3FD2C41A4E954521ULL, 0x3FEE97EC36016B30ULL, 0xBFEE97EC36016B2FULL, 0x3FD2C41A4E954526ULL,
|
||||
0x3FEEA68393E65800ULL, 0x3FD263E6995554BAULL, 0xBFD263E6995554B9ULL, 0x3FEEA68393E65800ULL,
|
||||
0x3FDE57A86D3CD825ULL, 0x3FEC2CD14931E3F1ULL, 0xBFEC2CD14931E3F1ULL, 0x3FDE57A86D3CD826ULL,
|
||||
0x3FE8CC6A75184655ULL, 0x3FE4397F5B2A4380ULL, 0xBFE4397F5B2A437FULL, 0x3FE8CC6A75184655ULL,
|
||||
0x3FB9DFB6EB24A860ULL, 0x3FEFD60D2DA75C9EULL, 0xBFEFD60D2DA75C9EULL, 0x3FB9DFB6EB24A864ULL,
|
||||
0x3FEF677556883CEEULL, 0x3FC8961727C41804ULL, 0xBFC8961727C417FEULL, 0x3FEF677556883CEEULL,
|
||||
0x3FE1DC1B64DC4872ULL, 0x3FEA8D676E545AD2ULL, 0xBFEA8D676E545AD1ULL, 0x3FE1DC1B64DC4874ULL,
|
||||
0x3FEAA9547A2CB98EULL, 0x3FE1B250171373BEULL, 0xBFE1B250171373BDULL, 0x3FEAA9547A2CB98FULL,
|
||||
0x3FC95B49E9B62AFFULL, 0x3FEF5DA6ED43685CULL, 0xBFEF5DA6ED43685CULL, 0x3FC95B49E9B62B02ULL,
|
||||
0x3FED9A00DD8B3D46ULL, 0x3FD84F6AAAF3903FULL, 0xBFD84F6AAAF3903CULL, 0x3FED9A00DD8B3D47ULL,
|
||||
0x3FD8AC4B86D5ED47ULL, 0x3FED86C48445A44FULL, 0xBFED86C48445A450ULL, 0x3FD8AC4B86D5ED44ULL,
|
||||
0x3FE6B25CED2FE29CULL, 0x3FE68ED1EAA19C71ULL, 0xBFE68ED1EAA19C71ULL, 0x3FE6B25CED2FE29BULL,
|
||||
0x3F6921F8BECCA62FULL, 0x3FEFFFF621621D02ULL, 0xBFEFFFF621621D02ULL, 0x3F6921F8BECCA4BCULL,
|
||||
};
|
||||
|
||||
#if !defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
/* When the AVX2 backend is selected, falcon_FFT/falcon_iFFT are provided by
|
||||
* wc_falcon_fft_avx2.c instead; the twiddle table above is still shared. */
|
||||
|
||||
/* In-place forward FFT: coefficient representation -> FFT representation. */
|
||||
void falcon_FFT(fpr* f, unsigned logn)
|
||||
{
|
||||
unsigned u;
|
||||
size_t t, n, hn, m;
|
||||
|
||||
n = (size_t)1 << logn;
|
||||
hn = n >> 1;
|
||||
t = hn;
|
||||
for (u = 1, m = 2; u < logn; u++, m <<= 1) {
|
||||
size_t ht = t >> 1, hm = m >> 1, i1, j1;
|
||||
for (i1 = 0, j1 = 0; i1 < hm; i1++, j1 += t) {
|
||||
size_t j, j2 = j1 + ht;
|
||||
fpr s_re = falcon_gm_tab[((m + i1) << 1) + 0];
|
||||
fpr s_im = falcon_gm_tab[((m + i1) << 1) + 1];
|
||||
for (j = j1; j < j2; j++) {
|
||||
fpr x_re = f[j], x_im = f[j + hn];
|
||||
fpr y_re = f[j + ht], y_im = f[j + ht + hn];
|
||||
FPC_MUL(y_re, y_im, y_re, y_im, s_re, s_im);
|
||||
FPC_ADD(f[j], f[j + hn], x_re, x_im, y_re, y_im);
|
||||
FPC_SUB(f[j + ht], f[j + ht + hn], x_re, x_im, y_re, y_im);
|
||||
}
|
||||
}
|
||||
t = ht;
|
||||
}
|
||||
}
|
||||
|
||||
/* In-place inverse FFT: exact reversal of falcon_FFT, then scale by 2^-(logn-1).
|
||||
* Each inverse butterfly is (a+b) and (a-b)*conj(s). */
|
||||
void falcon_iFFT(fpr* f, unsigned logn)
|
||||
{
|
||||
int u;
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1;
|
||||
|
||||
for (u = (int)logn - 1; u >= 1; u--) {
|
||||
size_t m = (size_t)1 << u, hm = m >> 1;
|
||||
size_t t = hn >> u; /* butterfly stride */
|
||||
size_t i1, j1;
|
||||
for (i1 = 0, j1 = 0; i1 < hm; i1++, j1 += (t << 1)) {
|
||||
size_t j, j2 = j1 + t;
|
||||
fpr s_re = falcon_gm_tab[((m + i1) << 1) + 0];
|
||||
fpr s_im = fpr_neg(falcon_gm_tab[((m + i1) << 1) + 1]);
|
||||
for (j = j1; j < j2; j++) {
|
||||
fpr a_re = f[j], a_im = f[j + hn];
|
||||
fpr b_re = f[j + t], b_im = f[j + t + hn];
|
||||
fpr d_re, d_im;
|
||||
FPC_ADD(f[j], f[j + hn], a_re, a_im, b_re, b_im);
|
||||
FPC_SUB(d_re, d_im, a_re, a_im, b_re, b_im);
|
||||
FPC_MUL(f[j + t], f[j + t + hn], d_re, d_im, s_re, s_im);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
fpr ni = fpr_inv(fpr_of((sword64)hn)); /* 1 / 2^(logn-1) (exact) */
|
||||
size_t j;
|
||||
for (j = 0; j < n; j++) {
|
||||
f[j] = fpr_mul(f[j], ni);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !WOLFSSL_FALCON_FFT_AVX2 */
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
@@ -0,0 +1,647 @@
|
||||
/* wc_falcon_fft_avx2.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* AVX2 (__m256d + FMA) FFT backend for the native FN-DSA / Falcon signing path.
|
||||
*
|
||||
* This is a vectorization of the scalar FFT in wc_falcon_fft.c and the hot
|
||||
* FFT-domain pointwise polynomial operations in wc_falcon_poly.c. It processes
|
||||
* 4 doubles per 256-bit vector and uses fused multiply-add for the complex
|
||||
* butterflies. The algorithm and twiddle-table (falcon_gm_tab) layout are
|
||||
* unchanged from the scalar backend; only the butterfly inner loops (and the
|
||||
* pointwise poly ops) are widened.
|
||||
*
|
||||
* Representation (see wc_falcon_fft.h): a degree-n real polynomial is carried as
|
||||
* n fpr (= IEEE-754 bit patterns in a word64) = n/2 complex evaluations; real
|
||||
* parts live in [0, n/2), imaginary parts in [n/2, n). Because an fpr IS the
|
||||
* bit pattern of a double, the fpr arrays are loaded directly with
|
||||
* _mm256_loadu_pd((const double*)ptr).
|
||||
*
|
||||
* CORRECTNESS NOTE: unlike the rest of the fpr seam, this backend does NOT
|
||||
* promise bit-identical (round-to-nearest-even, no-FMA) results. FMA fuses the
|
||||
* multiply-add with a single rounding, so the FFT output differs in the last
|
||||
* ULPs from the scalar backend. This is intentional and safe: the signing FFT
|
||||
* only needs to produce a short vector that passes the norm bound and verifies;
|
||||
* it is never required to be reproducible against the scalar path. The Gaussian
|
||||
* sampler's determinism depends only on the fpr_* scalar ops (unchanged), and
|
||||
* verification is integer-only and unaffected.
|
||||
*
|
||||
* TARGET ISA: every externally-visible function and every intrinsic helper is
|
||||
* annotated with __attribute__((target("avx2,fma"))) on GCC/Clang, so the TU
|
||||
* compiles and runs correctly even when the surrounding build uses only a
|
||||
* baseline (e.g. SSE2) -march. The annotation is harmless if the build ALSO
|
||||
* passes -mavx2 -mfma per file. On compilers without the target attribute
|
||||
* (e.g. MSVC) the TU must be compiled with the appropriate /arch:AVX2 flag.
|
||||
*/
|
||||
|
||||
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY) && \
|
||||
defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_fft.h>
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_poly.h>
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define FALCON_AVX2_TARGET __attribute__((target("avx2,fma")))
|
||||
#else
|
||||
#define FALCON_AVX2_TARGET
|
||||
#endif
|
||||
|
||||
/* Reinterpret an fpr (word64 bit pattern) as a double without aliasing UB:
|
||||
* the fpr arrays are word64 but hold IEEE-754 doubles, so a value-preserving
|
||||
* load through (const double*) is what the SIMD path needs. */
|
||||
static WC_INLINE double falcon_avx2_d(fpr x)
|
||||
{
|
||||
double d;
|
||||
XMEMCPY(&d, &x, sizeof(d));
|
||||
return d;
|
||||
}
|
||||
|
||||
/* Scalar (inline-double) complex helpers for the small-stride tail levels.
|
||||
* These match the scalar backend exactly (no FMA) for the few coefficients
|
||||
* where SIMD would not pay off. */
|
||||
#define FPC_MUL(d_re, d_im, a_re, a_im, b_re, b_im) do { \
|
||||
fpr _ar = (a_re), _ai = (a_im), _br = (b_re), _bi = (b_im); \
|
||||
(d_re) = fpr_sub(fpr_mul(_ar, _br), fpr_mul(_ai, _bi)); \
|
||||
(d_im) = fpr_add(fpr_mul(_ar, _bi), fpr_mul(_ai, _br)); \
|
||||
} while (0)
|
||||
#define FPC_ADD(d_re, d_im, a_re, a_im, b_re, b_im) do { \
|
||||
(d_re) = fpr_add((a_re), (b_re)); \
|
||||
(d_im) = fpr_add((a_im), (b_im)); \
|
||||
} while (0)
|
||||
#define FPC_SUB(d_re, d_im, a_re, a_im, b_re, b_im) do { \
|
||||
(d_re) = fpr_sub((a_re), (b_re)); \
|
||||
(d_im) = fpr_sub((a_im), (b_im)); \
|
||||
} while (0)
|
||||
|
||||
/* Vector complex multiply: (yr + i yi) <- (yr + i yi) * (sr + i si).
|
||||
* Uses FMA: re = yr*sr - yi*si, im = yr*si + yi*sr. */
|
||||
#define FALCON_VCMUL(out_re, out_im, yr, yi, sr, si) do { \
|
||||
__m256d _t0 = _mm256_mul_pd((yi), (si)); \
|
||||
__m256d _t1 = _mm256_mul_pd((yi), (sr)); \
|
||||
(out_re) = _mm256_fmsub_pd((yr), (sr), _t0); \
|
||||
(out_im) = _mm256_fmadd_pd((yr), (si), _t1); \
|
||||
} while (0)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Forward FFT */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_FFT(fpr* f, unsigned logn)
|
||||
{
|
||||
double* fd = (double*)f;
|
||||
unsigned u;
|
||||
size_t t, n, hn, m;
|
||||
|
||||
n = (size_t)1 << logn;
|
||||
hn = n >> 1;
|
||||
t = hn;
|
||||
for (u = 1, m = 2; u < logn; u++, m <<= 1) {
|
||||
size_t ht = t >> 1, hm = m >> 1, i1, j1;
|
||||
for (i1 = 0, j1 = 0; i1 < hm; i1++, j1 += t) {
|
||||
size_t j, j2 = j1 + ht;
|
||||
fpr s_re = falcon_gm_tab[((m + i1) << 1) + 0];
|
||||
fpr s_im = falcon_gm_tab[((m + i1) << 1) + 1];
|
||||
if (ht >= 4) {
|
||||
__m256d vsr = _mm256_set1_pd(falcon_avx2_d(s_re));
|
||||
__m256d vsi = _mm256_set1_pd(falcon_avx2_d(s_im));
|
||||
for (j = j1; j < j2; j += 4) {
|
||||
__m256d xr = _mm256_loadu_pd(fd + j);
|
||||
__m256d xi = _mm256_loadu_pd(fd + j + hn);
|
||||
__m256d yr = _mm256_loadu_pd(fd + j + ht);
|
||||
__m256d yi = _mm256_loadu_pd(fd + j + ht + hn);
|
||||
__m256d tr, ti;
|
||||
FALCON_VCMUL(tr, ti, yr, yi, vsr, vsi);
|
||||
_mm256_storeu_pd(fd + j, _mm256_add_pd(xr, tr));
|
||||
_mm256_storeu_pd(fd + j + hn, _mm256_add_pd(xi, ti));
|
||||
_mm256_storeu_pd(fd + j + ht, _mm256_sub_pd(xr, tr));
|
||||
_mm256_storeu_pd(fd + j + ht + hn, _mm256_sub_pd(xi, ti));
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* small-stride tail (ht == 1 or 2): scalar inline-double */
|
||||
for (j = j1; j < j2; j++) {
|
||||
fpr x_re = f[j], x_im = f[j + hn];
|
||||
fpr y_re = f[j + ht], y_im = f[j + ht + hn];
|
||||
FPC_MUL(y_re, y_im, y_re, y_im, s_re, s_im);
|
||||
FPC_ADD(f[j], f[j + hn], x_re, x_im, y_re, y_im);
|
||||
FPC_SUB(f[j + ht], f[j + ht + hn], x_re, x_im, y_re, y_im);
|
||||
}
|
||||
}
|
||||
}
|
||||
t = ht;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Inverse FFT */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_iFFT(fpr* f, unsigned logn)
|
||||
{
|
||||
double* fd = (double*)f;
|
||||
int u;
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1;
|
||||
|
||||
for (u = (int)logn - 1; u >= 1; u--) {
|
||||
size_t m = (size_t)1 << u, hm = m >> 1;
|
||||
size_t t = hn >> u; /* butterfly stride */
|
||||
size_t i1, j1;
|
||||
for (i1 = 0, j1 = 0; i1 < hm; i1++, j1 += (t << 1)) {
|
||||
size_t j, j2 = j1 + t;
|
||||
fpr s_re = falcon_gm_tab[((m + i1) << 1) + 0];
|
||||
fpr s_im = fpr_neg(falcon_gm_tab[((m + i1) << 1) + 1]);
|
||||
if (t >= 4) {
|
||||
__m256d vsr = _mm256_set1_pd(falcon_avx2_d(s_re));
|
||||
__m256d vsi = _mm256_set1_pd(falcon_avx2_d(s_im));
|
||||
for (j = j1; j < j2; j += 4) {
|
||||
__m256d ar = _mm256_loadu_pd(fd + j);
|
||||
__m256d ai = _mm256_loadu_pd(fd + j + hn);
|
||||
__m256d br = _mm256_loadu_pd(fd + j + t);
|
||||
__m256d bi = _mm256_loadu_pd(fd + j + t + hn);
|
||||
__m256d dr = _mm256_sub_pd(ar, br);
|
||||
__m256d di = _mm256_sub_pd(ai, bi);
|
||||
__m256d pr, pi;
|
||||
_mm256_storeu_pd(fd + j, _mm256_add_pd(ar, br));
|
||||
_mm256_storeu_pd(fd + j + hn, _mm256_add_pd(ai, bi));
|
||||
FALCON_VCMUL(pr, pi, dr, di, vsr, vsi);
|
||||
_mm256_storeu_pd(fd + j + t, pr);
|
||||
_mm256_storeu_pd(fd + j + t + hn, pi);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (j = j1; j < j2; j++) {
|
||||
fpr a_re = f[j], a_im = f[j + hn];
|
||||
fpr b_re = f[j + t], b_im = f[j + t + hn];
|
||||
fpr d_re, d_im;
|
||||
FPC_ADD(f[j], f[j + hn], a_re, a_im, b_re, b_im);
|
||||
FPC_SUB(d_re, d_im, a_re, a_im, b_re, b_im);
|
||||
FPC_MUL(f[j + t], f[j + t + hn], d_re, d_im, s_re, s_im);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* final scale by 1 / 2^(logn-1) */
|
||||
{
|
||||
fpr ni = fpr_inv(fpr_of((sword64)hn));
|
||||
if (n >= 4) {
|
||||
__m256d vni = _mm256_set1_pd(falcon_avx2_d(ni));
|
||||
size_t j;
|
||||
for (j = 0; j < n; j += 4) {
|
||||
_mm256_storeu_pd(fd + j,
|
||||
_mm256_mul_pd(_mm256_loadu_pd(fd + j), vni));
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t j;
|
||||
for (j = 0; j < n; j++) {
|
||||
f[j] = fpr_mul(f[j], ni);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* FFT-domain pointwise polynomial operations (hot in signing) */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* a <- a * b (pointwise complex product) over [0, hn). */
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_poly_mul_fft_avx2(fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
double* ad = (double*)a;
|
||||
const double* bd = (const double*)b;
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
|
||||
if (hn >= 4) {
|
||||
for (u = 0; u < hn; u += 4) {
|
||||
__m256d ar = _mm256_loadu_pd(ad + u);
|
||||
__m256d ai = _mm256_loadu_pd(ad + u + hn);
|
||||
__m256d br = _mm256_loadu_pd(bd + u);
|
||||
__m256d bi = _mm256_loadu_pd(bd + u + hn);
|
||||
__m256d t0 = _mm256_mul_pd(ai, bi);
|
||||
__m256d t1 = _mm256_mul_pd(ai, br);
|
||||
__m256d re = _mm256_fmsub_pd(ar, br, t0); /* ar*br - ai*bi */
|
||||
__m256d im = _mm256_fmadd_pd(ar, bi, t1); /* ar*bi + ai*br */
|
||||
_mm256_storeu_pd(ad + u, re);
|
||||
_mm256_storeu_pd(ad + u + hn, im);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr a_re = a[u], a_im = a[u + hn];
|
||||
fpr b_re = b[u], b_im = b[u + hn];
|
||||
FPC_MUL(a[u], a[u + hn], a_re, a_im, b_re, b_im);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* a <- a + b over [0, n). */
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_poly_add_avx2(fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
double* ad = (double*)a;
|
||||
const double* bd = (const double*)b;
|
||||
size_t n = (size_t)1 << logn, u;
|
||||
|
||||
if (n >= 4) {
|
||||
for (u = 0; u < n; u += 4) {
|
||||
_mm256_storeu_pd(ad + u,
|
||||
_mm256_add_pd(_mm256_loadu_pd(ad + u), _mm256_loadu_pd(bd + u)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (u = 0; u < n; u++) {
|
||||
a[u] = fpr_add(a[u], b[u]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* a <- a - b over [0, n). */
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_poly_sub_avx2(fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
double* ad = (double*)a;
|
||||
const double* bd = (const double*)b;
|
||||
size_t n = (size_t)1 << logn, u;
|
||||
|
||||
if (n >= 4) {
|
||||
for (u = 0; u < n; u += 4) {
|
||||
_mm256_storeu_pd(ad + u,
|
||||
_mm256_sub_pd(_mm256_loadu_pd(ad + u), _mm256_loadu_pd(bd + u)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (u = 0; u < n; u++) {
|
||||
a[u] = fpr_sub(a[u], b[u]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* a <- a * x (scalar fpr constant) over [0, n). */
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_poly_mulconst_avx2(fpr* a, fpr x, unsigned logn)
|
||||
{
|
||||
double* ad = (double*)a;
|
||||
size_t n = (size_t)1 << logn, u;
|
||||
|
||||
if (n >= 4) {
|
||||
__m256d vx = _mm256_set1_pd(falcon_avx2_d(x));
|
||||
for (u = 0; u < n; u += 4) {
|
||||
_mm256_storeu_pd(ad + u, _mm256_mul_pd(_mm256_loadu_pd(ad + u), vx));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (u = 0; u < n; u++) {
|
||||
a[u] = fpr_mul(a[u], x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* a <- a * adj(b): pointwise a * conj(b) over [0, hn). */
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_poly_muladj_fft_avx2(fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
double* ad = (double*)a;
|
||||
const double* bd = (const double*)b;
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
|
||||
if (hn >= 4) {
|
||||
for (u = 0; u < hn; u += 4) {
|
||||
__m256d ar = _mm256_loadu_pd(ad + u);
|
||||
__m256d ai = _mm256_loadu_pd(ad + u + hn);
|
||||
__m256d br = _mm256_loadu_pd(bd + u);
|
||||
__m256d bi = _mm256_loadu_pd(bd + u + hn);
|
||||
/* re = ar*br + ai*bi ; im = ai*br - ar*bi */
|
||||
__m256d re = _mm256_fmadd_pd(ar, br, _mm256_mul_pd(ai, bi));
|
||||
__m256d im = _mm256_fmsub_pd(ai, br, _mm256_mul_pd(ar, bi));
|
||||
_mm256_storeu_pd(ad + u, re);
|
||||
_mm256_storeu_pd(ad + u + hn, im);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr a_re = a[u], a_im = a[u + hn];
|
||||
fpr b_re = b[u], b_im = fpr_neg(b[u + hn]);
|
||||
FPC_MUL(a[u], a[u + hn], a_re, a_im, b_re, b_im);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* a <- a * adj(a) = |a|^2 (real) over [0, hn); imag half set to zero. */
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_poly_mulselfadj_fft_avx2(fpr* a, unsigned logn)
|
||||
{
|
||||
double* ad = (double*)a;
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
|
||||
if (hn >= 4) {
|
||||
__m256d zero = _mm256_setzero_pd();
|
||||
for (u = 0; u < hn; u += 4) {
|
||||
__m256d ar = _mm256_loadu_pd(ad + u);
|
||||
__m256d ai = _mm256_loadu_pd(ad + u + hn);
|
||||
__m256d re = _mm256_fmadd_pd(ar, ar, _mm256_mul_pd(ai, ai));
|
||||
_mm256_storeu_pd(ad + u, re);
|
||||
_mm256_storeu_pd(ad + u + hn, zero);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr a_re = a[u], a_im = a[u + hn];
|
||||
a[u] = fpr_add(fpr_mul(a_re, a_re), fpr_mul(a_im, a_im));
|
||||
a[u + hn] = fpr_zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* d <- 1 / (|a|^2 + |b|^2) (real) over [0, hn). */
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_poly_invnorm2_fft_avx2(fpr* d, const fpr* a, const fpr* b,
|
||||
unsigned logn)
|
||||
{
|
||||
double* dd = (double*)d;
|
||||
const double* ad = (const double*)a;
|
||||
const double* bd = (const double*)b;
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
|
||||
if (hn >= 4) {
|
||||
__m256d one = _mm256_set1_pd(1.0);
|
||||
for (u = 0; u < hn; u += 4) {
|
||||
__m256d ar = _mm256_loadu_pd(ad + u);
|
||||
__m256d ai = _mm256_loadu_pd(ad + u + hn);
|
||||
__m256d br = _mm256_loadu_pd(bd + u);
|
||||
__m256d bi = _mm256_loadu_pd(bd + u + hn);
|
||||
__m256d s = _mm256_fmadd_pd(ar, ar, _mm256_mul_pd(ai, ai));
|
||||
s = _mm256_fmadd_pd(br, br, s);
|
||||
s = _mm256_fmadd_pd(bi, bi, s);
|
||||
_mm256_storeu_pd(dd + u, _mm256_div_pd(one, s));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr a_re = a[u], a_im = a[u + hn];
|
||||
fpr b_re = b[u], b_im = b[u + hn];
|
||||
d[u] = fpr_inv(fpr_add(
|
||||
fpr_add(fpr_mul(a_re, a_re), fpr_mul(a_im, a_im)),
|
||||
fpr_add(fpr_mul(b_re, b_re), fpr_mul(b_im, b_im))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* d <- F*adj(f) + G*adj(g) over [0, hn). */
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_poly_add_muladj_fft_avx2(fpr* d, const fpr* F, const fpr* G,
|
||||
const fpr* f, const fpr* g, unsigned logn)
|
||||
{
|
||||
double* dd = (double*)d;
|
||||
const double* Fd = (const double*)F;
|
||||
const double* Gd = (const double*)G;
|
||||
const double* fd = (const double*)f;
|
||||
const double* gd = (const double*)g;
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
|
||||
if (hn >= 4) {
|
||||
for (u = 0; u < hn; u += 4) {
|
||||
__m256d Fr = _mm256_loadu_pd(Fd + u), Fi = _mm256_loadu_pd(Fd + u + hn);
|
||||
__m256d Gr = _mm256_loadu_pd(Gd + u), Gi = _mm256_loadu_pd(Gd + u + hn);
|
||||
__m256d fr = _mm256_loadu_pd(fd + u), fi = _mm256_loadu_pd(fd + u + hn);
|
||||
__m256d gr = _mm256_loadu_pd(gd + u), gi = _mm256_loadu_pd(gd + u + hn);
|
||||
/* F*conj(f): re=Fr*fr+Fi*fi, im=Fi*fr-Fr*fi */
|
||||
__m256d are = _mm256_fmadd_pd(Fr, fr, _mm256_mul_pd(Fi, fi));
|
||||
__m256d aim = _mm256_fmsub_pd(Fi, fr, _mm256_mul_pd(Fr, fi));
|
||||
__m256d bre = _mm256_fmadd_pd(Gr, gr, _mm256_mul_pd(Gi, gi));
|
||||
__m256d bim = _mm256_fmsub_pd(Gi, gr, _mm256_mul_pd(Gr, gi));
|
||||
_mm256_storeu_pd(dd + u, _mm256_add_pd(are, bre));
|
||||
_mm256_storeu_pd(dd + u + hn, _mm256_add_pd(aim, bim));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr F_re = F[u], F_im = F[u + hn];
|
||||
fpr G_re = G[u], G_im = G[u + hn];
|
||||
fpr f_re = f[u], f_im = f[u + hn];
|
||||
fpr g_re = g[u], g_im = g[u + hn];
|
||||
fpr a_re, a_im, b_re, b_im;
|
||||
FPC_MUL(a_re, a_im, F_re, F_im, f_re, fpr_neg(f_im));
|
||||
FPC_MUL(b_re, b_im, G_re, G_im, g_re, fpr_neg(g_im));
|
||||
d[u] = fpr_add(a_re, b_re);
|
||||
d[u + hn] = fpr_add(a_im, b_im);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* LDL of the 2x2 Hermitian Gram matrix, results to d11/l10 (inputs untouched).
|
||||
* mu = g01 / g00 ; d11 = g11 - mu*adj(g01) ; l10 = adj(mu) */
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_poly_LDLmv_fft_avx2(fpr* d11, fpr* l10, const fpr* g00,
|
||||
const fpr* g01, const fpr* g11, unsigned logn)
|
||||
{
|
||||
double* d11d = (double*)d11;
|
||||
double* l10d = (double*)l10;
|
||||
const double* g00d = (const double*)g00;
|
||||
const double* g01d = (const double*)g01;
|
||||
const double* g11d = (const double*)g11;
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
|
||||
if (hn >= 4) {
|
||||
__m256d one = _mm256_set1_pd(1.0);
|
||||
__m256d neg = _mm256_set1_pd(-0.0);
|
||||
for (u = 0; u < hn; u += 4) {
|
||||
__m256d ar = _mm256_loadu_pd(g01d + u), ai = _mm256_loadu_pd(g01d + u + hn);
|
||||
__m256d br = _mm256_loadu_pd(g00d + u), bi = _mm256_loadu_pd(g00d + u + hn);
|
||||
__m256d c11r = _mm256_loadu_pd(g11d + u), c11i = _mm256_loadu_pd(g11d + u + hn);
|
||||
/* mu = g01 / g00 */
|
||||
__m256d den = _mm256_fmadd_pd(br, br, _mm256_mul_pd(bi, bi));
|
||||
__m256d m = _mm256_div_pd(one, den);
|
||||
__m256d mur = _mm256_mul_pd(_mm256_fmadd_pd(ar, br, _mm256_mul_pd(ai, bi)), m);
|
||||
__m256d mui = _mm256_mul_pd(_mm256_fmsub_pd(ai, br, _mm256_mul_pd(ar, bi)), m);
|
||||
/* xx = mu * adj(g01) : adj(g01) = (ar, -ai)
|
||||
* re = mur*ar + mui*ai ; im = mui*ar - mur*ai */
|
||||
__m256d xxr = _mm256_fmadd_pd(mur, ar, _mm256_mul_pd(mui, ai));
|
||||
__m256d xxi = _mm256_fmsub_pd(mui, ar, _mm256_mul_pd(mur, ai));
|
||||
_mm256_storeu_pd(d11d + u, _mm256_sub_pd(c11r, xxr));
|
||||
_mm256_storeu_pd(d11d + u + hn, _mm256_sub_pd(c11i, xxi));
|
||||
_mm256_storeu_pd(l10d + u, mur);
|
||||
_mm256_storeu_pd(l10d + u + hn, _mm256_xor_pd(mui, neg)); /* -mu_im */
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr g00_re = g00[u], g00_im = g00[u + hn];
|
||||
fpr g01_re = g01[u], g01_im = g01[u + hn];
|
||||
fpr g11_re = g11[u], g11_im = g11[u + hn];
|
||||
fpr mu_re, mu_im, xx_re, xx_im, m;
|
||||
m = fpr_inv(fpr_add(fpr_mul(g00_re, g00_re), fpr_mul(g00_im, g00_im)));
|
||||
mu_re = fpr_mul(fpr_add(fpr_mul(g01_re, g00_re),
|
||||
fpr_mul(g01_im, g00_im)), m);
|
||||
mu_im = fpr_mul(fpr_sub(fpr_mul(g01_im, g00_re),
|
||||
fpr_mul(g01_re, g00_im)), m);
|
||||
FPC_MUL(xx_re, xx_im, mu_re, mu_im, g01_re, fpr_neg(g01_im));
|
||||
d11[u] = fpr_sub(g11_re, xx_re);
|
||||
d11[u + hn] = fpr_sub(g11_im, xx_im);
|
||||
l10[u] = mu_re;
|
||||
l10[u + hn] = fpr_neg(mu_im);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Deinterleave two contiguous vectors v0=[x0..x3], v1=[x4..x7] into
|
||||
* evens=[x0,x2,x4,x6] and odds=[x1,x3,x5,x7]. */
|
||||
FALCON_AVX2_TARGET
|
||||
static WC_INLINE void falcon_deint(__m256d v0, __m256d v1,
|
||||
__m256d* evens, __m256d* odds)
|
||||
{
|
||||
__m256d lo = _mm256_unpacklo_pd(v0, v1); /* [x0,x4,x2,x6] */
|
||||
__m256d hi = _mm256_unpackhi_pd(v0, v1); /* [x1,x5,x3,x7] */
|
||||
*evens = _mm256_permute4x64_pd(lo, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
*odds = _mm256_permute4x64_pd(hi, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
}
|
||||
|
||||
/* Interleave evens=[x0,x2,x4,x6], odds=[x1,x3,x5,x7] back into
|
||||
* v0=[x0,x1,x2,x3], v1=[x4,x5,x6,x7]. */
|
||||
FALCON_AVX2_TARGET
|
||||
static WC_INLINE void falcon_int(__m256d evens, __m256d odds,
|
||||
__m256d* v0, __m256d* v1)
|
||||
{
|
||||
__m256d e = _mm256_permute4x64_pd(evens, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
__m256d o = _mm256_permute4x64_pd(odds, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
*v0 = _mm256_unpacklo_pd(e, o);
|
||||
*v1 = _mm256_unpackhi_pd(e, o);
|
||||
}
|
||||
|
||||
/* Split f (degree n) into half-degree f0, f1 in FFT representation. */
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_poly_split_fft_avx2(fpr* f0, fpr* f1, const fpr* f, unsigned logn)
|
||||
{
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, qn = hn >> 1, u;
|
||||
const double* fd = (const double*)f;
|
||||
double* f0d = (double*)f0;
|
||||
double* f1d = (double*)f1;
|
||||
const double* gm = (const double*)falcon_gm_tab;
|
||||
|
||||
f0[0] = f[0];
|
||||
f1[0] = f[hn];
|
||||
if (qn >= 4) {
|
||||
__m256d half = _mm256_set1_pd(0.5);
|
||||
for (u = 0; u < qn; u += 4) {
|
||||
__m256d ar, ai, br, bi, gcos, gsin, tr, ti, sr, si, xr, xi;
|
||||
/* deinterleave real parts: f[2u..2u+7] -> a_re(even), b_re(odd) */
|
||||
falcon_deint(_mm256_loadu_pd(fd + 2*u),
|
||||
_mm256_loadu_pd(fd + 2*u + 4), &ar, &br);
|
||||
falcon_deint(_mm256_loadu_pd(fd + 2*u + hn),
|
||||
_mm256_loadu_pd(fd + 2*u + hn + 4), &ai, &bi);
|
||||
/* twiddles gm[2*(hn+u) ..] -> cos(even), sin(odd) */
|
||||
falcon_deint(_mm256_loadu_pd(gm + 2*(hn + u)),
|
||||
_mm256_loadu_pd(gm + 2*(hn + u) + 4), &gcos, &gsin);
|
||||
/* f0 = half(a + b) */
|
||||
_mm256_storeu_pd(f0d + u, _mm256_mul_pd(_mm256_add_pd(ar, br), half));
|
||||
_mm256_storeu_pd(f0d + u + qn, _mm256_mul_pd(_mm256_add_pd(ai, bi), half));
|
||||
/* t = a - b ; s = t * conj(gm) ; f1 = half(s) */
|
||||
tr = _mm256_sub_pd(ar, br);
|
||||
ti = _mm256_sub_pd(ai, bi);
|
||||
/* conj: (gcos, -gsin): sr=tr*gcos+ti*gsin, si=ti*gcos-tr*gsin */
|
||||
sr = _mm256_fmadd_pd(tr, gcos, _mm256_mul_pd(ti, gsin));
|
||||
si = _mm256_fmsub_pd(ti, gcos, _mm256_mul_pd(tr, gsin));
|
||||
xr = _mm256_mul_pd(sr, half);
|
||||
xi = _mm256_mul_pd(si, half);
|
||||
_mm256_storeu_pd(f1d + u, xr);
|
||||
_mm256_storeu_pd(f1d + u + qn, xi);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (u = 0; u < qn; u++) {
|
||||
fpr a_re = f[(u << 1) + 0], a_im = f[(u << 1) + 0 + hn];
|
||||
fpr b_re = f[(u << 1) + 1], b_im = f[(u << 1) + 1 + hn];
|
||||
fpr t_re, t_im;
|
||||
FPC_ADD(t_re, t_im, a_re, a_im, b_re, b_im);
|
||||
f0[u] = fpr_half(t_re);
|
||||
f0[u + qn] = fpr_half(t_im);
|
||||
FPC_SUB(t_re, t_im, a_re, a_im, b_re, b_im);
|
||||
FPC_MUL(t_re, t_im, t_re, t_im,
|
||||
falcon_gm_tab[((u + hn) << 1) + 0],
|
||||
fpr_neg(falcon_gm_tab[((u + hn) << 1) + 1]));
|
||||
f1[u] = fpr_half(t_re);
|
||||
f1[u + qn] = fpr_half(t_im);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge f0, f1 (degree n/2) into f (degree n) in FFT representation. */
|
||||
FALCON_AVX2_TARGET
|
||||
void falcon_poly_merge_fft_avx2(fpr* f, const fpr* f0, const fpr* f1,
|
||||
unsigned logn)
|
||||
{
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, qn = hn >> 1, u;
|
||||
double* fd = (double*)f;
|
||||
const double* f0d = (const double*)f0;
|
||||
const double* f1d = (const double*)f1;
|
||||
const double* gm = (const double*)falcon_gm_tab;
|
||||
|
||||
f[0] = f0[0];
|
||||
f[hn] = f1[0];
|
||||
if (qn >= 4) {
|
||||
for (u = 0; u < qn; u += 4) {
|
||||
__m256d ar, ai, c1r, c1i, gcos, gsin, br, bi, tr, ti, v0, v1;
|
||||
ar = _mm256_loadu_pd(f0d + u);
|
||||
ai = _mm256_loadu_pd(f0d + u + qn);
|
||||
c1r = _mm256_loadu_pd(f1d + u);
|
||||
c1i = _mm256_loadu_pd(f1d + u + qn);
|
||||
falcon_deint(_mm256_loadu_pd(gm + 2*(hn + u)),
|
||||
_mm256_loadu_pd(gm + 2*(hn + u) + 4), &gcos, &gsin);
|
||||
/* b = f1 * gm : br=c1r*gcos-c1i*gsin, bi=c1r*gsin+c1i*gcos */
|
||||
br = _mm256_fmsub_pd(c1r, gcos, _mm256_mul_pd(c1i, gsin));
|
||||
bi = _mm256_fmadd_pd(c1r, gsin, _mm256_mul_pd(c1i, gcos));
|
||||
/* even (index 2u) = a + b ; odd (index 2u+1) = a - b */
|
||||
tr = _mm256_add_pd(ar, br); /* even real */
|
||||
ti = _mm256_sub_pd(ar, br); /* odd real */
|
||||
falcon_int(tr, ti, &v0, &v1);
|
||||
_mm256_storeu_pd(fd + 2*u, v0);
|
||||
_mm256_storeu_pd(fd + 2*u + 4, v1);
|
||||
tr = _mm256_add_pd(ai, bi); /* even imag */
|
||||
ti = _mm256_sub_pd(ai, bi); /* odd imag */
|
||||
falcon_int(tr, ti, &v0, &v1);
|
||||
_mm256_storeu_pd(fd + 2*u + hn, v0);
|
||||
_mm256_storeu_pd(fd + 2*u + hn + 4, v1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (u = 0; u < qn; u++) {
|
||||
fpr a_re = f0[u], a_im = f0[u + qn];
|
||||
fpr b_re, b_im, t_re, t_im;
|
||||
FPC_MUL(b_re, b_im, f1[u], f1[u + qn],
|
||||
falcon_gm_tab[((u + hn) << 1) + 0],
|
||||
falcon_gm_tab[((u + hn) << 1) + 1]);
|
||||
FPC_ADD(t_re, t_im, a_re, a_im, b_re, b_im);
|
||||
f[(u << 1) + 0] = t_re;
|
||||
f[(u << 1) + 0 + hn] = t_im;
|
||||
FPC_SUB(t_re, t_im, a_re, a_im, b_re, b_im);
|
||||
f[(u << 1) + 1] = t_re;
|
||||
f[(u << 1) + 1 + hn] = t_im;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY &&
|
||||
* WOLFSSL_FALCON_FFT_AVX2 */
|
||||
@@ -0,0 +1,652 @@
|
||||
/* wc_falcon_fpr.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* Integer-emulated IEEE-754 binary64 backend for the FN-DSA / Falcon
|
||||
* floating-point primitive seam (wolfssl/wolfcrypt/wc_falcon_fpr.h).
|
||||
*
|
||||
* This is the portable, FP-unit-free, fully deterministic and constant-time
|
||||
* backend: every operation is performed with integer arithmetic only (64-bit
|
||||
* mantissa multiply-accumulate, shifts and CLZ-style normalization). No
|
||||
* hardware FPU is used and there is no branch or memory access that depends on
|
||||
* an operand value, so results are bit-identical to round-to-nearest-even
|
||||
* IEEE-754 binary64 on every platform.
|
||||
*
|
||||
* The algorithm is a port of the well-known Falcon reference "fpr" emulated
|
||||
* implementation by Thomas Pornin (MIT licensed), adapted to wolfSSL house
|
||||
* style (word64 / sword64 / word32). See https://falcon-sign.info/ and the
|
||||
* NIST PQC / Falcon round-3 reference code. */
|
||||
|
||||
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
||||
|
||||
#if defined(HAVE_FALCON)
|
||||
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_fpr.h>
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Low-level helpers. */
|
||||
/* */
|
||||
/* These shift helpers tolerate a (possibly secret) shift count in 0..63 in */
|
||||
/* constant time: a variable shift is split into a fixed conditional 32-bit */
|
||||
/* part plus a 0..31 part, avoiding both undefined behaviour and any */
|
||||
/* operand-dependent timing on platforms whose shift is data dependent. */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Right-shift a 64-bit unsigned value by n (0..63), constant-time. */
|
||||
static WC_INLINE fpr fpr_ursh(word64 x, int n)
|
||||
{
|
||||
x ^= (x ^ (x >> 32)) & ((word64)0 - (word64)(n >> 5));
|
||||
return x >> (n & 31);
|
||||
}
|
||||
|
||||
/* Right-shift a 64-bit signed value by n (0..63), constant-time. */
|
||||
static WC_INLINE sword64 fpr_irsh(sword64 x, int n)
|
||||
{
|
||||
x ^= (x ^ (x >> 32)) & ((sword64)0 - (sword64)(n >> 5));
|
||||
return x >> (n & 31);
|
||||
}
|
||||
|
||||
/* Left-shift a 64-bit unsigned value by n (0..63), constant-time. */
|
||||
static WC_INLINE word64 fpr_ulsh(word64 x, int n)
|
||||
{
|
||||
x ^= (x ^ (x << 32)) & ((word64)0 - (word64)(n >> 5));
|
||||
return x << (n & 31);
|
||||
}
|
||||
|
||||
/* Pack a sign s (0/1), unbiased exponent e and mantissa m (2^54 <= m < 2^55,
|
||||
* with the low 3 bits carrying guard/round/sticky information) into the
|
||||
* IEEE-754 binary64 bit pattern, applying round-to-nearest-even.
|
||||
*
|
||||
* If m == 0 a (signed) zero is produced. If e < -1076 the value underflows to
|
||||
* a (signed) zero. */
|
||||
static WC_INLINE fpr FPR(int s, int e, word64 m)
|
||||
{
|
||||
fpr x;
|
||||
word32 t;
|
||||
unsigned int f;
|
||||
|
||||
/* If e >= -1076 the value is "normal"; otherwise it would be subnormal,
|
||||
* which we clamp down to zero. */
|
||||
e += 1076;
|
||||
t = (word32)e >> 31;
|
||||
m &= (word64)t - 1;
|
||||
|
||||
/* If m == 0 we want a zero: force e to 0 too (the sign is conserved). */
|
||||
t = (word32)(m >> 54);
|
||||
e &= -(int)t;
|
||||
|
||||
/* The 52 stored mantissa bits come from m. Its top set bit (bit 54)
|
||||
* increments the exponent field by one when added, which is what we want
|
||||
* (and produces 0 for m == 0). */
|
||||
x = (((word64)s << 63) | (m >> 2)) + ((word64)(word32)e << 52);
|
||||
|
||||
/* Round to nearest, ties to even: increment when the low 3 bits of m are
|
||||
* 011, 110 or 111. A carry spilling into the exponent field is the desired
|
||||
* behaviour. */
|
||||
f = (unsigned int)m & 7U;
|
||||
x += (0xC8U >> f) & 1U;
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Normalize mantissa m so its top bit (bit 63) is set, adjusting exponent e so
|
||||
* that m * 2^e is preserved. A zero m is left unchanged. Constant-time. */
|
||||
#define FPR_NORM64(m, e) do { \
|
||||
word32 nt_; \
|
||||
\
|
||||
(e) -= 63; \
|
||||
\
|
||||
nt_ = (word32)((m) >> 32); \
|
||||
nt_ = (nt_ | (word32)(0U - nt_)) >> 31; \
|
||||
(m) ^= ((m) ^ ((m) << 32)) & ((word64)nt_ - 1); \
|
||||
(e) += (int)(nt_ << 5); \
|
||||
\
|
||||
nt_ = (word32)((m) >> 48); \
|
||||
nt_ = (nt_ | (word32)(0U - nt_)) >> 31; \
|
||||
(m) ^= ((m) ^ ((m) << 16)) & ((word64)nt_ - 1); \
|
||||
(e) += (int)(nt_ << 4); \
|
||||
\
|
||||
nt_ = (word32)((m) >> 56); \
|
||||
nt_ = (nt_ | (word32)(0U - nt_)) >> 31; \
|
||||
(m) ^= ((m) ^ ((m) << 8)) & ((word64)nt_ - 1); \
|
||||
(e) += (int)(nt_ << 3); \
|
||||
\
|
||||
nt_ = (word32)((m) >> 60); \
|
||||
nt_ = (nt_ | (word32)(0U - nt_)) >> 31; \
|
||||
(m) ^= ((m) ^ ((m) << 4)) & ((word64)nt_ - 1); \
|
||||
(e) += (int)(nt_ << 2); \
|
||||
\
|
||||
nt_ = (word32)((m) >> 62); \
|
||||
nt_ = (nt_ | (word32)(0U - nt_)) >> 31; \
|
||||
(m) ^= ((m) ^ ((m) << 2)) & ((word64)nt_ - 1); \
|
||||
(e) += (int)(nt_ << 1); \
|
||||
\
|
||||
nt_ = (word32)((m) >> 63); \
|
||||
(m) ^= ((m) ^ ((m) << 1)) & ((word64)nt_ - 1); \
|
||||
(e) += (int)(nt_); \
|
||||
} while (0)
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Constructors / conversions. */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#ifndef WOLFSSL_FALCON_FPR_DOUBLE /* inline backend provides fpr_scaled */
|
||||
fpr fpr_scaled(sword64 i, int sc)
|
||||
{
|
||||
/* Convert i * 2^sc to fpr: take the sign and absolute value, normalize the
|
||||
* magnitude so the top bit is set, round down to a 55-bit mantissa (with a
|
||||
* sticky low bit) and pack. The source integer is assumed not to be
|
||||
* -2^63. */
|
||||
int s, e;
|
||||
word32 t;
|
||||
word64 m;
|
||||
|
||||
/* Sign and absolute value (-i == 1 + ~i). */
|
||||
s = (int)((word64)i >> 63);
|
||||
i ^= -(sword64)s;
|
||||
i += s;
|
||||
|
||||
/* Suppose i != 0 for now: normalize it so the top bit is set. */
|
||||
m = (word64)i;
|
||||
e = 9 + sc;
|
||||
FPR_NORM64(m, e);
|
||||
|
||||
/* m is now in 2^63..2^64-1; divide by 512 into the 2^54..2^55-1 range,
|
||||
* folding any dropped bit into the sticky low bit. */
|
||||
m |= ((word32)m & 0x1FF) + 0x1FF;
|
||||
m >>= 9;
|
||||
|
||||
/* Corrective action for i == 0: clamp e and m to zero. */
|
||||
t = (word32)((word64)((word64)i | (word64)(0 - (word64)i)) >> 63);
|
||||
m &= (word64)0 - (word64)t;
|
||||
e &= -(int)t;
|
||||
|
||||
/* FPR() handles exponents that are too low. */
|
||||
return FPR(s, e, m);
|
||||
}
|
||||
#endif /* !WOLFSSL_FALCON_FPR_DOUBLE */
|
||||
|
||||
#if !defined(WOLFSSL_FALCON_FPR_ASM) && !defined(WOLFSSL_FALCON_FPR_DOUBLE)
|
||||
/* The scalar fpr operations below are supplied by the per-architecture assembly
|
||||
* backend (wc_falcon_fpr_x86_64_asm.S, WOLFSSL_FALCON_FPR_ASM) or by the inline
|
||||
* native-double backend (WOLFSSL_FALCON_FPR_DOUBLE) when either is set;
|
||||
* otherwise this constant-time integer emulation is used. fpr_expm_p63 and the
|
||||
* fpr constants (below) always come from this file. */
|
||||
fpr fpr_of(sword64 i)
|
||||
{
|
||||
return fpr_scaled(i, 0);
|
||||
}
|
||||
|
||||
sword64 fpr_rint(fpr x)
|
||||
{
|
||||
word64 m, d;
|
||||
int e;
|
||||
word32 s, dd, f;
|
||||
|
||||
/* Assuming the value fits in -(2^63-1)..+(2^63-1), extract the mantissa as
|
||||
* a 63-bit integer and right-shift it as needed. */
|
||||
m = ((x << 10) | ((word64)1 << 62)) & (((word64)1 << 63) - 1);
|
||||
e = 1085 - ((int)(x >> 52) & 0x7FF);
|
||||
|
||||
/* A shift of more than 63 bits sets m to zero (also covers x == 0). */
|
||||
m &= (word64)0 - (word64)((word32)(e - 64) >> 31);
|
||||
e &= 63;
|
||||
|
||||
/* Right-shift m by e, rounding to nearest with ties to even. We build a
|
||||
* word holding all dropped bits plus the lowest kept bit, then shrink it
|
||||
* to three bits, the lowest being sticky. */
|
||||
d = fpr_ulsh(m, 63 - e);
|
||||
dd = (word32)d | ((word32)(d >> 32) & 0x1FFFFFFF);
|
||||
f = (word32)(d >> 61) | ((dd | (word32)(0U - dd)) >> 31);
|
||||
m = fpr_ursh(m, e) + (word64)((0xC8U >> f) & 1U);
|
||||
|
||||
/* Apply the sign bit. */
|
||||
s = (word32)(x >> 63);
|
||||
return ((sword64)m ^ -(sword64)s) + (sword64)s;
|
||||
}
|
||||
|
||||
sword64 fpr_floor(fpr x)
|
||||
{
|
||||
word64 t;
|
||||
sword64 xi;
|
||||
int e, cc;
|
||||
|
||||
/* Extract the value as a signed scaled integer in the 2^62..2^63-1 range
|
||||
* (absolute value), so only a right-shift is needed afterwards. */
|
||||
e = (int)(x >> 52) & 0x7FF;
|
||||
t = x >> 63;
|
||||
xi = (sword64)(((x << 10) | ((word64)1 << 62)) & (((word64)1 << 63) - 1));
|
||||
xi = (xi ^ -(sword64)t) + (sword64)t;
|
||||
cc = 1085 - e;
|
||||
|
||||
/* An arithmetic right-shift implements floor() (round toward -inf) for
|
||||
* both positive and negative values. */
|
||||
xi = fpr_irsh(xi, cc & 63);
|
||||
|
||||
/* If the true shift count was 64 or more, replace xi with 0 (nonnegative)
|
||||
* or -1 (negative). This also fixes the bogus implicit-bit assumption for
|
||||
* a zero input. */
|
||||
xi ^= (xi ^ -(sword64)t) & -(sword64)((word32)(63 - cc) >> 31);
|
||||
return xi;
|
||||
}
|
||||
|
||||
sword64 fpr_trunc(fpr x)
|
||||
{
|
||||
word64 t, xu;
|
||||
int e, cc;
|
||||
|
||||
/* Extract the absolute value as a scaled integer in the 2^62..2^63-1
|
||||
* range, then right-shift. */
|
||||
e = (int)(x >> 52) & 0x7FF;
|
||||
xu = ((x << 10) | ((word64)1 << 62)) & (((word64)1 << 63) - 1);
|
||||
cc = 1085 - e;
|
||||
xu = fpr_ursh(xu, cc & 63);
|
||||
|
||||
/* If the exponent is too low (cc > 63), clamp to zero (also covers
|
||||
* x == 0). */
|
||||
xu &= (word64)0 - (word64)((word32)(cc - 64) >> 31);
|
||||
|
||||
/* Apply the sign. */
|
||||
t = x >> 63;
|
||||
xu = (xu ^ ((word64)0 - t)) + t;
|
||||
return (sword64)xu;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Arithmetic. */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
fpr fpr_add(fpr x, fpr y)
|
||||
{
|
||||
word64 m, xu, yu, za;
|
||||
word32 cs;
|
||||
int ex, ey, sx, sy, cc;
|
||||
|
||||
/* Ensure x has the larger absolute value, so the exponent of y is no
|
||||
* greater than that of x. We also conditionally swap when abs(x) == abs(y)
|
||||
* and the sign of x is 1, which guarantees the result keeps the sign of x
|
||||
* (and is +0 in the exact-cancellation case). */
|
||||
m = ((word64)1 << 63) - 1;
|
||||
za = (x & m) - (y & m);
|
||||
cs = (word32)(za >> 63)
|
||||
| ((1U - (word32)(((word64)0 - za) >> 63)) & (word32)(x >> 63));
|
||||
m = (x ^ y) & ((word64)0 - (word64)cs);
|
||||
x ^= m;
|
||||
y ^= m;
|
||||
|
||||
/* Extract sign bits, biased exponents and mantissas. The mantissas are
|
||||
* scaled up to the 2^55..2^56-1 range. A zero operand gets mantissa 0 and
|
||||
* exponent -1078. */
|
||||
ex = (int)(x >> 52);
|
||||
sx = ex >> 11;
|
||||
ex &= 0x7FF;
|
||||
m = (word64)(word32)((ex + 0x7FF) >> 11) << 52;
|
||||
xu = ((x & (((word64)1 << 52) - 1)) | m) << 3;
|
||||
ex -= 1078;
|
||||
ey = (int)(y >> 52);
|
||||
sy = ey >> 11;
|
||||
ey &= 0x7FF;
|
||||
m = (word64)(word32)((ey + 0x7FF) >> 11) << 52;
|
||||
yu = ((y & (((word64)1 << 52) - 1)) | m) << 3;
|
||||
ey -= 1078;
|
||||
|
||||
/* x has the larger exponent; right-shift y to align. A shift of 60 bits or
|
||||
* more clamps y to zero. */
|
||||
cc = ex - ey;
|
||||
yu &= (word64)0 - (word64)((word32)(cc - 60) >> 31);
|
||||
cc &= 63;
|
||||
|
||||
/* The lowest bit of yu becomes sticky over the shifted-out bits. */
|
||||
m = fpr_ulsh(1, cc) - 1;
|
||||
yu |= (yu & m) + m;
|
||||
yu = fpr_ursh(yu, cc);
|
||||
|
||||
/* Same sign: add mantissas; differing signs: subtract. */
|
||||
xu += yu - ((yu << 1) & ((word64)0 - (word64)(sx ^ sy)));
|
||||
|
||||
/* Renormalize the (possibly cancelled or carried) result. */
|
||||
FPR_NORM64(xu, ex);
|
||||
|
||||
/* Scale down to the 2^54..2^55-1 range, keeping a sticky low bit. */
|
||||
xu |= ((word32)xu & 0x1FF) + 0x1FF;
|
||||
xu >>= 9;
|
||||
ex += 9;
|
||||
|
||||
/* The result keeps the sign of x (the swap above made the -0 corner cases
|
||||
* impossible); FPR() clamps a too-low exponent to zero without altering
|
||||
* the sign. */
|
||||
return FPR(sx, ex, xu);
|
||||
}
|
||||
|
||||
fpr fpr_sub(fpr x, fpr y)
|
||||
{
|
||||
y ^= (word64)1 << 63;
|
||||
return fpr_add(x, y);
|
||||
}
|
||||
|
||||
fpr fpr_neg(fpr x)
|
||||
{
|
||||
x ^= (word64)1 << 63;
|
||||
return x;
|
||||
}
|
||||
|
||||
fpr fpr_half(fpr x)
|
||||
{
|
||||
/* Halving subtracts 1 from the exponent; handle zero specially. */
|
||||
word32 t;
|
||||
|
||||
x -= (word64)1 << 52;
|
||||
t = (((word32)(x >> 52) & 0x7FF) + 1) >> 11;
|
||||
x &= (word64)t - 1;
|
||||
return x;
|
||||
}
|
||||
|
||||
fpr fpr_double(fpr x)
|
||||
{
|
||||
/* Doubling increments the exponent; handle zero specially. Infinities and
|
||||
* NaNs are not a concern for this backend. */
|
||||
x += (word64)((((unsigned int)(x >> 52) & 0x7FFU) + 0x7FFU) >> 11) << 52;
|
||||
return x;
|
||||
}
|
||||
|
||||
fpr fpr_mul(fpr x, fpr y)
|
||||
{
|
||||
word64 xu, yu, w, zu, zv;
|
||||
word32 x0, x1, y0, y1, z0, z1, z2;
|
||||
int ex, ey, d, e, s;
|
||||
|
||||
/* Extract mantissas (with implicit bit) as 53-bit integers. */
|
||||
xu = (x & (((word64)1 << 52) - 1)) | ((word64)1 << 52);
|
||||
yu = (y & (((word64)1 << 52) - 1)) | ((word64)1 << 52);
|
||||
|
||||
/* Multiply the two 53-bit integers using 25-bit low halves so the low
|
||||
* limbs (z0, z1) only ever matter for the sticky bit. */
|
||||
x0 = (word32)xu & 0x01FFFFFF;
|
||||
x1 = (word32)(xu >> 25);
|
||||
y0 = (word32)yu & 0x01FFFFFF;
|
||||
y1 = (word32)(yu >> 25);
|
||||
w = (word64)x0 * (word64)y0;
|
||||
z0 = (word32)w & 0x01FFFFFF;
|
||||
z1 = (word32)(w >> 25);
|
||||
w = (word64)x0 * (word64)y1;
|
||||
z1 += (word32)w & 0x01FFFFFF;
|
||||
z2 = (word32)(w >> 25);
|
||||
w = (word64)x1 * (word64)y0;
|
||||
z1 += (word32)w & 0x01FFFFFF;
|
||||
z2 += (word32)(w >> 25);
|
||||
zu = (word64)x1 * (word64)y1;
|
||||
z2 += (z1 >> 25);
|
||||
z1 &= 0x01FFFFFF;
|
||||
zu += z2;
|
||||
|
||||
/* The product is in 2^104..2^106-1. Keep the top part (zu); fold the low
|
||||
* limbs into a sticky bit. */
|
||||
zu |= ((z0 | z1) + 0x01FFFFFF) >> 25;
|
||||
|
||||
/* Normalize zu to 2^54..2^55-1; it may be one bit too large. The
|
||||
* conditional right-shift preserves the sticky bit. */
|
||||
zv = (zu >> 1) | (zu & 1);
|
||||
w = zu >> 55;
|
||||
zu ^= (zu ^ zv) & ((word64)0 - w);
|
||||
|
||||
/* Aggregate scaling factor: sum the exponents, remove 2*(1023+52), then
|
||||
* add 50 + w (the right-shift amounts applied above). */
|
||||
ex = (int)((x >> 52) & 0x7FF);
|
||||
ey = (int)((y >> 52) & 0x7FF);
|
||||
e = ex + ey - 2100 + (int)w;
|
||||
|
||||
/* Result sign is the XOR of the operand signs. */
|
||||
s = (int)((x ^ y) >> 63);
|
||||
|
||||
/* Corrective action: if either operand is zero, clamp the mantissa. */
|
||||
d = ((ex + 0x7FF) & (ey + 0x7FF)) >> 11;
|
||||
zu &= (word64)0 - (word64)d;
|
||||
|
||||
return FPR(s, e, zu);
|
||||
}
|
||||
|
||||
fpr fpr_sqr(fpr x)
|
||||
{
|
||||
return fpr_mul(x, x);
|
||||
}
|
||||
|
||||
fpr fpr_div(fpr x, fpr y)
|
||||
{
|
||||
word64 xu, yu, q, q2, w;
|
||||
int i, ex, ey, e, d, s;
|
||||
|
||||
/* Extract mantissas (with implicit bit). */
|
||||
xu = (x & (((word64)1 << 52) - 1)) | ((word64)1 << 52);
|
||||
yu = (y & (((word64)1 << 52) - 1)) | ((word64)1 << 52);
|
||||
|
||||
/* Bit-by-bit long division of xu by yu, for 55 bits. */
|
||||
q = 0;
|
||||
for (i = 0; i < 55; i++) {
|
||||
word64 b;
|
||||
|
||||
b = ((xu - yu) >> 63) - 1;
|
||||
xu -= b & yu;
|
||||
q |= b & 1;
|
||||
xu <<= 1;
|
||||
q <<= 1;
|
||||
}
|
||||
|
||||
/* Make the 56th (extra) bit sticky: set it iff the remainder is nonzero. */
|
||||
q |= (xu | ((word64)0 - xu)) >> 63;
|
||||
|
||||
/* Normalize q to the 2^54..2^55-1 range (conditional shift, sticky-aware);
|
||||
* the top bit may be zero but then the next bit is one. */
|
||||
q2 = (q >> 1) | (q & 1);
|
||||
w = q >> 55;
|
||||
q ^= (q ^ q2) & ((word64)0 - w);
|
||||
|
||||
/* Scaling: exponent biases cancel; remove 55 (division shift) and add w. */
|
||||
ex = (int)((x >> 52) & 0x7FF);
|
||||
ey = (int)((y >> 52) & 0x7FF);
|
||||
e = ex - ey - 55 + (int)w;
|
||||
|
||||
/* Result sign is the XOR of the operand signs. */
|
||||
s = (int)((x ^ y) >> 63);
|
||||
|
||||
/* Corrective action for x == 0 (division by zero is excluded by the
|
||||
* caller's contract). */
|
||||
d = (ex + 0x7FF) >> 11;
|
||||
s &= d;
|
||||
e &= -d;
|
||||
q &= (word64)0 - (word64)d;
|
||||
|
||||
return FPR(s, e, q);
|
||||
}
|
||||
|
||||
fpr fpr_inv(fpr x)
|
||||
{
|
||||
/* 1.0 / x: fpr_one is the bit pattern of the double 1.0. */
|
||||
return fpr_div(fpr_one, x);
|
||||
}
|
||||
|
||||
fpr fpr_sqrt(fpr x)
|
||||
{
|
||||
word64 xu, q, s, r;
|
||||
int i, ex, e;
|
||||
|
||||
/* Extract the mantissa and the true exponent (mantissa in 1..2). The sign
|
||||
* is ignored: the operand is assumed nonnegative. */
|
||||
xu = (x & (((word64)1 << 52) - 1)) | ((word64)1 << 52);
|
||||
ex = (int)((x >> 52) & 0x7FF);
|
||||
e = ex - 1023;
|
||||
|
||||
/* If the exponent is odd, double the mantissa and decrement the exponent,
|
||||
* then halve the exponent for the square root. */
|
||||
xu += xu & ((word64)0 - (word64)(e & 1));
|
||||
e >>= 1;
|
||||
|
||||
/* Double the mantissa: now in 2^53..2^55-1, representing a value in
|
||||
* [1, 4) with 53 fractional bits. */
|
||||
xu <<= 1;
|
||||
|
||||
/* Compute the square root bit by bit. */
|
||||
q = 0;
|
||||
s = 0;
|
||||
r = (word64)1 << 53;
|
||||
for (i = 0; i < 54; i++) {
|
||||
word64 t, b;
|
||||
|
||||
t = s + r;
|
||||
b = ((xu - t) >> 63) - 1;
|
||||
s += (r << 1) & b;
|
||||
xu -= t & b;
|
||||
q += r & b;
|
||||
xu <<= 1;
|
||||
r >>= 1;
|
||||
}
|
||||
|
||||
/* q is a rounded-low 54-bit value (leading 1, 52 fractional digits and a
|
||||
* guard bit); add a sticky bit for the remaining operand. */
|
||||
q <<= 1;
|
||||
q |= (xu | ((word64)0 - xu)) >> 63;
|
||||
|
||||
/* q is now an integer in 2^54..2^55-1; bias the exponent by 54. */
|
||||
e -= 54;
|
||||
|
||||
/* Corrective action for an operand of value zero. */
|
||||
q &= (word64)0 - (word64)((ex + 0x7FF) >> 11);
|
||||
|
||||
return FPR(0, e, q);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Predicates. */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
int fpr_lt(fpr x, fpr y)
|
||||
{
|
||||
/* For equal signs a signed comparison of the bit patterns yields the
|
||||
* correct order (and x - y does not overflow). For differing signs the
|
||||
* sign of x decides. For two negatives the order is reversed, so we
|
||||
* combine sgn(x-y) and sgn(y-x). */
|
||||
int cc0, cc1;
|
||||
sword64 sx;
|
||||
sword64 sy;
|
||||
|
||||
sx = (sword64)x;
|
||||
sy = (sword64)y;
|
||||
sy &= ~((sx ^ sy) >> 63); /* sy = 0 if the signs differ */
|
||||
|
||||
cc0 = (int)((sx - sy) >> 63) & 1; /* neither subtraction overflows when */
|
||||
cc1 = (int)((sy - sx) >> 63) & 1; /* the signs are the same */
|
||||
|
||||
return cc0 ^ ((cc0 ^ cc1) & (int)((x & y) >> 63));
|
||||
}
|
||||
#endif /* !WOLFSSL_FALCON_FPR_ASM */
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Sampler support: ccs * exp(-x) in fixed point scaled by 2^63. */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Top 64 bits of the 128-bit product z*y. This is the inner operation of the
|
||||
* Bernoulli-exp polynomial and the hottest scalar op in signing. On 64-bit
|
||||
* targets it is a single multiply instruction; the portable 32x32 fallback
|
||||
* (one MUL becomes four) is kept for platforms without a 128-bit integer type
|
||||
* (e.g. Cortex-M). Both paths are constant-time and bit-identical. */
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
#define FALCON_MULHI(z, y) \
|
||||
((word64)(((unsigned __int128)(word64)(z) * (unsigned __int128)(word64)(y)) >> 64))
|
||||
#else
|
||||
static WC_INLINE word64 falcon_mulhi(word64 z, word64 y)
|
||||
{
|
||||
word32 z0 = (word32)z, z1 = (word32)(z >> 32);
|
||||
word32 y0 = (word32)y, y1 = (word32)(y >> 32);
|
||||
word64 a = ((word64)z0 * (word64)y1) + (((word64)z0 * (word64)y0) >> 32);
|
||||
word64 b = ((word64)z1 * (word64)y0);
|
||||
word64 c = (a >> 32) + (b >> 32);
|
||||
c += (((word64)(word32)a + (word64)(word32)b) >> 32);
|
||||
c += (word64)z1 * (word64)y1;
|
||||
return c;
|
||||
}
|
||||
#define FALCON_MULHI(z, y) falcon_mulhi((z), (y))
|
||||
#endif
|
||||
|
||||
word64 fpr_expm_p63(fpr x, fpr ccs)
|
||||
{
|
||||
/* Polynomial approximation of exp(-x), coefficients from FACCT
|
||||
* (https://eprint.iacr.org/2018/1234, https://github.com/raykzhao/gaussian)
|
||||
* scaled up by 2^63 and converted to integers. The maximum observed
|
||||
* deviation from the true value over the 0..log(2) range is below
|
||||
* 2^(-50). */
|
||||
static const word64 C[] = {
|
||||
0x00000004741183A3u,
|
||||
0x00000036548CFC06u,
|
||||
0x0000024FDCBF140Au,
|
||||
0x0000171D939DE045u,
|
||||
0x0000D00CF58F6F84u,
|
||||
0x000680681CF796E3u,
|
||||
0x002D82D8305B0FEAu,
|
||||
0x011111110E066FD0u,
|
||||
0x0555555555070F00u,
|
||||
0x155555555581FF00u,
|
||||
0x400000000002B400u,
|
||||
0x7FFFFFFFFFFF4800u,
|
||||
0x8000000000000000u
|
||||
};
|
||||
|
||||
word64 z, y;
|
||||
|
||||
/* Horner evaluation of the degree-12 polynomial; each step keeps the top
|
||||
* 64 bits of z*y. Fully unrolled (the loop bound is a compile-time 13). */
|
||||
y = C[0];
|
||||
z = (word64)fpr_trunc(fpr_mul(x, fpr_ptwo63)) << 1;
|
||||
y = C[1] - FALCON_MULHI(z, y);
|
||||
y = C[2] - FALCON_MULHI(z, y);
|
||||
y = C[3] - FALCON_MULHI(z, y);
|
||||
y = C[4] - FALCON_MULHI(z, y);
|
||||
y = C[5] - FALCON_MULHI(z, y);
|
||||
y = C[6] - FALCON_MULHI(z, y);
|
||||
y = C[7] - FALCON_MULHI(z, y);
|
||||
y = C[8] - FALCON_MULHI(z, y);
|
||||
y = C[9] - FALCON_MULHI(z, y);
|
||||
y = C[10] - FALCON_MULHI(z, y);
|
||||
y = C[11] - FALCON_MULHI(z, y);
|
||||
y = C[12] - FALCON_MULHI(z, y);
|
||||
|
||||
/* Apply the scaling factor ccs (converted to the same fixed-point format)
|
||||
* with a final 64x64->high-64 multiplication. */
|
||||
z = (word64)fpr_trunc(fpr_mul(ccs, fpr_ptwo63)) << 1;
|
||||
y = FALCON_MULHI(z, y);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Named constants: IEEE-754 binary64 bit patterns. */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
const fpr fpr_zero = 0;
|
||||
const fpr fpr_one = 4607182418800017408U; /* 1.0 */
|
||||
const fpr fpr_two = 4611686018427387904U; /* 2.0 */
|
||||
const fpr fpr_onehalf = 4602678819172646912U; /* 0.5 */
|
||||
const fpr fpr_invsqrt2 = 4604544271217802189U; /* 1/sqrt(2) */
|
||||
const fpr fpr_invsqrt8 = 4600040671590431693U; /* 1/sqrt(8) */
|
||||
const fpr fpr_ptwo31 = 4746794007248502784U; /* 2^31 */
|
||||
const fpr fpr_ptwo31m1 = 4746794007244308480U; /* 2^31 - 1 */
|
||||
const fpr fpr_mtwo31m1 = 13970166044099084288U; /* -(2^31 - 1) */
|
||||
const fpr fpr_ptwo63m1 = 4890909195324358656U; /* 2^63 - 1 */
|
||||
const fpr fpr_mtwo63m1 = 14114281232179134464U; /* -(2^63 - 1) */
|
||||
const fpr fpr_ptwo63 = 4890909195324358656U; /* 2^63 */
|
||||
|
||||
#endif /* HAVE_FALCON */
|
||||
@@ -0,0 +1,387 @@
|
||||
/* wc_falcon_fpr_x86_64_asm.S */
|
||||
/*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#ifdef WOLFSSL_USER_SETTINGS
|
||||
#ifdef WOLFSSL_USER_SETTINGS_ASM
|
||||
/*
|
||||
* user_settings_asm.h is a file generated by the script user_settings_asm.sh.
|
||||
* The script takes in a user_settings.h and produces user_settings_asm.h, which
|
||||
* is a stripped down version of user_settings.h containing only preprocessor
|
||||
* directives. This makes the header safe to include in assembly (.S) files.
|
||||
*/
|
||||
#include "user_settings_asm.h"
|
||||
#else
|
||||
/*
|
||||
* Note: if user_settings.h contains any C code (e.g. a typedef or function
|
||||
* prototype), including it here in an assembly (.S) file will cause an
|
||||
* assembler failure. See user_settings_asm.h above.
|
||||
*/
|
||||
#include "user_settings.h"
|
||||
#endif /* WOLFSSL_USER_SETTINGS_ASM */
|
||||
#endif /* WOLFSSL_USER_SETTINGS */
|
||||
|
||||
#ifndef HAVE_INTEL_AVX1
|
||||
#define HAVE_INTEL_AVX1
|
||||
#endif /* HAVE_INTEL_AVX1 */
|
||||
#ifndef NO_AVX2_SUPPORT
|
||||
#ifndef HAVE_INTEL_AVX2
|
||||
#define HAVE_INTEL_AVX2
|
||||
#endif /* HAVE_INTEL_AVX2 */
|
||||
#endif /* NO_AVX2_SUPPORT */
|
||||
#ifndef NO_VAES_SUPPORT
|
||||
#ifndef HAVE_INTEL_VAES
|
||||
#define HAVE_INTEL_VAES
|
||||
#endif /* HAVE_INTEL_VAES */
|
||||
#endif /* NO_VAES_SUPPORT */
|
||||
#ifndef NO_AVX512_SUPPORT
|
||||
#ifndef HAVE_INTEL_AVX512
|
||||
#define HAVE_INTEL_AVX512
|
||||
#endif /* HAVE_INTEL_AVX512 */
|
||||
#endif /* NO_AVX512_SUPPORT */
|
||||
|
||||
#if defined(HAVE_FALCON) && defined(WOLFSSL_FALCON_FPR_ASM)
|
||||
/* Native x86_64 (SSE2 scalar-double) backend for the FN-DSA fpr
|
||||
* seam. Generated by wolfssl-scripts: falcon/x86_64/falcon.rb.
|
||||
* Each routine is bit-exact with the round-to-nearest-even
|
||||
* IEEE-754 emulation in wolfcrypt/src/wc_falcon_fpr.c on all values
|
||||
* Falcon exercises (no subnormals, no NaN/Inf). DO NOT EDIT. */
|
||||
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_add
|
||||
.type fpr_add,@function
|
||||
.align 16
|
||||
fpr_add:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_add
|
||||
.p2align 4
|
||||
_fpr_add:
|
||||
#endif /* __APPLE__ */
|
||||
# r = x + y
|
||||
movq %rdi, %xmm0
|
||||
movq %rsi, %xmm1
|
||||
addsd %xmm1, %xmm0
|
||||
movq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_add,.-fpr_add
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_sub
|
||||
.type fpr_sub,@function
|
||||
.align 16
|
||||
fpr_sub:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_sub
|
||||
.p2align 4
|
||||
_fpr_sub:
|
||||
#endif /* __APPLE__ */
|
||||
# r = x - y
|
||||
movq %rdi, %xmm0
|
||||
movq %rsi, %xmm1
|
||||
subsd %xmm1, %xmm0
|
||||
movq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_sub,.-fpr_sub
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_neg
|
||||
.type fpr_neg,@function
|
||||
.align 16
|
||||
fpr_neg:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_neg
|
||||
.p2align 4
|
||||
_fpr_neg:
|
||||
#endif /* __APPLE__ */
|
||||
# r = -x (flip the sign bit)
|
||||
movq %rdi, %xmm0
|
||||
movabsq $0x8000000000000000, %rax
|
||||
movq %rax, %xmm1
|
||||
xorpd %xmm1, %xmm0
|
||||
movq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_neg,.-fpr_neg
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_half
|
||||
.type fpr_half,@function
|
||||
.align 16
|
||||
fpr_half:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_half
|
||||
.p2align 4
|
||||
_fpr_half:
|
||||
#endif /* __APPLE__ */
|
||||
# r = x * 0.5
|
||||
movq %rdi, %xmm0
|
||||
movabsq $0x3fe0000000000000, %rax
|
||||
movq %rax, %xmm1
|
||||
mulsd %xmm1, %xmm0
|
||||
movq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_half,.-fpr_half
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_double
|
||||
.type fpr_double,@function
|
||||
.align 16
|
||||
fpr_double:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_double
|
||||
.p2align 4
|
||||
_fpr_double:
|
||||
#endif /* __APPLE__ */
|
||||
# r = x + x
|
||||
movq %rdi, %xmm0
|
||||
addsd %xmm0, %xmm0
|
||||
movq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_double,.-fpr_double
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_mul
|
||||
.type fpr_mul,@function
|
||||
.align 16
|
||||
fpr_mul:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_mul
|
||||
.p2align 4
|
||||
_fpr_mul:
|
||||
#endif /* __APPLE__ */
|
||||
# r = x * y
|
||||
movq %rdi, %xmm0
|
||||
movq %rsi, %xmm1
|
||||
mulsd %xmm1, %xmm0
|
||||
movq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_mul,.-fpr_mul
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_sqr
|
||||
.type fpr_sqr,@function
|
||||
.align 16
|
||||
fpr_sqr:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_sqr
|
||||
.p2align 4
|
||||
_fpr_sqr:
|
||||
#endif /* __APPLE__ */
|
||||
# r = x * x
|
||||
movq %rdi, %xmm0
|
||||
mulsd %xmm0, %xmm0
|
||||
movq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_sqr,.-fpr_sqr
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_div
|
||||
.type fpr_div,@function
|
||||
.align 16
|
||||
fpr_div:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_div
|
||||
.p2align 4
|
||||
_fpr_div:
|
||||
#endif /* __APPLE__ */
|
||||
# r = x / y
|
||||
movq %rdi, %xmm0
|
||||
movq %rsi, %xmm1
|
||||
divsd %xmm1, %xmm0
|
||||
movq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_div,.-fpr_div
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_inv
|
||||
.type fpr_inv,@function
|
||||
.align 16
|
||||
fpr_inv:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_inv
|
||||
.p2align 4
|
||||
_fpr_inv:
|
||||
#endif /* __APPLE__ */
|
||||
# r = 1.0 / x
|
||||
movabsq $0x3ff0000000000000, %rax
|
||||
movq %rax, %xmm1
|
||||
movq %rdi, %xmm0
|
||||
divsd %xmm0, %xmm1
|
||||
movq %xmm1, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_inv,.-fpr_inv
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_sqrt
|
||||
.type fpr_sqrt,@function
|
||||
.align 16
|
||||
fpr_sqrt:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_sqrt
|
||||
.p2align 4
|
||||
_fpr_sqrt:
|
||||
#endif /* __APPLE__ */
|
||||
# r = sqrt(x) (operand assumed non-negative)
|
||||
movq %rdi, %xmm0
|
||||
sqrtsd %xmm0, %xmm0
|
||||
movq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_sqrt,.-fpr_sqrt
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_of
|
||||
.type fpr_of,@function
|
||||
.align 16
|
||||
fpr_of:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_of
|
||||
.p2align 4
|
||||
_fpr_of:
|
||||
#endif /* __APPLE__ */
|
||||
# r = (double)i (round-to-nearest-even)
|
||||
cvtsi2sdq %rdi, %xmm0
|
||||
movq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_of,.-fpr_of
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_rint
|
||||
.type fpr_rint,@function
|
||||
.align 16
|
||||
fpr_rint:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_rint
|
||||
.p2align 4
|
||||
_fpr_rint:
|
||||
#endif /* __APPLE__ */
|
||||
# return = lrint(x) (round-to-nearest, ties to even)
|
||||
movq %rdi, %xmm0
|
||||
cvtsd2siq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_rint,.-fpr_rint
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_floor
|
||||
.type fpr_floor,@function
|
||||
.align 16
|
||||
fpr_floor:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_floor
|
||||
.p2align 4
|
||||
_fpr_floor:
|
||||
#endif /* __APPLE__ */
|
||||
# return = floor(x) (round toward -inf), pure SSE2
|
||||
movq %rdi, %xmm0
|
||||
# t = trunc(x) toward zero
|
||||
cvttsd2siq %xmm0, %rax
|
||||
# tf = (double)t
|
||||
cvtsi2sdq %rax, %xmm1
|
||||
# when x < tf, subtract 1 from t (negative non-integers only)
|
||||
ucomisd %xmm1, %xmm0
|
||||
sbbq $0x00, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_floor,.-fpr_floor
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_trunc
|
||||
.type fpr_trunc,@function
|
||||
.align 16
|
||||
fpr_trunc:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_trunc
|
||||
.p2align 4
|
||||
_fpr_trunc:
|
||||
#endif /* __APPLE__ */
|
||||
# return = trunc(x) (round toward zero)
|
||||
movq %rdi, %xmm0
|
||||
cvttsd2siq %xmm0, %rax
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_trunc,.-fpr_trunc
|
||||
#endif /* __APPLE__ */
|
||||
#ifndef __APPLE__
|
||||
.text
|
||||
.globl fpr_lt
|
||||
.type fpr_lt,@function
|
||||
.align 16
|
||||
fpr_lt:
|
||||
#else
|
||||
.section __TEXT,__text
|
||||
.globl _fpr_lt
|
||||
.p2align 4
|
||||
_fpr_lt:
|
||||
#endif /* __APPLE__ */
|
||||
# return = (x < y) ? 1 : 0
|
||||
movq %rdi, %xmm0
|
||||
movq %rsi, %xmm1
|
||||
# clear eax (and flags) before the ordered compare
|
||||
xorl %eax, %eax
|
||||
ucomisd %xmm1, %xmm0
|
||||
# CF is set iff x < y
|
||||
setb %al
|
||||
repz retq
|
||||
#ifndef __APPLE__
|
||||
.size fpr_lt,.-fpr_lt
|
||||
#endif /* __APPLE__ */
|
||||
#endif /* HAVE_FALCON && WOLFSSL_FALCON_FPR_ASM */
|
||||
|
||||
#if defined(__linux__) && defined(__ELF__)
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,310 @@
|
||||
/* wc_falcon_poly.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* FN-DSA / Falcon FFT-domain polynomial operations over the fpr seam. Faithful
|
||||
* port of the poly_* functions from the MIT-licensed Falcon reference (fft.c,
|
||||
* Thomas Pornin). See wolfssl/wolfcrypt/wc_falcon_poly.h. */
|
||||
|
||||
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_poly.h>
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_fft.h> /* falcon_gm_tab */
|
||||
|
||||
/* Complex helpers (temps make the macros alias-safe). */
|
||||
#define FPC_ADD(d_re, d_im, a_re, a_im, b_re, b_im) do { \
|
||||
fpr _ar = (a_re), _ai = (a_im), _br = (b_re), _bi = (b_im); \
|
||||
(d_re) = fpr_add(_ar, _br); \
|
||||
(d_im) = fpr_add(_ai, _bi); \
|
||||
} while (0)
|
||||
#define FPC_SUB(d_re, d_im, a_re, a_im, b_re, b_im) do { \
|
||||
fpr _ar = (a_re), _ai = (a_im), _br = (b_re), _bi = (b_im); \
|
||||
(d_re) = fpr_sub(_ar, _br); \
|
||||
(d_im) = fpr_sub(_ai, _bi); \
|
||||
} while (0)
|
||||
#define FPC_MUL(d_re, d_im, a_re, a_im, b_re, b_im) do { \
|
||||
fpr _ar = (a_re), _ai = (a_im), _br = (b_re), _bi = (b_im); \
|
||||
(d_re) = fpr_sub(fpr_mul(_ar, _br), fpr_mul(_ai, _bi)); \
|
||||
(d_im) = fpr_add(fpr_mul(_ar, _bi), fpr_mul(_ai, _br)); \
|
||||
} while (0)
|
||||
/* (a) / (b) for complex a,b. */
|
||||
#define FPC_DIV(d_re, d_im, a_re, a_im, b_re, b_im) do { \
|
||||
fpr _ar = (a_re), _ai = (a_im), _br = (b_re), _bi = (b_im); \
|
||||
fpr _m = fpr_inv(fpr_add(fpr_mul(_br, _br), fpr_mul(_bi, _bi))); \
|
||||
_br = fpr_mul(_br, _m); \
|
||||
_bi = fpr_neg(fpr_mul(_bi, _m)); \
|
||||
(d_re) = fpr_sub(fpr_mul(_ar, _br), fpr_mul(_ai, _bi)); \
|
||||
(d_im) = fpr_add(fpr_mul(_ar, _bi), fpr_mul(_ai, _br)); \
|
||||
} while (0)
|
||||
|
||||
void falcon_poly_add(fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
falcon_poly_add_avx2(a, b, logn);
|
||||
#else
|
||||
size_t n = (size_t)1 << logn, u;
|
||||
for (u = 0; u < n; u++) {
|
||||
a[u] = fpr_add(a[u], b[u]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void falcon_poly_sub(fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
falcon_poly_sub_avx2(a, b, logn);
|
||||
#else
|
||||
size_t n = (size_t)1 << logn, u;
|
||||
for (u = 0; u < n; u++) {
|
||||
a[u] = fpr_sub(a[u], b[u]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void falcon_poly_neg(fpr* a, unsigned logn)
|
||||
{
|
||||
size_t n = (size_t)1 << logn, u;
|
||||
for (u = 0; u < n; u++) {
|
||||
a[u] = fpr_neg(a[u]);
|
||||
}
|
||||
}
|
||||
|
||||
void falcon_poly_adj_fft(fpr* a, unsigned logn)
|
||||
{
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
for (u = hn; u < n; u++) {
|
||||
a[u] = fpr_neg(a[u]);
|
||||
}
|
||||
}
|
||||
|
||||
void falcon_poly_mul_fft(fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
falcon_poly_mul_fft_avx2(a, b, logn);
|
||||
#else
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr a_re = a[u], a_im = a[u + hn];
|
||||
fpr b_re = b[u], b_im = b[u + hn];
|
||||
FPC_MUL(a[u], a[u + hn], a_re, a_im, b_re, b_im);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void falcon_poly_muladj_fft(fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
falcon_poly_muladj_fft_avx2(a, b, logn);
|
||||
#else
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr a_re = a[u], a_im = a[u + hn];
|
||||
fpr b_re = b[u], b_im = fpr_neg(b[u + hn]);
|
||||
FPC_MUL(a[u], a[u + hn], a_re, a_im, b_re, b_im);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void falcon_poly_mulselfadj_fft(fpr* a, unsigned logn)
|
||||
{
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
falcon_poly_mulselfadj_fft_avx2(a, logn);
|
||||
#else
|
||||
/* a * adj(a) = |a|^2 (real). */
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr a_re = a[u], a_im = a[u + hn];
|
||||
a[u] = fpr_add(fpr_mul(a_re, a_re), fpr_mul(a_im, a_im));
|
||||
a[u + hn] = fpr_zero;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void falcon_poly_mulconst(fpr* a, fpr x, unsigned logn)
|
||||
{
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
falcon_poly_mulconst_avx2(a, x, logn);
|
||||
#else
|
||||
size_t n = (size_t)1 << logn, u;
|
||||
for (u = 0; u < n; u++) {
|
||||
a[u] = fpr_mul(a[u], x);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void falcon_poly_div_fft(fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr a_re = a[u], a_im = a[u + hn];
|
||||
fpr b_re = b[u], b_im = b[u + hn];
|
||||
FPC_DIV(a[u], a[u + hn], a_re, a_im, b_re, b_im);
|
||||
}
|
||||
}
|
||||
|
||||
void falcon_poly_invnorm2_fft(fpr* d, const fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
falcon_poly_invnorm2_fft_avx2(d, a, b, logn);
|
||||
#else
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr a_re = a[u], a_im = a[u + hn];
|
||||
fpr b_re = b[u], b_im = b[u + hn];
|
||||
d[u] = fpr_inv(fpr_add(
|
||||
fpr_add(fpr_mul(a_re, a_re), fpr_mul(a_im, a_im)),
|
||||
fpr_add(fpr_mul(b_re, b_re), fpr_mul(b_im, b_im))));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void falcon_poly_add_muladj_fft(fpr* d, const fpr* F, const fpr* G,
|
||||
const fpr* f, const fpr* g, unsigned logn)
|
||||
{
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
falcon_poly_add_muladj_fft_avx2(d, F, G, f, g, logn);
|
||||
#else
|
||||
/* d = F*adj(f) + G*adj(g). */
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr F_re = F[u], F_im = F[u + hn];
|
||||
fpr G_re = G[u], G_im = G[u + hn];
|
||||
fpr f_re = f[u], f_im = f[u + hn];
|
||||
fpr g_re = g[u], g_im = g[u + hn];
|
||||
fpr a_re, a_im, b_re, b_im;
|
||||
FPC_MUL(a_re, a_im, F_re, F_im, f_re, fpr_neg(f_im));
|
||||
FPC_MUL(b_re, b_im, G_re, G_im, g_re, fpr_neg(g_im));
|
||||
d[u] = fpr_add(a_re, b_re);
|
||||
d[u + hn] = fpr_add(a_im, b_im);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void falcon_poly_mul_autoadj_fft(fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
/* b is self-adjoint (real); only its lower half is meaningful. */
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
for (u = 0; u < hn; u++) {
|
||||
a[u] = fpr_mul(a[u], b[u]);
|
||||
a[u + hn] = fpr_mul(a[u + hn], b[u]);
|
||||
}
|
||||
}
|
||||
|
||||
void falcon_poly_div_autoadj_fft(fpr* a, const fpr* b, unsigned logn)
|
||||
{
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr ib = fpr_inv(b[u]);
|
||||
a[u] = fpr_mul(a[u], ib);
|
||||
a[u + hn] = fpr_mul(a[u + hn], ib);
|
||||
}
|
||||
}
|
||||
|
||||
void falcon_poly_LDL_fft(const fpr* g00, fpr* g01, fpr* g11, unsigned logn)
|
||||
{
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr g00_re = g00[u], g00_im = g00[u + hn];
|
||||
fpr g01_re = g01[u], g01_im = g01[u + hn];
|
||||
fpr g11_re = g11[u], g11_im = g11[u + hn];
|
||||
fpr mu_re, mu_im, xx_re, xx_im;
|
||||
FPC_DIV(mu_re, mu_im, g01_re, g01_im, g00_re, g00_im);
|
||||
FPC_MUL(xx_re, xx_im, mu_re, mu_im, g01_re, fpr_neg(g01_im));
|
||||
FPC_SUB(g11[u], g11[u + hn], g11_re, g11_im, xx_re, xx_im);
|
||||
g01[u] = mu_re;
|
||||
g01[u + hn] = fpr_neg(mu_im);
|
||||
}
|
||||
}
|
||||
|
||||
void falcon_poly_LDLmv_fft(fpr* d11, fpr* l10, const fpr* g00, const fpr* g01,
|
||||
const fpr* g11, unsigned logn)
|
||||
{
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
falcon_poly_LDLmv_fft_avx2(d11, l10, g00, g01, g11, logn);
|
||||
#else
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, u;
|
||||
for (u = 0; u < hn; u++) {
|
||||
fpr g00_re = g00[u], g00_im = g00[u + hn];
|
||||
fpr g01_re = g01[u], g01_im = g01[u + hn];
|
||||
fpr g11_re = g11[u], g11_im = g11[u + hn];
|
||||
fpr mu_re, mu_im, xx_re, xx_im;
|
||||
FPC_DIV(mu_re, mu_im, g01_re, g01_im, g00_re, g00_im);
|
||||
FPC_MUL(xx_re, xx_im, mu_re, mu_im, g01_re, fpr_neg(g01_im));
|
||||
FPC_SUB(d11[u], d11[u + hn], g11_re, g11_im, xx_re, xx_im);
|
||||
l10[u] = mu_re;
|
||||
l10[u + hn] = fpr_neg(mu_im);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void falcon_poly_split_fft(fpr* f0, fpr* f1, const fpr* f, unsigned logn)
|
||||
{
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
falcon_poly_split_fft_avx2(f0, f1, f, logn);
|
||||
#else
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, qn = hn >> 1, u;
|
||||
/* Base case (logn==1, qn==0): single coefficient halves. */
|
||||
f0[0] = f[0];
|
||||
f1[0] = f[hn];
|
||||
for (u = 0; u < qn; u++) {
|
||||
fpr a_re = f[(u << 1) + 0], a_im = f[(u << 1) + 0 + hn];
|
||||
fpr b_re = f[(u << 1) + 1], b_im = f[(u << 1) + 1 + hn];
|
||||
fpr t_re, t_im;
|
||||
FPC_ADD(t_re, t_im, a_re, a_im, b_re, b_im);
|
||||
f0[u] = fpr_half(t_re);
|
||||
f0[u + qn] = fpr_half(t_im);
|
||||
FPC_SUB(t_re, t_im, a_re, a_im, b_re, b_im);
|
||||
FPC_MUL(t_re, t_im, t_re, t_im,
|
||||
falcon_gm_tab[((u + hn) << 1) + 0],
|
||||
fpr_neg(falcon_gm_tab[((u + hn) << 1) + 1]));
|
||||
f1[u] = fpr_half(t_re);
|
||||
f1[u + qn] = fpr_half(t_im);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void falcon_poly_merge_fft(fpr* f, const fpr* f0, const fpr* f1, unsigned logn)
|
||||
{
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
falcon_poly_merge_fft_avx2(f, f0, f1, logn);
|
||||
#else
|
||||
size_t n = (size_t)1 << logn, hn = n >> 1, qn = hn >> 1, u;
|
||||
/* Base case (logn==1, qn==0). */
|
||||
f[0] = f0[0];
|
||||
f[hn] = f1[0];
|
||||
for (u = 0; u < qn; u++) {
|
||||
fpr a_re = f0[u], a_im = f0[u + qn];
|
||||
fpr b_re, b_im, t_re, t_im;
|
||||
FPC_MUL(b_re, b_im, f1[u], f1[u + qn],
|
||||
falcon_gm_tab[((u + hn) << 1) + 0],
|
||||
falcon_gm_tab[((u + hn) << 1) + 1]);
|
||||
FPC_ADD(t_re, t_im, a_re, a_im, b_re, b_im);
|
||||
f[(u << 1) + 0] = t_re;
|
||||
f[(u << 1) + 0 + hn] = t_im;
|
||||
FPC_SUB(t_re, t_im, a_re, a_im, b_re, b_im);
|
||||
f[(u << 1) + 1] = t_re;
|
||||
f[(u << 1) + 1 + hn] = t_im;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
@@ -0,0 +1,352 @@
|
||||
/* wc_falcon_sampler.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* Discrete Gaussian sampler (SamplerZ) for FN-DSA / Falcon signing.
|
||||
*
|
||||
* This is a faithful port of the constant-time reference sampler written by
|
||||
* Thomas Pornin for the Falcon submission (MIT licensed). The identical code
|
||||
* is distributed in PQClean as the gaussian0_sampler / BerExp / sampler trio
|
||||
* (e.g. crypto_sign/falcon-512/clean/sign.c). It has been adapted to wolfSSL
|
||||
* house style (word32/word64/sword64, WOLFSSL_LOCAL linkage) and re-targeted
|
||||
* onto two wolfSSL seams:
|
||||
*
|
||||
* 1. The floating-point seam wolfssl/wolfcrypt/wc_falcon_fpr.h. All real
|
||||
* arithmetic goes through fpr_* (round-to-nearest-even IEEE-754 binary64,
|
||||
* bit-exact and branch-free in the default integer-emulated backend), and
|
||||
* the Bernoulli test uses fpr_expm_p63().
|
||||
* 2. A SHAKE256 randomness stream (wolfssl/wolfcrypt/sha3.h) seeded from a
|
||||
* WC_RNG (wolfssl/wolfcrypt/random.h), replacing the reference's ChaCha20
|
||||
* PRNG. The sampler algorithm is agnostic to the byte source; only the
|
||||
* uniform-byte contract matters for correctness and security.
|
||||
*
|
||||
* CONSTANT TIME / SIDE CHANNELS
|
||||
* - gaussian0() consumes a fixed 9 random bytes and runs a fixed-length,
|
||||
* branch-free table scan (comparison via borrow bits), so its running time
|
||||
* and PRNG consumption are independent of the sampled value.
|
||||
* - BerExp() and sampler() perform no branch or memory access that depends
|
||||
* on the secret center (mu) or secret inverse-sigma (isigma): the only
|
||||
* data-dependent control flow is the rejection-sampling retry loop and
|
||||
* BerExp's lazy byte comparison, both of which depend solely on fresh
|
||||
* uniform random bytes (the rejection probability is deliberately
|
||||
* decorrelated from mu/sigma by the sigma_min scaling factor ccs). This is
|
||||
* the standard Falcon argument; see the reference comments reproduced
|
||||
* below.
|
||||
* - The fpr backend supplies constant-time, value-independent arithmetic, so
|
||||
* no floating-point operation leaks operand values through timing.
|
||||
*
|
||||
* This translation unit is the signing-only sampler and is therefore excluded
|
||||
* from verify-only builds. */
|
||||
|
||||
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_sampler.h>
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_fpr.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
|
||||
#ifdef NO_INLINE
|
||||
#include <wolfssl/wolfcrypt/misc.h>
|
||||
#else
|
||||
#define WOLFSSL_MISC_INCLUDED
|
||||
#include <wolfcrypt/src/misc.c>
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* fpr constants needed by the sampler that are not exported by the seam. */
|
||||
/* */
|
||||
/* These are IEEE-754 binary64 bit patterns, identical to the values used by */
|
||||
/* the Falcon reference (fpr.h). Each has been verified by decoding the bit */
|
||||
/* pattern back to the documented decimal value (shown in the comment). */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* log(2) = 0.6931471805599453 */
|
||||
static const fpr falcon_fpr_log2 = (fpr)4604418534313441775U;
|
||||
/* 1/log(2) = 1.4426950408889634 */
|
||||
static const fpr falcon_fpr_inv_log2 = (fpr)4609176140021203710U;
|
||||
/* 1/(2*sigma0^2) with sigma0 = 1.8205 -> 0.15086504887537272 */
|
||||
static const fpr falcon_fpr_inv_2sqrsigma0 = (fpr)4594603506513722306U;
|
||||
|
||||
/* sigma_min, indexed by logn (degree = 2^logn). These match the Falcon
|
||||
* specification's sigma_min(n) table; entries decode to a smooth monotonic
|
||||
* curve from 1.1165 (n=2) to 1.2983 (n=1024). FN-DSA uses logn 9 and 10:
|
||||
* logn = 9 (FN-DSA-512 / Falcon-512 ) : 1.2778336969128337
|
||||
* logn = 10 (FN-DSA-1024 / Falcon-1024) : 1.298280334344292 */
|
||||
static const fpr falcon_fpr_sigma_min[11] = {
|
||||
(fpr)0U, /* logn 0 : unused */
|
||||
(fpr)4607707126469777035U, /* logn 1 : 1.1165085072 */
|
||||
(fpr)4607777455861499430U, /* logn 2 : 1.1321247692 */
|
||||
(fpr)4607846828256951418U, /* logn 3 : 1.1475285354 */
|
||||
(fpr)4607949175006100261U, /* logn 4 : 1.1702540789 */
|
||||
(fpr)4608049571757433526U, /* logn 5 : 1.1925466358 */
|
||||
(fpr)4608148125896792003U, /* logn 6 : 1.2144300508 */
|
||||
(fpr)4608244935301382692U, /* logn 7 : 1.2359260568 */
|
||||
(fpr)4608340089478362016U, /* logn 8 : 1.2570545284 */
|
||||
(fpr)4608433670533905013U, /* logn 9 : 1.2778336969 */
|
||||
(fpr)4608525754002622308U /* logn 10: 1.2982803343 */
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* SHAKE256 pseudo-random byte stream. */
|
||||
/* */
|
||||
/* Construction: absorb FALCON_PRNG_SEED_LEN fresh bytes from WC_RNG into a */
|
||||
/* SHAKE256 sponge, then squeeze the output in fixed FALCON_PRNG_BLOCKS-block */
|
||||
/* batches. get_u64 reads 8 stream bytes little-endian; get_u8 reads one. */
|
||||
/* The refill is a fixed-size squeeze, hence constant-time; consumption order */
|
||||
/* (and thus how many bytes are discarded at a refill boundary) never */
|
||||
/* depends on a secret. */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Squeeze a fresh batch of blocks into the buffer. Constant-time. */
|
||||
static int falcon_prng_refill(falcon_prng* p)
|
||||
{
|
||||
int ret = wc_Shake256_SqueezeBlocks(&p->shake, p->buf, FALCON_PRNG_BLOCKS);
|
||||
p->ptr = 0;
|
||||
p->len = (ret == 0) ? (word32)FALCON_PRNG_BUFLEN : 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int falcon_prng_init(falcon_prng* p, WC_RNG* rng)
|
||||
{
|
||||
byte seed[FALCON_PRNG_SEED_LEN];
|
||||
int ret;
|
||||
|
||||
if (p == NULL || rng == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
ret = wc_RNG_GenerateBlock(rng, seed, (word32)sizeof(seed));
|
||||
if (ret == 0)
|
||||
ret = wc_InitShake256(&p->shake, NULL, INVALID_DEVID);
|
||||
if (ret == 0)
|
||||
ret = wc_Shake256_Absorb(&p->shake, seed, (word32)sizeof(seed));
|
||||
|
||||
p->ptr = 0;
|
||||
p->len = 0;
|
||||
ForceZero(seed, (word32)sizeof(seed));
|
||||
|
||||
if (ret == 0)
|
||||
ret = falcon_prng_refill(p);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
byte falcon_prng_get_u8(falcon_prng* p)
|
||||
{
|
||||
byte v;
|
||||
|
||||
if (p->ptr + 1U > p->len)
|
||||
(void)falcon_prng_refill(p);
|
||||
v = p->buf[p->ptr];
|
||||
p->ptr += 1U;
|
||||
return v;
|
||||
}
|
||||
|
||||
word64 falcon_prng_get_u64(falcon_prng* p)
|
||||
{
|
||||
word64 v;
|
||||
word32 i;
|
||||
|
||||
if (p->ptr + 8U > p->len)
|
||||
(void)falcon_prng_refill(p);
|
||||
i = p->ptr;
|
||||
v = (word64)p->buf[i + 0]
|
||||
| ((word64)p->buf[i + 1] << 8)
|
||||
| ((word64)p->buf[i + 2] << 16)
|
||||
| ((word64)p->buf[i + 3] << 24)
|
||||
| ((word64)p->buf[i + 4] << 32)
|
||||
| ((word64)p->buf[i + 5] << 40)
|
||||
| ((word64)p->buf[i + 6] << 48)
|
||||
| ((word64)p->buf[i + 7] << 56);
|
||||
p->ptr += 8U;
|
||||
return v;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* gaussian0: base half-Gaussian sampler (centered on 0, sigma0 = 1.8205). */
|
||||
/* */
|
||||
/* Faithful port of Pornin's reference gaussian0_sampler. The RCDT (reverse */
|
||||
/* cumulative distribution table) "dist[]" below is copied VERBATIM from the */
|
||||
/* Falcon reference implementation (18 rows; each row is a 72-bit threshold */
|
||||
/* stored as three 24-bit limbs, most significant limb first). It is the */
|
||||
/* same table that appears in PQClean's */
|
||||
/* crypto_sign/falcon-512/clean/sign.c */
|
||||
/* and in the original Falcon round-3 reference. Do not edit these numbers. */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
int falcon_gaussian0(falcon_prng* p)
|
||||
{
|
||||
/* RCDT for the half-Gaussian of standard deviation sigma0 = 1.8205,
|
||||
* verbatim from the Falcon reference (Thomas Pornin). Each row holds a
|
||||
* 72-bit value as (hi24, mid24, lo24). */
|
||||
static const word32 dist[] = {
|
||||
10745844u, 3068844u, 3741698u,
|
||||
5559083u, 1580863u, 8248194u,
|
||||
2260429u, 13669192u, 2736639u,
|
||||
708981u, 4421575u, 10046180u,
|
||||
169348u, 7122675u, 4136815u,
|
||||
30538u, 13063405u, 7650655u,
|
||||
4132u, 14505003u, 7826148u,
|
||||
417u, 16768101u, 11363290u,
|
||||
31u, 8444042u, 8086568u,
|
||||
1u, 12844466u, 265321u,
|
||||
0u, 1232676u, 13644283u,
|
||||
0u, 38047u, 9111839u,
|
||||
0u, 870u, 6138264u,
|
||||
0u, 14u, 12545723u,
|
||||
0u, 0u, 3104126u,
|
||||
0u, 0u, 28824u,
|
||||
0u, 0u, 198u,
|
||||
0u, 0u, 1u
|
||||
};
|
||||
|
||||
word32 v0, v1, v2, hi;
|
||||
word64 lo;
|
||||
word32 u;
|
||||
int z;
|
||||
|
||||
/* Get a random 72-bit value, into three 24-bit limbs v0..v2. */
|
||||
lo = falcon_prng_get_u64(p);
|
||||
hi = (word32)falcon_prng_get_u8(p);
|
||||
v0 = (word32)lo & 0xFFFFFFu;
|
||||
v1 = (word32)(lo >> 24) & 0xFFFFFFu;
|
||||
v2 = (word32)(lo >> 48) | (hi << 16);
|
||||
|
||||
/* Sampled value is z, the number of leading table thresholds that the
|
||||
* uniform 72-bit value (v0..v2) is strictly less than. Done with borrow
|
||||
* bits, fully branch-free. */
|
||||
z = 0;
|
||||
for (u = 0; u < (word32)((sizeof dist) / sizeof(dist[0])); u += 3) {
|
||||
word32 w0, w1, w2, cc;
|
||||
|
||||
w0 = dist[u + 2];
|
||||
w1 = dist[u + 1];
|
||||
w2 = dist[u + 0];
|
||||
cc = (v0 - w0) >> 31;
|
||||
cc = (v1 - w1 - cc) >> 31;
|
||||
cc = (v2 - w2 - cc) >> 31;
|
||||
z += (int)cc;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* BerExp: Bernoulli test, returns 1 with probability ccs * exp(-x). */
|
||||
/* */
|
||||
/* Faithful port of Pornin's reference BerExp. x >= 0 is guaranteed by the */
|
||||
/* caller. The only data-dependent loop is the lazy 8-bit comparison, whose */
|
||||
/* iteration count depends on fresh random bytes, not on secrets. */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
static int falcon_berexp(falcon_prng* p, fpr x, fpr ccs)
|
||||
{
|
||||
int s, i;
|
||||
fpr r;
|
||||
word32 sw, w;
|
||||
word64 z;
|
||||
|
||||
/* Reduce x modulo log(2): x = s*log(2) + r, with s an integer and
|
||||
* 0 <= r < log(2). Since x >= 0 we can use fpr_trunc (toward zero). */
|
||||
s = (int)fpr_trunc(fpr_mul(x, falcon_fpr_inv_log2));
|
||||
r = fpr_sub(x, fpr_mul(fpr_of((sword64)s), falcon_fpr_log2));
|
||||
|
||||
/* It may happen (rarely) that s >= 64; if so, BerExp would be non-zero
|
||||
* with probability below 2^-64, so we simply saturate s at 63. */
|
||||
sw = (word32)s;
|
||||
sw ^= (sw ^ 63u) & (word32)(0U - ((63u - sw) >> 31));
|
||||
s = (int)sw;
|
||||
|
||||
/* exp(-r), scaled to 2^63, scaled up to 2^64, then >> s to obtain
|
||||
* exp(-x) = 2^-s * exp(-r). The "-1" keeps the value on 64 bits. */
|
||||
z = ((fpr_expm_p63(r, ccs) << 1) - 1) >> s;
|
||||
|
||||
/* Compare exp(-x) against fresh random bytes, 8 bits at a time; the sign
|
||||
* of the difference yields the sampled bit. */
|
||||
i = 64;
|
||||
do {
|
||||
i -= 8;
|
||||
w = (word32)falcon_prng_get_u8(p) - ((word32)(z >> i) & 0xFFu);
|
||||
} while ((w == 0) && (i > 0));
|
||||
|
||||
return (int)(w >> 31);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* sampler (SamplerZ): discrete Gaussian of center mu, std dev 1/isigma. */
|
||||
/* */
|
||||
/* Faithful port of Pornin's reference sampler. ctx is an falcon_sampler_ctx. */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
int falcon_sampler_z(void* ctx, fpr mu, fpr isigma)
|
||||
{
|
||||
falcon_sampler_ctx* spc = (falcon_sampler_ctx*)ctx;
|
||||
int s;
|
||||
fpr r, dss, ccs;
|
||||
|
||||
/* Center is mu = s + r, with s an integer and 0 <= r < 1. */
|
||||
s = (int)fpr_floor(mu);
|
||||
r = fpr_sub(mu, fpr_of((sword64)s));
|
||||
|
||||
/* dss = 1/(2*sigma^2) = 0.5 * isigma^2. */
|
||||
dss = fpr_half(fpr_sqr(isigma));
|
||||
|
||||
/* ccs = sigma_min / sigma = sigma_min * isigma. */
|
||||
ccs = fpr_mul(isigma, spc->sigma_min);
|
||||
|
||||
/* Sample on center r. */
|
||||
for (;;) {
|
||||
int z0, z, b;
|
||||
fpr x;
|
||||
|
||||
/* Half-Gaussian sample, plus a random bit b turning it bimodal:
|
||||
* b = 1 -> use z0+1 (centered on 1), b = 0 -> use -z0 (centered 0). */
|
||||
z0 = falcon_gaussian0(&spc->p);
|
||||
b = (int)falcon_prng_get_u8(&spc->p) & 1;
|
||||
z = b + ((b << 1) - 1) * z0;
|
||||
|
||||
/* Rejection sampling. Keep z with probability exp(-x), where
|
||||
* x = ((z-r)^2)/(2*sigma^2) - (z0^2)/(2*sigma0^2).
|
||||
* The sigma_min scaling in ccs decorrelates the rejection rate from
|
||||
* mu/sigma, keeping the whole sampler constant-time. */
|
||||
x = fpr_mul(fpr_sqr(fpr_sub(fpr_of((sword64)z), r)), dss);
|
||||
x = fpr_sub(x, fpr_mul(fpr_of((sword64)(z0 * z0)),
|
||||
falcon_fpr_inv_2sqrsigma0));
|
||||
if (falcon_berexp(&spc->p, x, ccs)) {
|
||||
/* Rejection was centered on r; the actual center is mu = s + r. */
|
||||
return s + z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Context initialisation. */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
int falcon_sampler_init(falcon_sampler_ctx* spc, int logn, WC_RNG* rng)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (spc == NULL || rng == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
if (logn < 1 || logn > 10)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
spc->sigma_min = falcon_fpr_sigma_min[logn];
|
||||
ret = falcon_prng_init(&spc->p, rng);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
@@ -0,0 +1,682 @@
|
||||
/* wc_falcon_sign.c
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* FN-DSA / Falcon signing orchestration. See wolfssl/wolfcrypt/wc_falcon_sign.h.
|
||||
*
|
||||
* Faithful port of the signature-generation core of the MIT-licensed Falcon
|
||||
* reference implementation sign.c (Thomas Pornin, Falcon Project, 2017-2019):
|
||||
* expand_privkey (B0 basis in FFT + ffLDL tree), ffSampling_fft and
|
||||
* do_sign_tree. The big-integer NTRU completion of G (complete_private) is done
|
||||
* here over the FFT seam. All floating-point work flows through the abstract
|
||||
* fpr_* seam (wc_falcon_fpr / fft / poly); the discrete Gaussian sampler and its
|
||||
* SHAKE256-backed randomness come from wc_falcon_sampler. */
|
||||
|
||||
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_sign.h>
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_fpr.h>
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_fft.h>
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_poly.h>
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_sampler.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
|
||||
#define MKN(logn) ((size_t)1 << (logn))
|
||||
|
||||
#define FALCON_Q 12289
|
||||
|
||||
/* IEEE-754 binary64 bit patterns (the fpr seam carries doubles as word64).
|
||||
* These mirror named constants from the reference fpr.h that are not part of
|
||||
* the public wc_falcon_fpr.h API. fpr_invsqrt2 / fpr_invsqrt8 ARE exported by
|
||||
* the seam and are used directly. */
|
||||
static const fpr fpr_q = 4667981563525332992ULL; /* (double)12289 */
|
||||
static const fpr fpr_inverse_of_q = 4545632735260551042ULL; /* 1/12289 */
|
||||
|
||||
/* 1/sigma, indexed by logn (1..10). Ported from the reference fpr.h. */
|
||||
static const fpr fpr_inv_sigma[] = {
|
||||
0, /* unused */
|
||||
4574611497772390042ULL,
|
||||
4574501679055810265ULL,
|
||||
4574396282908341804ULL,
|
||||
4574245855758572086ULL,
|
||||
4574103865040221165ULL,
|
||||
4573969550563515544ULL,
|
||||
4573842244705920822ULL,
|
||||
4573721358406441454ULL,
|
||||
4573606369665796042ULL,
|
||||
4573496814039276259ULL
|
||||
};
|
||||
|
||||
/* Acceptance bound for the (squared) l2-norm of the signature, indexed by logn
|
||||
* (1..10). Inclusive bounds (= floor(beta^2)). Ported from the reference
|
||||
* common.c l2bound[]. */
|
||||
static const word32 l2bound[] = {
|
||||
0, /* unused */
|
||||
101498u,
|
||||
208714u,
|
||||
428865u,
|
||||
892039u,
|
||||
1852696u,
|
||||
3842630u,
|
||||
7959734u,
|
||||
16468416u,
|
||||
34034726u,
|
||||
70265242u
|
||||
};
|
||||
|
||||
/* ==================================================================== */
|
||||
/* complete_private: recompute G from (f, g, F). */
|
||||
|
||||
/* The keygen NTRU solver produces (F, G) such that f*G - g*F = q, hence
|
||||
* G = (g*F + q) / f. We recompute it over the FFT seam, add the constant q to
|
||||
* the real (lower) half of the FFT representation, divide by f, inverse-FFT and
|
||||
* round to integers. */
|
||||
int falcon_complete_private(sword8* G, const sword8* f, const sword8* g,
|
||||
const sword8* F, unsigned logn)
|
||||
{
|
||||
size_t n, hn, u;
|
||||
fpr* t1;
|
||||
fpr* t2;
|
||||
fpr* t3;
|
||||
int ret = 0;
|
||||
|
||||
if (G == NULL || f == NULL || g == NULL || F == NULL
|
||||
|| logn < 1 || logn > 10) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
n = MKN(logn);
|
||||
hn = n >> 1;
|
||||
|
||||
/* Three working polynomials. */
|
||||
t1 = (fpr*)XMALLOC((size_t)3 * n * sizeof(fpr), NULL,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (t1 == NULL) {
|
||||
return MEMORY_E;
|
||||
}
|
||||
t2 = t1 + n;
|
||||
t3 = t2 + n;
|
||||
|
||||
for (u = 0; u < n; u++) {
|
||||
t1[u] = fpr_of(g[u]); /* g */
|
||||
t2[u] = fpr_of(F[u]); /* F */
|
||||
t3[u] = fpr_of(f[u]); /* f */
|
||||
}
|
||||
falcon_FFT(t1, logn);
|
||||
falcon_FFT(t2, logn);
|
||||
falcon_FFT(t3, logn);
|
||||
|
||||
/* t1 <- g*F. */
|
||||
falcon_poly_mul_fft(t1, t2, logn);
|
||||
|
||||
/* t1 <- g*F + q. The constant polynomial q evaluates to q (a real value) at
|
||||
* every FFT point, so only the real (lower) half is incremented. */
|
||||
for (u = 0; u < hn; u++) {
|
||||
t1[u] = fpr_add(t1[u], fpr_q);
|
||||
}
|
||||
|
||||
/* t1 <- (g*F + q) / f. */
|
||||
falcon_poly_div_fft(t1, t3, logn);
|
||||
|
||||
falcon_iFFT(t1, logn);
|
||||
|
||||
for (u = 0; u < n; u++) {
|
||||
sword64 z;
|
||||
|
||||
z = fpr_rint(t1[u]);
|
||||
if (z < -127 || z > 127) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
break;
|
||||
}
|
||||
G[u] = (sword8)z;
|
||||
}
|
||||
|
||||
/* t1 held the FFT images of the secret basis (g, F, f) and the derived G. */
|
||||
wc_ForceZero(t1, (word32)((size_t)3 * n * sizeof(fpr)));
|
||||
XFREE(t1, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ==================================================================== */
|
||||
/* ffLDL tree construction (expand_privkey). */
|
||||
|
||||
/* Size of the ffLDL tree (number of fpr elements) for polynomials of degree
|
||||
* 2^logn: s(0) = 1, s(logn) = 2^logn + 2*s(logn-1) => (logn+1)*2^logn. */
|
||||
static WC_INLINE unsigned ffLDL_treesize(unsigned logn)
|
||||
{
|
||||
return (logn + 1) << logn;
|
||||
}
|
||||
|
||||
/* Inner ffLDL recursion. Expects the (auto-adjoint, quasicyclic) matrix in
|
||||
* (g0, g1), which are used as modifiable temporaries. tmp[] needs room for at
|
||||
* least one polynomial. */
|
||||
static void ffLDL_fft_inner(fpr* tree, fpr* g0, fpr* g1, unsigned logn,
|
||||
fpr* tmp)
|
||||
{
|
||||
size_t n, hn;
|
||||
|
||||
n = MKN(logn);
|
||||
if (n == 1) {
|
||||
tree[0] = g0[0];
|
||||
return;
|
||||
}
|
||||
hn = n >> 1;
|
||||
|
||||
/* d00 = g0; d11 -> tmp; L[1][0] -> tree. */
|
||||
falcon_poly_LDLmv_fft(tmp, tree, g0, g1, g0, logn);
|
||||
|
||||
/* Split d00 (in g0) and d11 (in tmp), reusing g0/g1 as scratch:
|
||||
* d00 -> g1, g1+hn ; d11 -> g0, g0+hn. */
|
||||
falcon_poly_split_fft(g1, g1 + hn, g0, logn);
|
||||
falcon_poly_split_fft(g0, g0 + hn, tmp, logn);
|
||||
|
||||
ffLDL_fft_inner(tree + n, g1, g1 + hn, logn - 1, tmp);
|
||||
ffLDL_fft_inner(tree + n + ffLDL_treesize(logn - 1),
|
||||
g0, g0 + hn, logn - 1, tmp);
|
||||
}
|
||||
|
||||
/* Compute the ffLDL tree of the auto-adjoint matrix [[g00, adj(g01)],
|
||||
* [g01, g11]] (FFT representation). tmp[] needs room for at least three
|
||||
* polynomials. */
|
||||
static void ffLDL_fft(fpr* tree, const fpr* g00, const fpr* g01,
|
||||
const fpr* g11, unsigned logn, fpr* tmp)
|
||||
{
|
||||
size_t n, hn;
|
||||
fpr* d00;
|
||||
fpr* d11;
|
||||
|
||||
n = MKN(logn);
|
||||
if (n == 1) {
|
||||
tree[0] = g00[0];
|
||||
return;
|
||||
}
|
||||
hn = n >> 1;
|
||||
d00 = tmp;
|
||||
d11 = tmp + n;
|
||||
tmp += n << 1;
|
||||
|
||||
XMEMCPY(d00, g00, n * sizeof(*g00));
|
||||
falcon_poly_LDLmv_fft(d11, tree, g00, g01, g11, logn);
|
||||
|
||||
falcon_poly_split_fft(tmp, tmp + hn, d00, logn);
|
||||
falcon_poly_split_fft(d00, d00 + hn, d11, logn);
|
||||
XMEMCPY(d11, tmp, n * sizeof(*tmp));
|
||||
ffLDL_fft_inner(tree + n, d11, d11 + hn, logn - 1, tmp);
|
||||
ffLDL_fft_inner(tree + n + ffLDL_treesize(logn - 1),
|
||||
d00, d00 + hn, logn - 1, tmp);
|
||||
}
|
||||
|
||||
/* Normalize an ffLDL tree: each leaf x is replaced with sigma/sqrt(x). The leaf
|
||||
* stores the inverse of the spec value, saving a division here and in the
|
||||
* sampler. */
|
||||
static void ffLDL_binary_normalize(fpr* tree, unsigned orig_logn, unsigned logn)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
n = MKN(logn);
|
||||
if (n == 1) {
|
||||
tree[0] = fpr_mul(fpr_sqrt(tree[0]), fpr_inv_sigma[orig_logn]);
|
||||
}
|
||||
else {
|
||||
ffLDL_binary_normalize(tree + n, orig_logn, logn - 1);
|
||||
ffLDL_binary_normalize(tree + n + ffLDL_treesize(logn - 1),
|
||||
orig_logn, logn - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a small-integer polynomial into the fpr representation. */
|
||||
static void smallints_to_fpr(fpr* r, const sword8* t, unsigned logn)
|
||||
{
|
||||
size_t n, u;
|
||||
|
||||
n = MKN(logn);
|
||||
for (u = 0; u < n; u++) {
|
||||
r[u] = fpr_of(t[u]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Expanded-key layout offsets (in fpr elements). */
|
||||
static WC_INLINE size_t skoff_b00(unsigned logn) { (void)logn; return 0; }
|
||||
static WC_INLINE size_t skoff_b01(unsigned logn) { return MKN(logn); }
|
||||
static WC_INLINE size_t skoff_b10(unsigned logn) { return 2 * MKN(logn); }
|
||||
static WC_INLINE size_t skoff_b11(unsigned logn) { return 3 * MKN(logn); }
|
||||
static WC_INLINE size_t skoff_tree(unsigned logn) { return 4 * MKN(logn); }
|
||||
|
||||
int falcon_expand_privkey(fpr* expanded, const sword8* f, const sword8* g,
|
||||
const sword8* F, const sword8* G, unsigned logn)
|
||||
{
|
||||
size_t n;
|
||||
fpr* rf;
|
||||
fpr* rg;
|
||||
fpr* rF;
|
||||
fpr* rG;
|
||||
fpr* b00;
|
||||
fpr* b01;
|
||||
fpr* b10;
|
||||
fpr* b11;
|
||||
fpr* g00;
|
||||
fpr* g01;
|
||||
fpr* g11;
|
||||
fpr* gxx;
|
||||
fpr* tree;
|
||||
fpr* tmp;
|
||||
|
||||
if (expanded == NULL || f == NULL || g == NULL || F == NULL || G == NULL
|
||||
|| logn < 1 || logn > 10) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
n = MKN(logn);
|
||||
|
||||
/* Internal scratch: six polynomials (matches the reference 48*2^logn). */
|
||||
tmp = (fpr*)XMALLOC((size_t)6 * n * sizeof(fpr), NULL,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (tmp == NULL) {
|
||||
return MEMORY_E;
|
||||
}
|
||||
|
||||
b00 = expanded + skoff_b00(logn);
|
||||
b01 = expanded + skoff_b01(logn);
|
||||
b10 = expanded + skoff_b10(logn);
|
||||
b11 = expanded + skoff_b11(logn);
|
||||
tree = expanded + skoff_tree(logn);
|
||||
|
||||
/* B0 = [[g, -f], [G, -F]]. */
|
||||
rf = b01;
|
||||
rg = b00;
|
||||
rF = b11;
|
||||
rG = b10;
|
||||
|
||||
smallints_to_fpr(rf, f, logn);
|
||||
smallints_to_fpr(rg, g, logn);
|
||||
smallints_to_fpr(rF, F, logn);
|
||||
smallints_to_fpr(rG, G, logn);
|
||||
|
||||
falcon_FFT(rf, logn);
|
||||
falcon_FFT(rg, logn);
|
||||
falcon_FFT(rF, logn);
|
||||
falcon_FFT(rG, logn);
|
||||
falcon_poly_neg(rf, logn);
|
||||
falcon_poly_neg(rF, logn);
|
||||
|
||||
/* Gram matrix G = B*B^* (upper triangle: g00, g01, g11). */
|
||||
g00 = tmp;
|
||||
g01 = g00 + n;
|
||||
g11 = g01 + n;
|
||||
gxx = g11 + n;
|
||||
|
||||
XMEMCPY(g00, b00, n * sizeof(*b00));
|
||||
falcon_poly_mulselfadj_fft(g00, logn);
|
||||
XMEMCPY(gxx, b01, n * sizeof(*b01));
|
||||
falcon_poly_mulselfadj_fft(gxx, logn);
|
||||
falcon_poly_add(g00, gxx, logn);
|
||||
|
||||
XMEMCPY(g01, b00, n * sizeof(*b00));
|
||||
falcon_poly_muladj_fft(g01, b10, logn);
|
||||
XMEMCPY(gxx, b01, n * sizeof(*b01));
|
||||
falcon_poly_muladj_fft(gxx, b11, logn);
|
||||
falcon_poly_add(g01, gxx, logn);
|
||||
|
||||
XMEMCPY(g11, b10, n * sizeof(*b10));
|
||||
falcon_poly_mulselfadj_fft(g11, logn);
|
||||
XMEMCPY(gxx, b11, n * sizeof(*b11));
|
||||
falcon_poly_mulselfadj_fft(gxx, logn);
|
||||
falcon_poly_add(g11, gxx, logn);
|
||||
|
||||
/* Falcon tree, then normalization. */
|
||||
ffLDL_fft(tree, g00, g01, g11, logn, gxx);
|
||||
ffLDL_binary_normalize(tree, logn, logn);
|
||||
|
||||
/* tmp held the secret-derived Gram matrix and ffLDL intermediates. */
|
||||
wc_ForceZero(tmp, (word32)((size_t)6 * n * sizeof(fpr)));
|
||||
XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ==================================================================== */
|
||||
/* Fast Fourier sampling. */
|
||||
|
||||
void falcon_ffSampling_fft(falcon_samplerZ samp, void* samp_ctx,
|
||||
fpr* z0, fpr* z1, const fpr* tree, const fpr* t0, const fpr* t1,
|
||||
unsigned logn, fpr* tmp)
|
||||
{
|
||||
size_t n, hn;
|
||||
const fpr* tree0;
|
||||
const fpr* tree1;
|
||||
|
||||
/* logn == 2: inline the last two recursion levels. */
|
||||
if (logn == 2) {
|
||||
fpr x0, x1, y0, y1, w0, w1, w2, w3, sigma;
|
||||
fpr a_re, a_im, b_re, b_im, c_re, c_im;
|
||||
|
||||
tree0 = tree + 4;
|
||||
tree1 = tree + 8;
|
||||
|
||||
a_re = t1[0];
|
||||
a_im = t1[2];
|
||||
b_re = t1[1];
|
||||
b_im = t1[3];
|
||||
c_re = fpr_add(a_re, b_re);
|
||||
c_im = fpr_add(a_im, b_im);
|
||||
w0 = fpr_half(c_re);
|
||||
w1 = fpr_half(c_im);
|
||||
c_re = fpr_sub(a_re, b_re);
|
||||
c_im = fpr_sub(a_im, b_im);
|
||||
w2 = fpr_mul(fpr_add(c_re, c_im), fpr_invsqrt8);
|
||||
w3 = fpr_mul(fpr_sub(c_im, c_re), fpr_invsqrt8);
|
||||
|
||||
x0 = w2;
|
||||
x1 = w3;
|
||||
sigma = tree1[3];
|
||||
w2 = fpr_of(samp(samp_ctx, x0, sigma));
|
||||
w3 = fpr_of(samp(samp_ctx, x1, sigma));
|
||||
a_re = fpr_sub(x0, w2);
|
||||
a_im = fpr_sub(x1, w3);
|
||||
b_re = tree1[0];
|
||||
b_im = tree1[1];
|
||||
c_re = fpr_sub(fpr_mul(a_re, b_re), fpr_mul(a_im, b_im));
|
||||
c_im = fpr_add(fpr_mul(a_re, b_im), fpr_mul(a_im, b_re));
|
||||
x0 = fpr_add(c_re, w0);
|
||||
x1 = fpr_add(c_im, w1);
|
||||
sigma = tree1[2];
|
||||
w0 = fpr_of(samp(samp_ctx, x0, sigma));
|
||||
w1 = fpr_of(samp(samp_ctx, x1, sigma));
|
||||
|
||||
a_re = w0;
|
||||
a_im = w1;
|
||||
b_re = w2;
|
||||
b_im = w3;
|
||||
c_re = fpr_mul(fpr_sub(b_re, b_im), fpr_invsqrt2);
|
||||
c_im = fpr_mul(fpr_add(b_re, b_im), fpr_invsqrt2);
|
||||
z1[0] = w0 = fpr_add(a_re, c_re);
|
||||
z1[2] = w2 = fpr_add(a_im, c_im);
|
||||
z1[1] = w1 = fpr_sub(a_re, c_re);
|
||||
z1[3] = w3 = fpr_sub(a_im, c_im);
|
||||
|
||||
w0 = fpr_sub(t1[0], w0);
|
||||
w1 = fpr_sub(t1[1], w1);
|
||||
w2 = fpr_sub(t1[2], w2);
|
||||
w3 = fpr_sub(t1[3], w3);
|
||||
|
||||
a_re = w0;
|
||||
a_im = w2;
|
||||
b_re = tree[0];
|
||||
b_im = tree[2];
|
||||
w0 = fpr_sub(fpr_mul(a_re, b_re), fpr_mul(a_im, b_im));
|
||||
w2 = fpr_add(fpr_mul(a_re, b_im), fpr_mul(a_im, b_re));
|
||||
a_re = w1;
|
||||
a_im = w3;
|
||||
b_re = tree[1];
|
||||
b_im = tree[3];
|
||||
w1 = fpr_sub(fpr_mul(a_re, b_re), fpr_mul(a_im, b_im));
|
||||
w3 = fpr_add(fpr_mul(a_re, b_im), fpr_mul(a_im, b_re));
|
||||
|
||||
w0 = fpr_add(w0, t0[0]);
|
||||
w1 = fpr_add(w1, t0[1]);
|
||||
w2 = fpr_add(w2, t0[2]);
|
||||
w3 = fpr_add(w3, t0[3]);
|
||||
|
||||
a_re = w0;
|
||||
a_im = w2;
|
||||
b_re = w1;
|
||||
b_im = w3;
|
||||
c_re = fpr_add(a_re, b_re);
|
||||
c_im = fpr_add(a_im, b_im);
|
||||
w0 = fpr_half(c_re);
|
||||
w1 = fpr_half(c_im);
|
||||
c_re = fpr_sub(a_re, b_re);
|
||||
c_im = fpr_sub(a_im, b_im);
|
||||
w2 = fpr_mul(fpr_add(c_re, c_im), fpr_invsqrt8);
|
||||
w3 = fpr_mul(fpr_sub(c_im, c_re), fpr_invsqrt8);
|
||||
|
||||
x0 = w2;
|
||||
x1 = w3;
|
||||
sigma = tree0[3];
|
||||
w2 = y0 = fpr_of(samp(samp_ctx, x0, sigma));
|
||||
w3 = y1 = fpr_of(samp(samp_ctx, x1, sigma));
|
||||
a_re = fpr_sub(x0, y0);
|
||||
a_im = fpr_sub(x1, y1);
|
||||
b_re = tree0[0];
|
||||
b_im = tree0[1];
|
||||
c_re = fpr_sub(fpr_mul(a_re, b_re), fpr_mul(a_im, b_im));
|
||||
c_im = fpr_add(fpr_mul(a_re, b_im), fpr_mul(a_im, b_re));
|
||||
x0 = fpr_add(c_re, w0);
|
||||
x1 = fpr_add(c_im, w1);
|
||||
sigma = tree0[2];
|
||||
w0 = fpr_of(samp(samp_ctx, x0, sigma));
|
||||
w1 = fpr_of(samp(samp_ctx, x1, sigma));
|
||||
|
||||
a_re = w0;
|
||||
a_im = w1;
|
||||
b_re = w2;
|
||||
b_im = w3;
|
||||
c_re = fpr_mul(fpr_sub(b_re, b_im), fpr_invsqrt2);
|
||||
c_im = fpr_mul(fpr_add(b_re, b_im), fpr_invsqrt2);
|
||||
z0[0] = fpr_add(a_re, c_re);
|
||||
z0[2] = fpr_add(a_im, c_im);
|
||||
z0[1] = fpr_sub(a_re, c_re);
|
||||
z0[3] = fpr_sub(a_im, c_im);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* logn == 1: reachable only for the (insecure) smallest degree. */
|
||||
if (logn == 1) {
|
||||
fpr x0, x1, y0, y1, sigma;
|
||||
fpr a_re, a_im, b_re, b_im, c_re, c_im;
|
||||
|
||||
x0 = t1[0];
|
||||
x1 = t1[1];
|
||||
sigma = tree[3];
|
||||
z1[0] = y0 = fpr_of(samp(samp_ctx, x0, sigma));
|
||||
z1[1] = y1 = fpr_of(samp(samp_ctx, x1, sigma));
|
||||
a_re = fpr_sub(x0, y0);
|
||||
a_im = fpr_sub(x1, y1);
|
||||
b_re = tree[0];
|
||||
b_im = tree[1];
|
||||
c_re = fpr_sub(fpr_mul(a_re, b_re), fpr_mul(a_im, b_im));
|
||||
c_im = fpr_add(fpr_mul(a_re, b_im), fpr_mul(a_im, b_re));
|
||||
x0 = fpr_add(c_re, t0[0]);
|
||||
x1 = fpr_add(c_im, t0[1]);
|
||||
sigma = tree[2];
|
||||
z0[0] = fpr_of(samp(samp_ctx, x0, sigma));
|
||||
z0[1] = fpr_of(samp(samp_ctx, x1, sigma));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* General recursive case (logn >= 3). */
|
||||
n = (size_t)1 << logn;
|
||||
hn = n >> 1;
|
||||
tree0 = tree + n;
|
||||
tree1 = tree + n + ffLDL_treesize(logn - 1);
|
||||
|
||||
/* Split t1, recurse (output in tmp), merge back into z1. */
|
||||
falcon_poly_split_fft(z1, z1 + hn, t1, logn);
|
||||
falcon_ffSampling_fft(samp, samp_ctx, tmp, tmp + hn,
|
||||
tree1, z1, z1 + hn, logn - 1, tmp + n);
|
||||
falcon_poly_merge_fft(z1, tmp, tmp + hn, logn);
|
||||
|
||||
/* tb0 = t0 + (t1 - z1) * L, ending up in tmp[]. */
|
||||
XMEMCPY(tmp, t1, n * sizeof(*t1));
|
||||
falcon_poly_sub(tmp, z1, logn);
|
||||
falcon_poly_mul_fft(tmp, tree, logn);
|
||||
falcon_poly_add(tmp, t0, logn);
|
||||
|
||||
/* Second recursion. */
|
||||
falcon_poly_split_fft(z0, z0 + hn, tmp, logn);
|
||||
falcon_ffSampling_fft(samp, samp_ctx, tmp, tmp + hn,
|
||||
tree0, z0, z0 + hn, logn - 1, tmp + n);
|
||||
falcon_poly_merge_fft(z0, tmp, tmp + hn, logn);
|
||||
}
|
||||
|
||||
/* ==================================================================== */
|
||||
/* do_sign_tree / sign_core. */
|
||||
|
||||
/* is_short_half: squared l2-norm of (s1, s2) where the s1 partial sum (sqn) is
|
||||
* already accumulated and saturates to 2^32-1. Returns 1 if within bound. */
|
||||
static int is_short_half(word32 sqn, const sword16* s2, unsigned logn)
|
||||
{
|
||||
size_t n, u;
|
||||
word32 ng;
|
||||
|
||||
n = (size_t)1 << logn;
|
||||
ng = (word32)(0 - (sqn >> 31));
|
||||
for (u = 0; u < n; u++) {
|
||||
sword32 z;
|
||||
|
||||
z = s2[u];
|
||||
sqn += (word32)(z * z);
|
||||
ng |= sqn;
|
||||
}
|
||||
sqn |= (word32)(0 - (ng >> 31));
|
||||
|
||||
return sqn <= l2bound[logn];
|
||||
}
|
||||
|
||||
/* Single signing attempt over the expanded key. Returns 1 if the produced
|
||||
* (s1, s2) is short enough (s2 written), 0 if the caller should retry. tmp[]
|
||||
* needs room for six polynomials. */
|
||||
static int do_sign_tree_once(falcon_samplerZ samp, void* samp_ctx, sword16* s2,
|
||||
const fpr* expanded, const word16* hm, unsigned logn, fpr* tmp)
|
||||
{
|
||||
size_t n, u;
|
||||
fpr* t0;
|
||||
fpr* t1;
|
||||
fpr* tx;
|
||||
fpr* ty;
|
||||
const fpr* b00;
|
||||
const fpr* b01;
|
||||
const fpr* b10;
|
||||
const fpr* b11;
|
||||
const fpr* tree;
|
||||
fpr ni;
|
||||
word32 sqn, ng;
|
||||
sword16* s1tmp;
|
||||
sword16* s2tmp;
|
||||
|
||||
n = MKN(logn);
|
||||
t0 = tmp;
|
||||
t1 = t0 + n;
|
||||
b00 = expanded + skoff_b00(logn);
|
||||
b01 = expanded + skoff_b01(logn);
|
||||
b10 = expanded + skoff_b10(logn);
|
||||
b11 = expanded + skoff_b11(logn);
|
||||
tree = expanded + skoff_tree(logn);
|
||||
|
||||
/* Target vector [hm, 0]. */
|
||||
for (u = 0; u < n; u++) {
|
||||
t0[u] = fpr_of(hm[u]);
|
||||
}
|
||||
|
||||
/* Apply the basis to obtain the real target (after q-normalization). */
|
||||
falcon_FFT(t0, logn);
|
||||
ni = fpr_inverse_of_q;
|
||||
XMEMCPY(t1, t0, n * sizeof(*t0));
|
||||
falcon_poly_mul_fft(t1, b01, logn);
|
||||
falcon_poly_mulconst(t1, fpr_neg(ni), logn);
|
||||
falcon_poly_mul_fft(t0, b11, logn);
|
||||
falcon_poly_mulconst(t0, ni, logn);
|
||||
|
||||
tx = t1 + n;
|
||||
ty = tx + n;
|
||||
|
||||
/* Sampling; output written to [tx, ty]. */
|
||||
falcon_ffSampling_fft(samp, samp_ctx, tx, ty, tree, t0, t1, logn, ty + n);
|
||||
|
||||
/* Lattice point corresponding to that short vector. */
|
||||
XMEMCPY(t0, tx, n * sizeof(*tx));
|
||||
XMEMCPY(t1, ty, n * sizeof(*ty));
|
||||
falcon_poly_mul_fft(tx, b00, logn);
|
||||
falcon_poly_mul_fft(ty, b10, logn);
|
||||
falcon_poly_add(tx, ty, logn);
|
||||
XMEMCPY(ty, t0, n * sizeof(*t0));
|
||||
falcon_poly_mul_fft(ty, b01, logn);
|
||||
|
||||
XMEMCPY(t0, tx, n * sizeof(*tx));
|
||||
falcon_poly_mul_fft(t1, b11, logn);
|
||||
falcon_poly_add(t1, ty, logn);
|
||||
|
||||
falcon_iFFT(t0, logn);
|
||||
falcon_iFFT(t1, logn);
|
||||
|
||||
/* s1 = hm - round(t0); accumulate squared norm with saturation. */
|
||||
s1tmp = (sword16*)tx;
|
||||
sqn = 0;
|
||||
ng = 0;
|
||||
for (u = 0; u < n; u++) {
|
||||
sword32 z;
|
||||
|
||||
z = (sword32)hm[u] - (sword32)fpr_rint(t0[u]);
|
||||
sqn += (word32)(z * z);
|
||||
ng |= sqn;
|
||||
s1tmp[u] = (sword16)z;
|
||||
}
|
||||
sqn |= (word32)(0 - (ng >> 31));
|
||||
|
||||
/* s2 = -round(t1) (written into tmp; never into s2[] until accepted, so a
|
||||
* retry preserves hm[]). */
|
||||
s2tmp = (sword16*)tmp;
|
||||
for (u = 0; u < n; u++) {
|
||||
s2tmp[u] = (sword16)(0 - fpr_rint(t1[u]));
|
||||
}
|
||||
if (is_short_half(sqn, s2tmp, logn)) {
|
||||
XMEMCPY(s2, s2tmp, n * sizeof(*s2));
|
||||
XMEMCPY(tmp, s1tmp, n * sizeof(*s1tmp));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int falcon_do_sign_tree(falcon_samplerZ samp, void* samp_ctx, sword16* s2,
|
||||
const fpr* expanded, const word16* hm, unsigned logn, fpr* tmp)
|
||||
{
|
||||
if (samp == NULL || s2 == NULL || expanded == NULL || hm == NULL
|
||||
|| tmp == NULL || logn < 1 || logn > 10) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* Loop until the candidate (s1, s2) is short enough. With degrees 512 and
|
||||
* 1024 a restart is very rare. */
|
||||
for (;;) {
|
||||
if (do_sign_tree_once(samp, samp_ctx, s2, expanded, hm, logn, tmp)) {
|
||||
return 0;
|
||||
}
|
||||
#ifdef WOLFSSL_FALCON_SIGN_STATS
|
||||
/* Optional instrumentation for test harnesses: counts the rare
|
||||
* ffSampling restarts. Not compiled into production builds. */
|
||||
extern unsigned long falcon_sign_restart_count;
|
||||
falcon_sign_restart_count++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int falcon_sign_core(falcon_sampler_ctx* spc, const fpr* expanded,
|
||||
const word16* c, sword16* s2, fpr* tmp, unsigned logn)
|
||||
{
|
||||
if (spc == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
return falcon_do_sign_tree(falcon_sampler_z, spc, s2, expanded, c, logn, tmp);
|
||||
}
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
@@ -403,6 +403,9 @@ static const byte const_byte_array[] = "A+Gd\0\0\0";
|
||||
#ifdef WOLFSSL_HAVE_MLDSA
|
||||
#include <wolfssl/wolfcrypt/wc_mldsa.h>
|
||||
#endif
|
||||
#ifdef HAVE_FALCON
|
||||
#include <wolfssl/wolfcrypt/falcon.h>
|
||||
#endif
|
||||
#if defined(WOLFSSL_HAVE_XMSS)
|
||||
#include <wolfssl/wolfcrypt/wc_xmss.h>
|
||||
#endif
|
||||
@@ -991,6 +994,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t scrypt_test(void);
|
||||
#ifdef WOLFSSL_HAVE_MLDSA
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mldsa_test(void);
|
||||
#endif
|
||||
#ifdef HAVE_FALCON
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t falcon_test(void);
|
||||
#endif
|
||||
#if defined(WOLFSSL_HAVE_XMSS)
|
||||
#if !defined(WOLFSSL_SMALL_STACK) && WOLFSSL_XMSS_MIN_HEIGHT <= 10
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test_verify_only(void);
|
||||
@@ -3237,6 +3243,15 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
|
||||
PRIVATE_KEY_LOCK();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FALCON
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
if ( (ret = falcon_test()) != 0)
|
||||
TEST_FAIL("Falcon test failed!\n", ret);
|
||||
else
|
||||
TEST_PASS("Falcon test passed!\n");
|
||||
PRIVATE_KEY_LOCK();
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_HAVE_XMSS)
|
||||
#if !defined(WOLFSSL_SMALL_STACK) && WOLFSSL_XMSS_MIN_HEIGHT <= 10
|
||||
if ( (ret = xmss_test_verify_only()) != 0)
|
||||
@@ -57669,8 +57684,550 @@ static wc_test_ret_t mldsa_decode_test(void)
|
||||
}
|
||||
#endif /* (WOLFSSL_MLDSA_PUBLIC_KEY && !WOLFSSL_MLDSA_NO_VERIFY) ||
|
||||
* (WOLFSSL_MLDSA_PRIVATE_KEY && !WOLFSSL_MLDSA_NO_SIGN) */
|
||||
#endif /* WOLFSSL_HAVE_MLDSA - FN-DSA test below is independent of ML-DSA */
|
||||
|
||||
|
||||
#ifdef HAVE_FALCON
|
||||
|
||||
/* Differential FN-DSA (Falcon) verify test.
|
||||
*
|
||||
* The public keys and signatures below are KNOWN-ANSWER VECTORS that were
|
||||
* generated with the EXISTING liboqs Falcon implementation
|
||||
* (OQS_SIG_alg_falcon_512 / OQS_SIG_alg_falcon_1024, the non-padded
|
||||
* "compressed" encoding, which matches wolfSSL's liboqs Falcon port) over the
|
||||
* message string FALCON_KAT_MSG. They are verified here by the NATIVE
|
||||
* wc_falcon_verify_msg(), making this a true differential test: a signature
|
||||
* produced by the old liboqs path must be accepted by the new native verifier
|
||||
* (res == 1), and a single-byte corruption must be rejected (res != 1).
|
||||
*
|
||||
* The native public-key encoding is identical to Falcon's: one header byte
|
||||
* (0x09 for level 1 / 0x0A for level 5) followed by the 14-bit packed h. The
|
||||
* compressed signature begins with header byte 0x39 (level 1) / 0x3A
|
||||
* (level 5).
|
||||
*
|
||||
* To regenerate these vectors against liboqs (e.g. when liboqs is available):
|
||||
* OQS_SIG *s = OQS_SIG_new(OQS_SIG_alg_falcon_512);
|
||||
* OQS_SIG_keypair(s, pk, sk);
|
||||
* OQS_SIG_sign(s, sig, &siglen, (const uint8_t*)FALCON_KAT_MSG,
|
||||
* strlen(FALCON_KAT_MSG), sk);
|
||||
* then drop pk / sig / siglen into the arrays below. (liboqs >= 0.11 API.)
|
||||
*/
|
||||
|
||||
#define FALCON_KAT_MSG "wolfSSL FN-DSA differential KAT"
|
||||
|
||||
static const byte FALCON512_pk[] = {
|
||||
0x09,0x8d,0x15,0xc5,0x31,0x5b,0xa1,0x8a,0x92,0x2d,0x93,0x81,
|
||||
0x26,0x93,0xa7,0x05,0x1a,0xf2,0x92,0x99,0x0c,0x67,0x77,0x30,
|
||||
0xdf,0x03,0xb9,0x21,0xbe,0xa1,0x06,0x2e,0x81,0x20,0x6b,0x27,
|
||||
0x5c,0x7a,0x6d,0x9b,0x1d,0x19,0xb6,0xbc,0x65,0x7c,0xe5,0x02,
|
||||
0x0a,0xdc,0xa1,0xb9,0x87,0x56,0x6e,0x29,0x0a,0x14,0x85,0x10,
|
||||
0x80,0xc9,0xc8,0x1b,0x48,0x4c,0x7a,0x28,0x74,0xdc,0x8c,0x38,
|
||||
0xf8,0x4c,0x8a,0x53,0xe9,0x34,0x03,0x76,0xcc,0x88,0x55,0x2c,
|
||||
0x48,0x00,0x55,0x3e,0x78,0x0c,0xa4,0xf5,0x3b,0x5d,0xc9,0x77,
|
||||
0xd9,0xd7,0xec,0xa8,0x28,0xb0,0x4a,0xdb,0xaa,0xa4,0x88,0xcd,
|
||||
0xde,0xe2,0xc3,0xaf,0xa8,0x15,0x09,0x64,0x9a,0x8f,0x5d,0x37,
|
||||
0x51,0x26,0xce,0xd3,0x06,0x0c,0x9f,0x35,0x56,0x1f,0x70,0x67,
|
||||
0x6e,0xf3,0x60,0x90,0x2c,0x54,0x91,0x1c,0xbd,0x3d,0x95,0xa8,
|
||||
0x54,0x3b,0xc2,0x0e,0x6f,0x90,0x80,0xd7,0xcd,0x03,0x3d,0xa8,
|
||||
0x05,0x09,0x54,0xab,0xa5,0xec,0x1b,0xe2,0xe7,0x39,0x2c,0x0d,
|
||||
0xc3,0x53,0xe0,0x34,0xea,0x92,0x1c,0xae,0x2e,0x91,0x68,0x74,
|
||||
0x82,0xe0,0xdf,0x5d,0x18,0xb8,0xe2,0x47,0xcc,0x84,0x35,0xc4,
|
||||
0xf7,0x08,0xc7,0x00,0xe8,0xb9,0x64,0x8d,0xe9,0x1b,0xcc,0x2b,
|
||||
0x28,0x78,0x7a,0x65,0x18,0x67,0x0b,0xb1,0xa9,0x10,0x40,0x8d,
|
||||
0x1f,0xc5,0x4c,0x64,0xe7,0x99,0xf9,0x0d,0x9f,0xb3,0x71,0x2a,
|
||||
0xf5,0x2a,0x89,0xd0,0xb2,0xf6,0x80,0x61,0x37,0x50,0x5d,0x16,
|
||||
0x70,0x82,0x73,0x8e,0x9d,0x59,0x88,0xe9,0x84,0xf7,0x32,0x93,
|
||||
0xfd,0x24,0x61,0x94,0x2b,0xc6,0xdf,0xf7,0x3b,0x5e,0x05,0x88,
|
||||
0xc0,0x48,0x2a,0x7c,0x40,0x8a,0x03,0x8f,0x8b,0x3b,0x85,0x7d,
|
||||
0xe0,0xbb,0x73,0xaf,0xbb,0x4b,0xe9,0xe5,0x76,0x7a,0xd0,0x2c,
|
||||
0x6a,0xb9,0x60,0x19,0xf7,0xa3,0xc0,0xb0,0x64,0x45,0x71,0xb3,
|
||||
0x6d,0xdf,0x97,0x59,0x4c,0xc2,0xab,0x0c,0x5b,0x29,0xe1,0x52,
|
||||
0x21,0x0e,0xcf,0xda,0x4e,0x55,0xc7,0x87,0x39,0x9b,0x0f,0x54,
|
||||
0x88,0xc4,0xbb,0xe7,0x5b,0xcb,0xb6,0x10,0x80,0x5a,0x16,0x96,
|
||||
0x8b,0x41,0x9a,0x9a,0x41,0x76,0x88,0x2e,0x02,0xa1,0x83,0x78,
|
||||
0x19,0x67,0xb2,0x07,0x11,0x55,0x56,0xd3,0x5b,0xea,0x3d,0x19,
|
||||
0xf9,0x81,0xd8,0xe9,0xa4,0x91,0x94,0x06,0x70,0xb9,0x95,0xbd,
|
||||
0x7e,0x68,0x05,0x82,0x81,0x8f,0x94,0xab,0x36,0xe8,0xa2,0x4a,
|
||||
0x02,0x6a,0x33,0x6e,0x00,0x87,0x44,0xe8,0xdc,0xa1,0xee,0xf8,
|
||||
0x00,0x4d,0xaa,0x81,0x99,0x8e,0x46,0xe8,0x36,0x25,0x0b,0x3e,
|
||||
0xbe,0xd9,0x03,0x38,0x14,0x62,0x8a,0xb5,0x3e,0x79,0xef,0x69,
|
||||
0x94,0x41,0x41,0xcf,0x16,0x84,0xa9,0xba,0x0f,0x5a,0xd6,0x48,
|
||||
0xef,0x57,0x0e,0x76,0xc5,0x89,0xf1,0x71,0x29,0x5f,0xb5,0xe2,
|
||||
0x09,0x14,0xc3,0xd2,0x3f,0xb1,0xb9,0x41,0xc7,0x91,0xa5,0xda,
|
||||
0x54,0xb4,0x43,0xba,0xa5,0x50,0xf2,0xa1,0x8d,0x0a,0x59,0x18,
|
||||
0x1e,0xd1,0x58,0x76,0x1c,0x29,0xfa,0x04,0x8c,0x23,0x66,0xee,
|
||||
0x8b,0xe1,0x11,0x46,0x0c,0x89,0xe3,0x80,0x56,0xa5,0x70,0xa6,
|
||||
0x7c,0xf1,0x73,0xf1,0x13,0xe4,0x83,0x25,0xe7,0xea,0xd2,0x8c,
|
||||
0x39,0x36,0xd6,0x5e,0x4b,0x82,0x5a,0x5e,0xa5,0x0c,0xce,0xaa,
|
||||
0xb7,0x4e,0x01,0x9b,0x46,0xde,0x81,0xd3,0x2f,0xf7,0xbd,0x60,
|
||||
0x20,0x77,0xac,0xca,0x62,0x41,0x80,0x1a,0x72,0xe3,0x0d,0x49,
|
||||
0x74,0x16,0xff,0xe7,0xb0,0x65,0xb3,0xa2,0xda,0x6d,0xe1,0x34,
|
||||
0x4f,0x0e,0xa7,0xb2,0xdf,0xf2,0x9d,0x6d,0xe3,0x78,0x36,0xe9,
|
||||
0x43,0x7e,0x0b,0xab,0x0e,0xa8,0xe3,0xf1,0x77,0x27,0x78,0x9d,
|
||||
0xfd,0x43,0x44,0xdd,0xc8,0x3b,0x1f,0x71,0xc6,0xe5,0xef,0xe2,
|
||||
0x8c,0x7e,0xc6,0x63,0x8b,0x29,0x24,0x34,0x6a,0xcd,0xd8,0xf4,
|
||||
0xa8,0x5b,0x7b,0xa6,0x38,0x8f,0x3b,0x59,0x8a,0xff,0xb4,0xbc,
|
||||
0xd6,0xd5,0x0a,0xc0,0xc3,0x7c,0x40,0x80,0x78,0x31,0x41,0x17,
|
||||
0x23,0xde,0x28,0xe2,0x79,0x2d,0xeb,0x7b,0xee,0xf6,0x65,0xff,
|
||||
0xe5,0xf7,0x45,0x86,0x13,0xeb,0xf1,0xc3,0xd8,0x82,0x3c,0xcb,
|
||||
0x44,0xc9,0xde,0xcc,0x36,0x2d,0x68,0x85,0x64,0x66,0x74,0x81,
|
||||
0xc0,0x21,0xc2,0xe0,0x53,0xa9,0x05,0xae,0xec,0x05,0x86,0xe6,
|
||||
0x34,0x88,0xea,0x5e,0x5a,0x6a,0xc2,0xdf,0x51,0x65,0x5c,0x80,
|
||||
0xc5,0xce,0xe9,0xb8,0x4a,0x88,0x08,0x10,0x56,0xe5,0x29,0xb2,
|
||||
0x44,0x69,0x73,0x4c,0x4d,0x04,0x21,0xf6,0xc0,0x8b,0xed,0xec,
|
||||
0x80,0x84,0x08,0xbb,0x6c,0xe0,0xef,0xbb,0xce,0xd8,0x12,0x9a,
|
||||
0x8d,0x1a,0x54,0x41,0xba,0x63,0xc9,0xa8,0xfe,0x97,0x72,0x2c,
|
||||
0xe9,0xb7,0xe4,0xa4,0x3e,0xda,0x73,0xa1,0xcc,0x86,0x40,0xb8,
|
||||
0xae,0x7d,0x91,0x52,0x40,0xe7,0x1b,0x3d,0x0f,0xeb,0x7a,0x4e,
|
||||
0x0d,0x36,0x0c,0x0d,0xf2,0x00,0xaf,0x08,0x70,0xa5,0x6d,0xa2,
|
||||
0xf5,0x0b,0xc3,0x51,0x70,0x34,0xc6,0x1d,0x16,0x00,0x5c,0xb6,
|
||||
0x65,0x71,0x9e,0x8d,0x47,0x35,0x6d,0xae,0xfa,0x6d,0x91,0x05,
|
||||
0x26,0xfd,0x89,0x45,0x14,0x13,0x90,0x3a,0xd8,0xb4,0x11,0xd1,
|
||||
0xef,0x57,0x63,0x62,0xea,0xc6,0x6c,0x2c,0xf9,0x0b,0x9c,0xa8,
|
||||
0xa1,0x01,0x40,0x46,0x87,0x2e,0xe0,0xdb,0x90,0x6f,0x4b,0x10,
|
||||
0xf2,0x95,0xd1,0x3e,0xdb,0xfd,0x6b,0x0c,0xcc,0x7b,0x73,0x5f,
|
||||
0x2c,0x98,0x8e,0xb0,0x35,0x7c,0xaa,0x99,0x72,0xf9,0x3d,0x64,
|
||||
0xc4,0x8f,0x09,0x5f,0xbc,0xeb,0x02,0xb2,0x22,0xff,0x08,0xf8,
|
||||
0x8a,0xa3,0x0d,0x0e,0xa0,0xb6,0xec,0x89,0x36,0xbf,0x8d,0x8e,
|
||||
0x0f,0xcd,0x3a,0x76,0xd5,0x19,0xe3,0xa8,0xe6,0x73,0x01,0x47,
|
||||
0x55,0x05,0x09,0xb5,0x51,0xda,0x10,0x4f,0xd9,
|
||||
};
|
||||
static const byte FALCON512_sig[] = {
|
||||
0x39,0xf9,0x52,0x91,0x34,0x81,0x6f,0x8a,0xd6,0x02,0x62,0x7b,
|
||||
0x16,0xa3,0x0f,0x19,0xee,0x36,0x30,0x9a,0xe3,0xbd,0x02,0xf7,
|
||||
0x12,0x4c,0x04,0xb7,0x45,0x2b,0x55,0x65,0xb8,0x7a,0x24,0xca,
|
||||
0x5b,0xb7,0xde,0xe1,0x86,0x89,0x69,0x90,0xb6,0x12,0x34,0xe2,
|
||||
0xe2,0x62,0x6d,0x00,0x7a,0x2e,0x75,0x86,0xb6,0x98,0x37,0x69,
|
||||
0x44,0x58,0xb7,0xab,0xf4,0xa9,0xd6,0x38,0x6f,0x92,0x7e,0x6c,
|
||||
0x0d,0xcc,0x9c,0x20,0x25,0x45,0x84,0xc5,0x34,0x97,0x94,0xd5,
|
||||
0xb6,0xa5,0xf4,0x1e,0xac,0x41,0x6b,0xad,0xe4,0x13,0x47,0x01,
|
||||
0x42,0x86,0xd1,0x50,0xf7,0x09,0x41,0x75,0x69,0x90,0xaf,0xde,
|
||||
0xd7,0x6b,0xeb,0xd0,0x75,0x77,0x78,0x5a,0xfc,0xb9,0xe3,0xa4,
|
||||
0x7b,0x6a,0x28,0x67,0x1e,0x56,0xca,0x97,0x71,0x06,0x92,0x1a,
|
||||
0x5d,0x3e,0x42,0xa7,0x63,0xef,0x2f,0xc6,0x40,0xf1,0x6b,0xb1,
|
||||
0x1a,0x14,0x2d,0x72,0xac,0x37,0x50,0x05,0xad,0xc1,0xc1,0x74,
|
||||
0x44,0xc6,0xa7,0xe9,0x62,0x13,0xa2,0x03,0x02,0x67,0x52,0x08,
|
||||
0x9c,0x9d,0x65,0xb4,0x4b,0x05,0xe4,0xd3,0x43,0x3a,0x91,0x66,
|
||||
0xf7,0x29,0x13,0x4a,0xfd,0x94,0x8c,0xfa,0x84,0xeb,0xe5,0xd2,
|
||||
0xd8,0x71,0x91,0x42,0xd9,0xf7,0xae,0x1d,0x88,0x70,0x74,0x33,
|
||||
0xca,0xae,0xda,0x15,0xc1,0xb7,0xeb,0x11,0x5d,0x39,0x5e,0xc3,
|
||||
0x76,0x9c,0x3a,0x52,0x1b,0x19,0xe3,0x70,0xdb,0xd2,0x3e,0xe0,
|
||||
0x47,0x4d,0x74,0x33,0xa5,0xc3,0x5d,0xfc,0x76,0x34,0x2b,0x13,
|
||||
0x50,0xe6,0x9d,0xb8,0xae,0x44,0x23,0x42,0x95,0x27,0xaf,0x48,
|
||||
0x9b,0x15,0x11,0x8e,0x13,0xeb,0x36,0xe5,0xe0,0x3d,0xff,0x16,
|
||||
0x47,0x51,0x20,0xf1,0x4e,0x9a,0x2a,0x22,0x01,0xbd,0xf1,0x40,
|
||||
0x66,0x74,0xd6,0x52,0x33,0x05,0xb3,0xfe,0xd0,0x5c,0xb7,0x85,
|
||||
0xc1,0xfb,0x20,0x1e,0x84,0xa2,0x6b,0xcf,0x9b,0xcc,0x8e,0x13,
|
||||
0x4d,0xa9,0x44,0x92,0x06,0x9c,0x9b,0x3c,0xf3,0x83,0x19,0x58,
|
||||
0xab,0xe5,0x16,0x4f,0xe2,0x41,0x42,0xd9,0xbc,0xf5,0xa3,0x3b,
|
||||
0x4e,0x9a,0x5d,0xaf,0x77,0x5d,0xcf,0x9f,0xd2,0x47,0x8c,0x75,
|
||||
0xb6,0x3d,0x84,0x68,0x36,0xe5,0x15,0x33,0x4c,0xab,0x5a,0x07,
|
||||
0xa3,0x93,0x6d,0x51,0xc8,0x29,0xc9,0xe1,0xa5,0x57,0x44,0x9a,
|
||||
0x99,0xab,0x6c,0x5b,0x6e,0xa3,0x26,0xcb,0xea,0xe1,0x0a,0x4a,
|
||||
0x40,0xb3,0x69,0xbb,0xd6,0xc2,0xcd,0x64,0x35,0x08,0xe9,0x92,
|
||||
0x61,0x67,0x9f,0x2f,0xc5,0x28,0xc2,0xa0,0x04,0xc9,0xd7,0xf8,
|
||||
0xd2,0x2b,0x50,0xd6,0x9b,0xf7,0xae,0xf3,0x67,0xd4,0x6a,0x4f,
|
||||
0x89,0xb4,0x70,0x23,0xe4,0x19,0x97,0x5d,0x86,0xc6,0x2b,0x8f,
|
||||
0x58,0xd8,0xd6,0x3d,0x59,0x39,0x86,0xa1,0x28,0xc4,0x2b,0xae,
|
||||
0xf2,0x6d,0x0d,0x76,0x25,0xdc,0x55,0x06,0x73,0x9a,0x27,0xf5,
|
||||
0x34,0x7f,0xcf,0x9a,0x7a,0xfd,0x1e,0xa5,0xb9,0x66,0x8c,0x9e,
|
||||
0x78,0x8f,0x9e,0x64,0xcf,0xc8,0xf7,0x73,0x12,0x8a,0x82,0xb3,
|
||||
0x67,0x03,0xd9,0x1d,0x71,0x63,0x3c,0x5f,0x5e,0x9b,0x2f,0xaf,
|
||||
0xa1,0x41,0x95,0x47,0x0f,0xff,0x18,0x3e,0xd1,0x09,0x2f,0x23,
|
||||
0x4e,0x8f,0x4d,0x9b,0xa7,0xe4,0xad,0x47,0xf5,0x17,0xbf,0x86,
|
||||
0x89,0xd2,0x50,0x6a,0x87,0xdd,0x9e,0xfe,0xf4,0xd0,0xd1,0xa0,
|
||||
0xcf,0x4f,0x21,0x8c,0x41,0xc5,0xd1,0xa8,0x35,0x9a,0xbe,0xab,
|
||||
0x95,0x8d,0x5d,0x6d,0x2f,0xbc,0x78,0x8c,0x41,0xee,0xac,0x0c,
|
||||
0x01,0x48,0x7e,0xd2,0x35,0xba,0x02,0xcc,0x62,0xf9,0xed,0x39,
|
||||
0x23,0xe2,0x61,0x2d,0xd3,0x61,0x7d,0x43,0x21,0x3a,0x03,0x9c,
|
||||
0x4b,0x78,0x08,0x2b,0x31,0x5b,0xe8,0xdb,0x4d,0xcb,0xb8,0x8c,
|
||||
0x54,0xa1,0x58,0xf8,0x2f,0x15,0x64,0x71,0xcc,0x5f,0x41,0x61,
|
||||
0xd7,0x44,0xb0,0xfb,0x46,0xa8,0xfd,0xe4,0xfc,0xad,0x0c,0x0f,
|
||||
0xef,0xa8,0x6e,0xb4,0x97,0xfc,0xc2,0x82,0x96,0x40,0x0f,0x1d,
|
||||
0xd1,0xdf,0x41,0xe0,0x14,0x8f,0x8c,0x22,0x41,0x03,0x5b,0xe6,
|
||||
0xc8,0x8c,0x71,0xdc,0xf5,0xf6,0xd5,0xa4,0xc3,0x00,0xc3,0x45,
|
||||
0x1e,0x0f,0x15,0x1d,0xc2,0x70,0x76,0x58,0xf3,0x61,0xa7,0x96,
|
||||
0x4b,0x58,0x68,0xa4,0x13,0xbf,
|
||||
};
|
||||
#define FALCON512_SIGLEN 654
|
||||
|
||||
/* msg="wolfSSL FN-DSA differential KAT" */
|
||||
static const byte FALCON1024_pk[] = {
|
||||
0x0a,0x19,0x74,0x2e,0x24,0x91,0x1a,0xb4,0x48,0x34,0x71,0xc7,
|
||||
0xf4,0xad,0x90,0x41,0xea,0x21,0xf9,0xf9,0x1e,0xc5,0x86,0xc5,
|
||||
0x15,0xfa,0x7b,0x5c,0xe5,0x8f,0x72,0x3f,0x76,0xcc,0x44,0xe1,
|
||||
0x67,0x9a,0x9c,0xf8,0x94,0xec,0xa4,0x14,0xf8,0x32,0x10,0xc9,
|
||||
0x94,0x0a,0x60,0x71,0x91,0x80,0x75,0x51,0x1f,0x9b,0x65,0xcb,
|
||||
0x58,0x44,0x1c,0x46,0x22,0x95,0x3d,0x09,0xbd,0x1a,0xa2,0xa7,
|
||||
0xd8,0x13,0x64,0x87,0xa7,0x3a,0x66,0xcd,0x9c,0x34,0xf6,0xd0,
|
||||
0xc0,0x01,0x75,0x8d,0xf3,0xe6,0x53,0xbb,0x7d,0x85,0xc9,0x72,
|
||||
0x3a,0xe6,0xa6,0x19,0xdc,0xdd,0xd1,0xfc,0x2f,0xa7,0x11,0xc9,
|
||||
0xdf,0xfb,0x35,0x99,0x20,0xa9,0x32,0x53,0xf9,0xa7,0x20,0xcd,
|
||||
0x1b,0x58,0x7f,0x86,0xdc,0xc2,0xcf,0x7b,0x89,0x26,0x60,0x48,
|
||||
0x25,0xfc,0x1f,0xaa,0x9e,0x16,0x84,0x20,0x3e,0x92,0xe2,0xda,
|
||||
0xa3,0xe8,0xe0,0xf1,0x17,0xf2,0xa2,0xc5,0xde,0x5b,0xb5,0x5c,
|
||||
0x20,0x38,0x19,0x65,0xd5,0x98,0x62,0xdc,0xfa,0x05,0x62,0x0d,
|
||||
0x85,0x2d,0x49,0xca,0x14,0xa7,0x62,0xde,0x0c,0x80,0xce,0xf1,
|
||||
0x55,0x08,0x68,0xaa,0xcc,0x90,0xd7,0x52,0xe9,0xf3,0x05,0x8e,
|
||||
0x25,0x56,0xb4,0x65,0xd3,0x73,0x4e,0x2d,0xf1,0x6d,0x47,0x94,
|
||||
0x63,0xf5,0x1c,0x75,0xd2,0x4c,0x15,0x30,0x0d,0x1d,0x46,0x66,
|
||||
0xa3,0x99,0xb1,0x66,0xf1,0xd5,0x1d,0x5d,0x9e,0x50,0x24,0xf1,
|
||||
0xdb,0x56,0x4f,0x18,0x2b,0x86,0xf0,0x49,0x1c,0xaf,0xf5,0xbb,
|
||||
0x02,0x0a,0xf0,0x27,0x5b,0xaa,0x8f,0xa2,0x87,0x68,0x72,0x56,
|
||||
0xaf,0x39,0x48,0x9c,0x9b,0x15,0x59,0x0d,0x06,0xb6,0xdc,0x9b,
|
||||
0x7a,0x00,0xff,0xaa,0x15,0xce,0xd6,0x2c,0xeb,0xaf,0x9a,0x45,
|
||||
0x58,0x16,0xb4,0xa3,0x2f,0x37,0xae,0xce,0xb7,0x49,0x59,0x82,
|
||||
0x1f,0x04,0x84,0x05,0x11,0xc9,0x91,0x56,0x3a,0xda,0x42,0x00,
|
||||
0xe9,0xd4,0xbc,0x40,0x50,0xd7,0x68,0x2d,0xbb,0x8b,0xda,0x14,
|
||||
0xf2,0x93,0xec,0x5c,0xb2,0xc6,0x2f,0x8a,0x5f,0xd5,0x3c,0x29,
|
||||
0x92,0x73,0xc7,0x76,0xce,0xa9,0x31,0xd8,0x83,0x2b,0xad,0xae,
|
||||
0xc5,0x75,0x2e,0x88,0x72,0x4e,0x91,0x9b,0x57,0xb1,0x77,0xa7,
|
||||
0xda,0x8b,0x51,0x60,0xc2,0xc6,0x02,0x04,0x43,0xdb,0x2a,0xd9,
|
||||
0x9b,0x67,0xab,0xa2,0xb0,0x30,0xd1,0x5c,0x97,0xf7,0x07,0x0d,
|
||||
0x6d,0x4e,0xd4,0x50,0xfe,0xe3,0xa1,0x2c,0xb4,0x3b,0xd9,0xd4,
|
||||
0x11,0x75,0x82,0xa5,0xa6,0xa9,0x72,0x04,0x35,0x54,0x89,0x1c,
|
||||
0x21,0xb1,0xe4,0xa6,0x97,0x8e,0xfb,0x65,0x3b,0xed,0x54,0x8d,
|
||||
0x21,0x84,0x55,0xcd,0xea,0xb1,0x22,0xbe,0x9a,0xb6,0xff,0xa2,
|
||||
0x09,0x19,0xcc,0x0d,0x9b,0x92,0x9e,0x08,0x54,0x6c,0x1d,0x57,
|
||||
0x27,0x1b,0xbb,0x00,0xcd,0x5e,0x9a,0x9d,0xc8,0x73,0xbf,0xf0,
|
||||
0xa0,0x08,0x9b,0x5f,0xe2,0x97,0x86,0x4e,0xc9,0x81,0x2b,0x26,
|
||||
0x2f,0xe4,0x8b,0x12,0x0a,0x86,0x84,0xa8,0xd1,0xf6,0xa2,0x28,
|
||||
0x2d,0x70,0x9c,0xca,0xe2,0x98,0xc8,0x59,0x2d,0x5b,0xd5,0x21,
|
||||
0xd0,0x52,0x69,0x9e,0x0f,0xa2,0x89,0xea,0xd0,0xdf,0x18,0x4b,
|
||||
0x2a,0x11,0x06,0xcf,0x08,0x12,0x6f,0x00,0x5c,0xe3,0xd9,0x8c,
|
||||
0x70,0x9c,0x29,0x9b,0x82,0x88,0x9e,0x39,0x66,0x84,0xd9,0x84,
|
||||
0x98,0xa9,0xa4,0x4c,0x4c,0x5b,0x2a,0xbc,0xc1,0xe9,0x82,0x6a,
|
||||
0xc6,0xe7,0xfe,0xd4,0x91,0x9b,0x5e,0x7f,0xe4,0xd8,0x95,0xe0,
|
||||
0x4b,0xcc,0x6b,0xe7,0x93,0xd6,0x86,0x66,0xdc,0x81,0x20,0xb3,
|
||||
0x1d,0x54,0x2d,0xb8,0x9d,0x26,0x90,0x4c,0x1e,0x01,0xbe,0xef,
|
||||
0x81,0xfa,0x67,0x90,0x9c,0x1d,0x58,0x38,0x38,0xdf,0xef,0xb3,
|
||||
0xfe,0xd8,0x81,0xbb,0x80,0xc3,0x44,0x30,0xa0,0x36,0xff,0xd0,
|
||||
0x76,0x75,0xd2,0x7e,0x78,0x54,0x17,0xb6,0x1d,0x81,0x0d,0x27,
|
||||
0x94,0xd5,0x5d,0x15,0xf4,0x07,0xd5,0x69,0xa2,0xb3,0x23,0x8a,
|
||||
0x80,0xaa,0xe3,0xc2,0x11,0x03,0x39,0x11,0x14,0x92,0x8c,0x34,
|
||||
0x67,0x24,0x5d,0x06,0x02,0x5a,0x1a,0x73,0x9d,0x34,0x00,0x72,
|
||||
0x8d,0x03,0x49,0x0c,0x3a,0x90,0x98,0x55,0xdf,0xab,0x09,0x88,
|
||||
0x62,0xe8,0x63,0x4c,0x69,0x58,0xca,0x8b,0x47,0x4b,0x62,0xa2,
|
||||
0x65,0xdb,0x87,0x08,0x46,0xc9,0x84,0x34,0x6c,0x38,0xe7,0x60,
|
||||
0xec,0x3f,0x25,0x27,0x69,0x63,0x92,0x11,0x9e,0x55,0x9d,0xab,
|
||||
0x51,0x13,0x9a,0x57,0xcc,0x77,0xd1,0xaf,0xdc,0x62,0x06,0xd1,
|
||||
0x50,0xd1,0x83,0xad,0x67,0x25,0x74,0x51,0x47,0x1b,0x48,0x0e,
|
||||
0x2e,0xad,0x01,0x26,0xd7,0x55,0xda,0x13,0xc2,0x3f,0x48,0x0d,
|
||||
0x97,0xa8,0xb3,0xc4,0xe3,0x12,0xe8,0xcd,0xef,0x55,0xf1,0x52,
|
||||
0x0b,0xf4,0x09,0x03,0x38,0xa8,0xa9,0xd7,0x24,0xe2,0xb9,0xbc,
|
||||
0x99,0x5b,0x96,0x5d,0x1d,0x0b,0x89,0x64,0x19,0x75,0xa5,0xee,
|
||||
0xd6,0x09,0xcd,0x3a,0xb3,0x80,0xa6,0x44,0xab,0x30,0x73,0x90,
|
||||
0x8e,0x90,0x13,0x29,0xe9,0xf6,0x6a,0xd0,0x83,0xf4,0x33,0x22,
|
||||
0xc7,0x7a,0xf7,0xe1,0xcf,0x68,0xda,0x04,0x74,0x37,0x62,0x99,
|
||||
0x5a,0x06,0x04,0xa7,0x9c,0x5c,0xe4,0x0d,0x71,0xad,0xc2,0x52,
|
||||
0x94,0xe4,0x81,0xc0,0x66,0x33,0xb5,0x56,0x69,0x9c,0x8a,0x5a,
|
||||
0x57,0x43,0x4f,0x9e,0xaf,0xb8,0x37,0xea,0xc4,0x54,0x92,0x48,
|
||||
0xed,0xe3,0x4a,0x87,0xce,0x82,0x1a,0xba,0xa9,0x51,0x9d,0xda,
|
||||
0xdd,0x0b,0xa6,0x20,0x73,0x4b,0x2d,0x98,0x2f,0xad,0xa1,0xb0,
|
||||
0x4f,0xae,0xea,0x6d,0xa2,0xfe,0x14,0xcf,0x50,0x46,0xa6,0xaa,
|
||||
0xd5,0x54,0x1d,0xae,0x1b,0x67,0x08,0x24,0x22,0xb2,0x26,0x0a,
|
||||
0x85,0x26,0xbf,0x65,0xeb,0x20,0x48,0xa9,0x1c,0x86,0x45,0xa6,
|
||||
0x9c,0x08,0x35,0x50,0x31,0x76,0xc5,0x84,0x02,0xad,0x2a,0x73,
|
||||
0x93,0x29,0xab,0x6e,0x9e,0xd2,0x9b,0xd2,0x9d,0xa9,0x66,0x8e,
|
||||
0x69,0x9e,0xd9,0xf2,0x4d,0x4a,0x8b,0x0c,0x16,0x60,0x7b,0x85,
|
||||
0xa5,0x1b,0x96,0xab,0xc3,0x74,0x22,0x68,0x34,0x51,0xb6,0xf4,
|
||||
0xea,0x5d,0x31,0x5e,0x81,0x41,0xfa,0x02,0xe0,0x7c,0x71,0xad,
|
||||
0x67,0x40,0xb3,0x24,0x29,0x16,0xf9,0xc4,0xdb,0x18,0x07,0xb2,
|
||||
0x17,0x5e,0x77,0xb9,0x5d,0xaa,0xc6,0xa4,0x54,0x4a,0x86,0xe4,
|
||||
0x8d,0x4d,0x84,0x44,0x53,0x65,0x25,0x04,0x2a,0x0b,0xea,0x47,
|
||||
0xd9,0x05,0x27,0xdc,0x4f,0x1c,0x95,0x28,0x19,0x96,0x41,0x1f,
|
||||
0xe5,0x93,0xf3,0x1b,0x51,0x27,0x46,0x56,0xd6,0xe6,0x4f,0xa3,
|
||||
0xdb,0x7b,0x00,0xc6,0xc3,0x6e,0x2e,0x11,0x01,0x54,0x59,0xf6,
|
||||
0x58,0x48,0xb4,0x6a,0xa9,0x6d,0x39,0x76,0x0f,0x88,0x2c,0xee,
|
||||
0x7f,0x20,0x8c,0xc0,0x56,0x03,0x38,0x6d,0x44,0x58,0x90,0xc0,
|
||||
0x05,0x4a,0x73,0xb2,0xdf,0x45,0xdf,0xbd,0xee,0x65,0x06,0x6a,
|
||||
0x52,0xf3,0x08,0x81,0x9c,0x33,0x40,0xab,0xed,0xa5,0x91,0xee,
|
||||
0x2b,0x75,0x09,0x83,0x9f,0xfa,0xb4,0x6b,0x65,0x12,0xae,0x71,
|
||||
0xf6,0x7b,0x58,0x32,0x6e,0xac,0x54,0x99,0x7e,0xa2,0x92,0x1b,
|
||||
0xa5,0xa0,0xc6,0xd8,0x02,0x1c,0x19,0x61,0xbf,0x79,0x8a,0xf8,
|
||||
0x10,0x20,0x59,0x66,0x34,0xcf,0x43,0xc9,0x04,0x9a,0x00,0xf4,
|
||||
0x2a,0x6b,0x06,0x22,0x2e,0xb2,0x81,0x86,0x04,0x37,0x52,0xef,
|
||||
0x0d,0xde,0xb7,0x99,0x11,0x88,0xa0,0x43,0xbe,0x60,0x98,0x76,
|
||||
0x1d,0xfd,0x13,0x79,0x4e,0xb5,0x1f,0xc3,0xcf,0x7e,0xf8,0xbf,
|
||||
0xe0,0xdd,0x67,0x03,0x76,0x2e,0x83,0xe1,0xb3,0x07,0x88,0x4d,
|
||||
0x9a,0x0c,0xfb,0x97,0x1f,0xd6,0x1f,0xd4,0xe5,0x33,0x88,0x11,
|
||||
0xcd,0x5d,0x02,0x10,0x69,0xb0,0xeb,0xc6,0x8b,0x95,0xa8,0x64,
|
||||
0xba,0x0b,0x32,0x2c,0x06,0xef,0x55,0x21,0x47,0x8a,0x04,0x99,
|
||||
0x56,0x63,0x56,0xce,0xd4,0x7a,0xee,0x8c,0x35,0x34,0xcb,0x63,
|
||||
0x17,0xcd,0xdb,0x49,0xa4,0xcc,0x0d,0x1c,0x46,0xe0,0xb1,0x99,
|
||||
0xe8,0x87,0x24,0x92,0xc1,0x44,0x68,0x45,0x3a,0x4e,0xb8,0x1b,
|
||||
0xd3,0x22,0x45,0xec,0x95,0x1a,0xb6,0x25,0xe1,0x99,0x32,0x85,
|
||||
0xc0,0x12,0x75,0xf5,0xe7,0x06,0x8d,0x2c,0xb9,0x59,0x11,0xe9,
|
||||
0xec,0x87,0x8e,0xb7,0x07,0x47,0x50,0x19,0x31,0x20,0x47,0xe4,
|
||||
0x49,0x94,0x14,0x77,0x82,0x84,0x34,0xe8,0xe0,0xe9,0x4b,0x0e,
|
||||
0x41,0x51,0x60,0xdd,0x0a,0x97,0x14,0xe4,0xd4,0x2e,0x55,0x44,
|
||||
0x29,0x4a,0x20,0x7b,0xbd,0xc2,0xb0,0x23,0x86,0x61,0x94,0x44,
|
||||
0x06,0x1d,0x1b,0xca,0x03,0x21,0x7a,0xd5,0x82,0x31,0x60,0x4e,
|
||||
0x34,0xeb,0x10,0xf9,0x3b,0xdd,0x2b,0xa1,0x47,0xe6,0xb4,0x42,
|
||||
0x85,0xd6,0x70,0x89,0x45,0xf1,0x74,0x38,0x93,0x62,0x6d,0x54,
|
||||
0xa4,0xb9,0x76,0xa6,0xd3,0x4c,0xde,0xbe,0x1c,0x5c,0xa1,0x14,
|
||||
0xf9,0x1c,0x6a,0x10,0x06,0x2a,0xb0,0xd6,0xa9,0x5b,0x67,0x69,
|
||||
0x14,0x05,0x1c,0xe6,0xc7,0xb8,0x56,0xb8,0x10,0x8d,0xe7,0x0a,
|
||||
0x59,0x3e,0xdc,0xb2,0xcd,0x9d,0xfe,0x72,0x1a,0x48,0x43,0x9e,
|
||||
0x4f,0x73,0x98,0x49,0xc7,0x19,0x0c,0xc9,0x4e,0x20,0x44,0x25,
|
||||
0x06,0xed,0x4f,0x50,0x71,0xcd,0x05,0xb0,0x66,0x93,0x60,0x12,
|
||||
0xde,0xa9,0x43,0xdc,0xc3,0xf1,0x59,0x6a,0x60,0x62,0x25,0x25,
|
||||
0xc2,0xab,0xa0,0x25,0xa9,0xda,0x84,0x26,0x40,0x51,0xf6,0x31,
|
||||
0xf9,0xa4,0xf0,0x85,0x21,0x8f,0xaa,0x61,0x17,0x05,0x43,0x82,
|
||||
0xa1,0x88,0x54,0x84,0xd0,0x5e,0x39,0x5d,0xc7,0xce,0x21,0x1d,
|
||||
0x1d,0xed,0x9c,0xe2,0xb5,0x4b,0xd0,0x53,0xf1,0x65,0xe3,0x76,
|
||||
0xd5,0x40,0x8b,0xba,0x69,0xca,0x29,0xa6,0xd2,0xb4,0x02,0x95,
|
||||
0x13,0x6e,0xe7,0x37,0x71,0xe1,0xfb,0x52,0xe5,0x90,0x09,0x79,
|
||||
0x98,0x7d,0xc9,0x9c,0x08,0x87,0x17,0x15,0xfc,0x25,0x66,0x41,
|
||||
0x96,0x75,0xaa,0x0c,0xfb,0x7c,0xa7,0x0b,0xa5,0x95,0xf7,0x68,
|
||||
0xf0,0x48,0xbe,0x92,0x60,0x24,0xe7,0x3d,0xaf,0x9e,0xa2,0xda,
|
||||
0xc1,0xb0,0xd7,0xd7,0xcd,0x50,0xc9,0x65,0xb6,0xb8,0x04,0xef,
|
||||
0x45,0x46,0x0d,0x05,0x0f,0x86,0xe6,0x28,0x74,0x47,0x96,0x6e,
|
||||
0x88,0xe4,0x2b,0xed,0xad,0xd9,0x4b,0x68,0xd8,0x1e,0xbd,0x7f,
|
||||
0x81,0x64,0x42,0x53,0x5a,0x7a,0xd7,0x8b,0x7b,0x8e,0x73,0x68,
|
||||
0x06,0x4b,0x43,0x9e,0x62,0x1f,0x16,0xbc,0x75,0xf0,0x63,0xde,
|
||||
0xa0,0xa9,0x11,0x24,0x55,0xfc,0x44,0x72,0x94,0x91,0xe6,0x64,
|
||||
0x8a,0xaf,0x60,0x85,0xf2,0x2f,0x84,0x04,0x25,0x35,0x01,0xae,
|
||||
0x21,0x90,0x28,0x28,0x7c,0x48,0x5a,0x51,0x0b,0xd0,0xd3,0x2d,
|
||||
0x7d,0x8c,0x1e,0xb1,0x20,0x05,0xe3,0xb3,0x48,0x58,0x30,0x18,
|
||||
0xac,0x59,0xbf,0x30,0x69,0xab,0x4c,0xdb,0xba,0xa6,0x9c,0xa5,
|
||||
0x7b,0xdd,0xd5,0xac,0x3a,0xb5,0xbb,0xc4,0xbd,0x1c,0x86,0x3b,
|
||||
0x68,0xb9,0x8a,0x2a,0x18,0x67,0xa4,0xaa,0x67,0xd5,0x9a,0xc6,
|
||||
0x3c,0x72,0x42,0x00,0x8a,0x31,0xa3,0xee,0x06,0xbd,0x06,0xc9,
|
||||
0xcc,0xd8,0xd3,0xac,0x48,0x26,0x99,0x0d,0x1c,0xe3,0xbb,0xa4,
|
||||
0xb2,0x26,0x1b,0xdd,0x06,0x32,0x3a,0x6a,0x67,0xed,0xce,0x8e,
|
||||
0x24,0x0a,0x69,0xea,0x02,0x61,0xf1,0x00,0x31,0xbd,0x9b,0x22,
|
||||
0x8a,0x82,0x58,0xe6,0x80,0xc2,0x3c,0x20,0x00,0x33,0x90,0xaa,
|
||||
0xf0,0x43,0xcb,0x1f,0x1a,0xf4,0xe8,0xa3,0xdc,0x01,0x37,0x79,
|
||||
0xe1,0xc6,0x05,0x3e,0x8b,0x94,0x2d,0x3a,0x9a,0x39,0xdd,0xce,
|
||||
0xbc,0xbb,0x1c,0xc0,0x63,0xee,0x0d,0x01,0x2c,0x14,0x4d,0xa5,
|
||||
0x7f,0x0c,0x43,0x16,0xc1,0x70,0xa6,0xb5,0x2f,0x3a,0xbb,0xbe,
|
||||
0x57,0xa7,0x95,0x00,0x91,
|
||||
};
|
||||
static const byte FALCON1024_sig[] = {
|
||||
0x3a,0x26,0xae,0x20,0x5d,0xc6,0x25,0xe0,0x80,0xf0,0x4d,0xec,
|
||||
0x22,0xb0,0xab,0xff,0x39,0xfb,0x23,0xef,0xe2,0x50,0x91,0x8e,
|
||||
0xb4,0x61,0xf2,0x28,0x25,0xf3,0xec,0x00,0x86,0xe6,0x61,0x37,
|
||||
0x16,0x1b,0xef,0xb2,0x73,0xdc,0xe7,0x75,0x34,0xa9,0xcc,0x1e,
|
||||
0x79,0x4f,0x85,0x29,0x5d,0x8b,0xe9,0xad,0x6a,0x56,0xc2,0x3e,
|
||||
0x93,0xc9,0x5a,0xa6,0x15,0xa6,0xe6,0x62,0xb4,0x48,0xfe,0xd1,
|
||||
0xa3,0xc2,0x8d,0xb2,0xb1,0x66,0x99,0xc0,0x58,0xfe,0x97,0x13,
|
||||
0x59,0x05,0xdb,0x54,0x32,0xa5,0x9d,0xbc,0xaf,0x21,0xc2,0xab,
|
||||
0xb1,0x8b,0xae,0x96,0xcd,0x1e,0x04,0xf6,0x42,0x08,0xdf,0xa2,
|
||||
0x34,0xa4,0x43,0x9b,0xae,0x84,0xc7,0x6b,0xe9,0xc9,0x5d,0xc6,
|
||||
0xdc,0xf0,0x6b,0x88,0x3a,0xf2,0x9b,0xc6,0xd9,0x9f,0x95,0x95,
|
||||
0x15,0x95,0xd0,0xc9,0x67,0x5a,0x58,0xcd,0x7b,0xf3,0xce,0x84,
|
||||
0x8b,0x33,0x29,0x40,0x49,0x9f,0xce,0xb9,0x31,0x36,0x18,0x28,
|
||||
0xad,0x43,0x30,0xd9,0x61,0x11,0x76,0xb1,0xc0,0xf4,0xdb,0x7b,
|
||||
0xf5,0x93,0x35,0x94,0x67,0x7d,0x9b,0x84,0xe5,0x19,0xe6,0x8a,
|
||||
0x1b,0x8f,0x82,0x6f,0x2b,0x8e,0x10,0xdf,0x4d,0x1f,0xce,0xd6,
|
||||
0xdf,0x9e,0x79,0x58,0x64,0x1d,0xbd,0xa8,0x76,0x35,0x7b,0x68,
|
||||
0xcf,0x1d,0xea,0x68,0xd9,0xc8,0xfb,0xa3,0x34,0x65,0xe0,0xcc,
|
||||
0xf3,0x71,0xa7,0x23,0xd4,0xfc,0xa5,0x8d,0x2f,0x82,0x4d,0x61,
|
||||
0x8c,0xf1,0xa6,0xa8,0x4f,0xd8,0xa3,0x44,0x7b,0x32,0x4d,0x0a,
|
||||
0x94,0x9c,0x31,0xe4,0x59,0x11,0x79,0xc4,0xf5,0x87,0x86,0x10,
|
||||
0x25,0x02,0x44,0xb2,0xc7,0x18,0xe7,0x6f,0x8a,0xed,0x56,0x1b,
|
||||
0xf9,0x4b,0xe5,0xb4,0x92,0xb8,0x97,0x59,0x23,0xe9,0xff,0x50,
|
||||
0x61,0xac,0xdc,0x51,0x30,0x68,0x6a,0x1e,0xed,0xb4,0x5a,0xec,
|
||||
0x8b,0x31,0xcc,0xf6,0xa2,0xfe,0x91,0x30,0xbf,0x49,0x4a,0x8e,
|
||||
0xd8,0xd1,0x13,0xe8,0x1e,0xd5,0xae,0xa5,0xcd,0x8d,0x6f,0x0d,
|
||||
0x51,0x9d,0xbf,0xd7,0x36,0x63,0x11,0x19,0x21,0x7d,0x9a,0x4d,
|
||||
0x61,0x38,0x64,0x53,0xd4,0xb4,0xd4,0x49,0xcd,0x55,0x3b,0x3d,
|
||||
0x5d,0x93,0xcf,0x2f,0x86,0x2f,0x16,0x9c,0xa6,0x7a,0x46,0xc0,
|
||||
0xa4,0x70,0x62,0x33,0xe6,0x4d,0x28,0x77,0x16,0xd8,0xbc,0x77,
|
||||
0x16,0x84,0xc0,0xd6,0xed,0x02,0x7d,0xe0,0xca,0x4f,0xb1,0x6c,
|
||||
0xf9,0x7c,0xa7,0xce,0x68,0x9d,0x37,0x41,0xfa,0x91,0x45,0x2a,
|
||||
0xdd,0xf2,0x3b,0xb8,0xd3,0x5a,0x98,0x2f,0x84,0x62,0xdf,0xef,
|
||||
0x3f,0x1d,0xa5,0x7e,0x4f,0x79,0x94,0x75,0x6c,0x35,0x3a,0xca,
|
||||
0xb5,0x12,0xf6,0x8c,0xae,0x4f,0x0d,0xaa,0xcb,0x67,0xdb,0x2c,
|
||||
0x73,0xb9,0x34,0xb0,0x64,0x93,0x56,0x35,0x8d,0x52,0x94,0x5a,
|
||||
0x31,0xd3,0xec,0xf1,0x93,0x86,0xe3,0x33,0xe1,0x83,0x54,0x32,
|
||||
0x0c,0xf2,0x41,0x5e,0xb5,0x4a,0x79,0xe6,0xd3,0x11,0x37,0xfb,
|
||||
0xd5,0x62,0xa8,0xfa,0xd5,0xe2,0xc6,0xfb,0x10,0xcf,0xaf,0xee,
|
||||
0x4a,0x28,0xff,0x84,0x15,0xf2,0x6a,0x90,0xac,0xe3,0x32,0x8a,
|
||||
0xe7,0x1e,0x76,0x35,0x05,0xf5,0x70,0x1e,0x1c,0x0b,0x95,0x88,
|
||||
0x4e,0x8a,0x14,0x06,0x0b,0xc1,0xda,0x98,0x28,0x7f,0xef,0x87,
|
||||
0x8c,0xc6,0xf7,0x74,0x28,0x55,0xe3,0x1c,0x96,0x4e,0x2d,0x3a,
|
||||
0x7f,0xf5,0x2e,0x9f,0x2c,0xf4,0x23,0x50,0x91,0x7e,0xfd,0x4f,
|
||||
0xa9,0xfd,0x36,0xf1,0x91,0x9e,0xa0,0x93,0xbf,0xbe,0xad,0x5e,
|
||||
0xc1,0xbf,0xba,0xbb,0x84,0xb3,0xb0,0xc4,0x98,0x74,0xd7,0x23,
|
||||
0x81,0xa1,0x41,0xe9,0xfa,0xb3,0xdf,0x59,0xb6,0x25,0x39,0xd7,
|
||||
0xa9,0xd9,0x7e,0xe1,0xd7,0x3c,0x7b,0x1b,0xee,0xd1,0xb1,0x7e,
|
||||
0x14,0x32,0x91,0xa3,0x2a,0x85,0x25,0x45,0x86,0x1f,0xb4,0xdb,
|
||||
0x4a,0xb4,0xb9,0x57,0xb4,0xe3,0xf5,0x78,0x36,0x0f,0x2d,0x4d,
|
||||
0xc8,0xdd,0x41,0x76,0xf6,0xc7,0x9b,0x0c,0xcb,0x52,0xe2,0xf0,
|
||||
0xbb,0xc5,0x00,0x54,0x9a,0x44,0x35,0x0f,0xcc,0x5f,0x12,0x06,
|
||||
0x45,0xd1,0x7d,0x19,0x26,0x98,0x3f,0xd3,0x9d,0xad,0xaa,0xac,
|
||||
0xd3,0x9b,0xe6,0xb6,0x0b,0x78,0xac,0x6f,0xeb,0xe4,0x23,0x70,
|
||||
0x1f,0x36,0x82,0x6b,0x41,0x22,0x1f,0xd8,0x6e,0x99,0x03,0xb4,
|
||||
0xd2,0x5f,0x8d,0xe3,0x62,0xe3,0x22,0x4a,0x81,0xa5,0xc4,0x27,
|
||||
0x7a,0xb9,0x9e,0xd6,0xcd,0x6e,0x7e,0xa0,0x07,0x4d,0x44,0xe4,
|
||||
0xae,0xc8,0xcd,0x96,0xbf,0xd4,0xb1,0xca,0x59,0x5c,0xaa,0x00,
|
||||
0xea,0x70,0x2f,0x71,0x1a,0x6e,0x05,0xec,0xe5,0xd0,0xe7,0x19,
|
||||
0xd4,0x38,0xd3,0x50,0x75,0xe8,0xcd,0x4a,0xe8,0xd6,0x38,0x68,
|
||||
0xff,0x31,0x64,0x83,0x4b,0x08,0xda,0x76,0xa2,0x9e,0xbc,0x66,
|
||||
0xc3,0x37,0x14,0x42,0x6d,0xea,0x6d,0xd5,0xc9,0xb1,0xe6,0xec,
|
||||
0x96,0x1e,0x12,0x11,0xb6,0x4a,0x9e,0x86,0x9a,0x39,0x61,0xc7,
|
||||
0x43,0x10,0xdc,0xa0,0xcf,0xae,0xf4,0xf9,0xf4,0x46,0xa3,0xca,
|
||||
0x8a,0x6b,0x9a,0xf9,0x08,0x9f,0xe9,0x62,0xfe,0x07,0x87,0x34,
|
||||
0x9e,0x5c,0xa3,0xfb,0x78,0x51,0x44,0x6c,0x34,0x6a,0x1f,0x93,
|
||||
0x02,0xe7,0x78,0xca,0xdd,0x35,0x0f,0xc6,0x1c,0xbe,0xbc,0x3d,
|
||||
0x22,0xd2,0x68,0x6d,0x6e,0xea,0x5f,0x0c,0xad,0xfb,0x95,0xb2,
|
||||
0xcf,0x19,0x63,0xb4,0xac,0xe1,0x52,0x71,0xb8,0x0b,0x7d,0xf4,
|
||||
0x53,0x59,0xaa,0x29,0xe2,0xc4,0x40,0x97,0xf8,0xae,0x58,0xfc,
|
||||
0xc5,0x5b,0xc8,0xd7,0x6b,0xe6,0x88,0x06,0x28,0x8f,0x5f,0x9a,
|
||||
0x5b,0xcb,0xb7,0x5e,0x6a,0xb4,0x97,0x27,0xbf,0xa5,0x0f,0x64,
|
||||
0xd2,0x33,0x8a,0x71,0x53,0xcc,0xb4,0xf7,0xd1,0x8e,0xd7,0xe3,
|
||||
0x0a,0xb2,0x1f,0xbf,0x82,0x9f,0xca,0x21,0x8c,0x60,0x8c,0x11,
|
||||
0x0e,0x35,0x3e,0xa5,0x19,0xe6,0xbe,0x3a,0x11,0x59,0x38,0x85,
|
||||
0x2e,0x78,0x44,0x19,0x16,0x9b,0x09,0x07,0xd2,0x99,0x54,0xa8,
|
||||
0xc4,0x9e,0xdf,0x56,0x23,0xa9,0x22,0x67,0x65,0x9f,0xe9,0x8b,
|
||||
0xe9,0x15,0xa8,0x89,0x96,0x1c,0xb5,0x9e,0x3c,0x2b,0x5c,0x84,
|
||||
0x4c,0x31,0x0e,0xf3,0xd7,0xdb,0x6f,0x94,0x5f,0x76,0x85,0x6e,
|
||||
0x67,0xe3,0x0d,0x9c,0xa1,0x4f,0xca,0xe7,0x48,0xff,0xc6,0xed,
|
||||
0x22,0x6e,0x39,0x8c,0x5a,0x36,0xf4,0xe1,0xaa,0x38,0xb8,0x72,
|
||||
0x22,0xb1,0x6a,0xde,0x19,0x43,0x34,0x6a,0xf4,0x2f,0xe4,0xed,
|
||||
0x71,0x56,0x90,0xc2,0x12,0xcc,0x62,0x6f,0xfd,0x13,0x78,0x4e,
|
||||
0x50,0x2a,0x04,0xc9,0x88,0x7c,0xb9,0xf5,0x8c,0x92,0xbb,0xc7,
|
||||
0x42,0xdc,0x83,0xc1,0x88,0x2e,0x3b,0x9b,0xf4,0xa2,0x65,0x82,
|
||||
0x36,0x0c,0xee,0xed,0x2e,0x59,0xaf,0x31,0x6d,0x26,0xb5,0x82,
|
||||
0x15,0x67,0xe5,0x0a,0xf3,0x56,0x6f,0x69,0x6f,0xa5,0x47,0xce,
|
||||
0xc0,0xff,0x51,0x2d,0x03,0x31,0x22,0x3b,0xf1,0xd5,0x6e,0xdc,
|
||||
0xf1,0x08,0xc3,0x02,0x58,0xe4,0x76,0xb3,0xf7,0xbf,0x29,0x24,
|
||||
0x55,0x95,0x4f,0xb4,0x64,0x43,0x2b,0x94,0x76,0xc8,0x11,0xef,
|
||||
0x83,0x45,0x3b,0x0a,0xaf,0x29,0xb5,0x7a,0x0b,0xc6,0x88,0x8b,
|
||||
0xe2,0x23,0x69,0xee,0x13,0x50,0x95,0x95,0x35,0xde,0x99,0x28,
|
||||
0xe0,0xe3,0x37,0xb4,0xa9,0xde,0x57,0x83,0x9c,0x3a,0x08,0x60,
|
||||
0xdf,0x21,0xbd,0xad,0x62,0xe0,0x60,0x9c,0x9c,0xe2,0xa7,0x20,
|
||||
0x6b,0x6d,0x7a,0x68,0x23,0x5f,0xca,0x50,0xe7,0x0a,0x13,0x51,
|
||||
0xfc,0xe3,0x77,0xe0,0x1f,0x82,0x19,0x4c,0xc3,0xda,0x50,0xf5,
|
||||
0x87,0x53,0xf1,0xd6,0x4f,0xf3,0x12,0xf9,0x12,0xf3,0x8e,0xdb,
|
||||
0x6f,0x39,0xbd,0x59,0xc7,0xdd,0x9a,0xd1,0x67,0xa4,0x70,0xc1,
|
||||
0x85,0x83,0xaa,0x76,0xd3,0x79,0xdc,0x90,0xe9,0x9a,0x0a,0x83,
|
||||
0xd7,0xa3,0xa0,0x5c,0x72,0x22,0x17,0xf7,0x8c,0x88,0x83,0x70,
|
||||
0x81,0x1e,0x4d,0x4a,0xeb,0xe0,0x9c,0xc1,0xa4,0x50,0x2a,0xa6,
|
||||
0x1b,0x22,0x79,0x5b,0x44,0x42,0x68,0xcc,0x30,0xe8,0x37,0x07,
|
||||
0xd4,0x9b,0x63,0x9b,0x9d,0xe9,0xa8,0x4c,0x28,0x3e,0xfa,0xaa,
|
||||
0xff,0x5c,0xe3,0x33,0x9c,0x99,0x7e,0x6e,0x51,0x83,0x30,0x46,
|
||||
0x48,0xe6,0x6c,0xcf,0xd2,0xa9,0x92,0xdf,0xab,0xf3,0x0a,0x2e,
|
||||
0xbd,0x56,0x95,0xe5,0x18,0x24,
|
||||
};
|
||||
#define FALCON1024_SIGLEN 1266
|
||||
|
||||
|
||||
static wc_test_ret_t falcon_verify_kat(byte level, const byte* pk, word32 pkLen,
|
||||
const byte* sig, word32 sigLen)
|
||||
{
|
||||
wc_test_ret_t ret;
|
||||
falcon_key key;
|
||||
int res;
|
||||
byte badSig[FALCON_MAX_SIG_SIZE];
|
||||
const byte* msg = (const byte*)FALCON_KAT_MSG;
|
||||
word32 msgLen = (word32)XSTRLEN(FALCON_KAT_MSG);
|
||||
|
||||
ret = wc_falcon_init(&key);
|
||||
if (ret != 0)
|
||||
return WC_TEST_RET_ENC_EC(ret);
|
||||
|
||||
ret = wc_falcon_set_level(&key, level);
|
||||
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto out; }
|
||||
|
||||
ret = wc_falcon_import_public(pk, pkLen, &key);
|
||||
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto out; }
|
||||
|
||||
/* A genuine liboqs-produced signature must verify (res == 1). */
|
||||
res = 0;
|
||||
ret = wc_falcon_verify_msg(sig, sigLen, msg, msgLen, &res, &key);
|
||||
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto out; }
|
||||
if (res != 1) { ret = WC_TEST_RET_ENC_NC; goto out; }
|
||||
|
||||
/* Flip a byte in the compressed signature body; it must NOT verify. The
|
||||
* verifier may report this either as an operational parse error or as a
|
||||
* clean res == 0; in all cases it must not claim the signature is valid. */
|
||||
if (sigLen > (word32)sizeof(badSig)) { ret = WC_TEST_RET_ENC_NC; goto out; }
|
||||
XMEMCPY(badSig, sig, sigLen);
|
||||
badSig[sigLen - 1] ^= 0x01;
|
||||
res = 1;
|
||||
(void)wc_falcon_verify_msg(badSig, sigLen, msg, msgLen, &res, &key);
|
||||
if (res == 1) { ret = WC_TEST_RET_ENC_NC; goto out; }
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
wc_falcon_free(&key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t falcon_test(void)
|
||||
{
|
||||
wc_test_ret_t ret;
|
||||
|
||||
ret = falcon_verify_kat(FALCON_LEVEL1, FALCON512_pk,
|
||||
(word32)sizeof(FALCON512_pk), FALCON512_sig, FALCON512_SIGLEN);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = falcon_verify_kat(FALCON_LEVEL5, FALCON1024_pk,
|
||||
(word32)sizeof(FALCON1024_pk), FALCON1024_sig, FALCON1024_SIGLEN);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
#ifdef WC_FALCON_HAVE_NATIVE_SIGN
|
||||
{
|
||||
/* Native keygen -> sign -> verify round-trip (no liboqs). */
|
||||
static const byte falconLvls[2] = { FALCON_LEVEL1, FALCON_LEVEL5 };
|
||||
const char* falconMsg = "wolfSSL native FN-DSA self test";
|
||||
word32 falconMsgLen = (word32)XSTRLEN(falconMsg);
|
||||
WC_RNG rng;
|
||||
int li;
|
||||
|
||||
ret = wc_InitRng_ex(&rng, HEAP_HINT, devId);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
for (li = 0; li < 2; li++) {
|
||||
falcon_key k;
|
||||
byte sig[FALCON_MAX_SIG_SIZE];
|
||||
word32 siglen = (word32)sizeof(sig);
|
||||
int res = 0;
|
||||
|
||||
ret = wc_falcon_init(&k);
|
||||
if (ret == 0)
|
||||
ret = wc_falcon_set_level(&k, falconLvls[li]);
|
||||
if (ret == 0)
|
||||
ret = wc_falcon_make_key(&k, &rng);
|
||||
if (ret == 0)
|
||||
ret = wc_falcon_sign_msg((const byte*)falconMsg, falconMsgLen, sig,
|
||||
&siglen, &k, &rng);
|
||||
if (ret == 0)
|
||||
ret = wc_falcon_verify_msg(sig, siglen, (const byte*)falconMsg,
|
||||
falconMsgLen, &res, &k);
|
||||
if (ret == 0 && res != 1)
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
if (ret == 0) {
|
||||
/* A different message must be rejected. */
|
||||
res = 1;
|
||||
(void)wc_falcon_verify_msg(sig, siglen, (const byte*)"x", 1, &res,
|
||||
&k);
|
||||
if (res != 0)
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
}
|
||||
wc_falcon_free(&k);
|
||||
if (ret != 0) {
|
||||
wc_FreeRng(&rng);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
wc_FreeRng(&rng);
|
||||
}
|
||||
#endif /* WC_FALCON_HAVE_NATIVE_SIGN */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_FALCON */
|
||||
|
||||
#if defined(WOLFSSL_HAVE_MLDSA)
|
||||
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mldsa_test(void)
|
||||
{
|
||||
wc_test_ret_t ret;
|
||||
|
||||
+63
-11
@@ -37,27 +37,57 @@
|
||||
|
||||
#if defined(HAVE_FALCON)
|
||||
|
||||
#ifndef HAVE_LIBOQS
|
||||
#error "HAVE_FALCON requires HAVE_LIBOQS."
|
||||
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
|
||||
#include <wolfssl/wolfcrypt/random.h>
|
||||
#endif
|
||||
|
||||
#include <oqs/oqs.h>
|
||||
#include <wolfssl/wolfcrypt/port/liboqs/liboqs.h>
|
||||
/* Falcon is the PRE-STANDARDIZATION name for this NIST post-quantum signature
|
||||
* scheme. NIST is standardizing it as FN-DSA (FIPS 206), which is still a draft.
|
||||
* Until FN-DSA is finalized, wolfCrypt exposes the algorithm under its current
|
||||
* name -- "falcon" (wc_falcon_* / falcon_key) -- and it requires
|
||||
* --enable-experimental to build.
|
||||
*
|
||||
* NOTE: this API and its "falcon" spelling are TEMPORARY and subject to change.
|
||||
* When FN-DSA is finalized the canonical API will be renamed to the
|
||||
* standardized name -- exactly as the pre-standardization Kyber and Dilithium
|
||||
* APIs were renamed to ML-KEM (FIPS 203) and ML-DSA (FIPS 204) in wolfSSL 5.7 --
|
||||
* and this <falcon.h> is expected to be retained thereafter as a temporary
|
||||
* compatibility shim. Application code that uses wc_falcon_* / falcon_key should
|
||||
* expect to migrate to the standardized spelling. */
|
||||
|
||||
/* This is the native wolfCrypt implementation (no liboqs dependency). */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Macros Definitions */
|
||||
/* Macro Definitions */
|
||||
|
||||
#define FALCON_LEVEL1_KEY_SIZE OQS_SIG_falcon_512_length_secret_key
|
||||
#define FALCON_LEVEL1_SIG_SIZE OQS_SIG_falcon_512_length_signature
|
||||
#define FALCON_LEVEL1_PUB_KEY_SIZE OQS_SIG_falcon_512_length_public_key
|
||||
/* Security level identifiers. */
|
||||
#define FALCON_LEVEL1 1 /* Falcon-512 */
|
||||
#define FALCON_LEVEL5 5 /* Falcon-1024 */
|
||||
|
||||
/* Ring modulus q = 12289 and degree parameters. */
|
||||
#define FALCON_Q 12289
|
||||
#define FALCON_LEVEL1_LOGN 9
|
||||
#define FALCON_LEVEL1_N (1 << FALCON_LEVEL1_LOGN) /* 512 */
|
||||
#define FALCON_LEVEL5_LOGN 10
|
||||
#define FALCON_LEVEL5_N (1 << FALCON_LEVEL5_LOGN) /* 1024 */
|
||||
#define FALCON_MAX_N FALCON_LEVEL5_N
|
||||
|
||||
/* Salt/nonce prepended to the message before hash-to-point. */
|
||||
#define FALCON_NONCE_SIZE 40
|
||||
|
||||
/* Encoded sizes (Falcon specification, Table 3.3): 14-bit packed public key,
|
||||
* (header|f|g|F) secret key, compressed signature. */
|
||||
#define FALCON_LEVEL1_KEY_SIZE 1281
|
||||
#define FALCON_LEVEL1_SIG_SIZE 666
|
||||
#define FALCON_LEVEL1_PUB_KEY_SIZE 897
|
||||
#define FALCON_LEVEL1_PRV_KEY_SIZE (FALCON_LEVEL1_PUB_KEY_SIZE+FALCON_LEVEL1_KEY_SIZE)
|
||||
|
||||
#define FALCON_LEVEL5_KEY_SIZE OQS_SIG_falcon_1024_length_secret_key
|
||||
#define FALCON_LEVEL5_SIG_SIZE OQS_SIG_falcon_1024_length_signature
|
||||
#define FALCON_LEVEL5_PUB_KEY_SIZE OQS_SIG_falcon_1024_length_public_key
|
||||
#define FALCON_LEVEL5_KEY_SIZE 2305
|
||||
#define FALCON_LEVEL5_SIG_SIZE 1280
|
||||
#define FALCON_LEVEL5_PUB_KEY_SIZE 1793
|
||||
#define FALCON_LEVEL5_PRV_KEY_SIZE (FALCON_LEVEL5_PUB_KEY_SIZE+FALCON_LEVEL5_KEY_SIZE)
|
||||
|
||||
#define FALCON_MAX_KEY_SIZE FALCON_LEVEL5_KEY_SIZE
|
||||
@@ -65,6 +95,10 @@
|
||||
#define FALCON_MAX_PUB_KEY_SIZE FALCON_LEVEL5_PUB_KEY_SIZE
|
||||
#define FALCON_MAX_PRV_KEY_SIZE FALCON_LEVEL5_PRV_KEY_SIZE
|
||||
|
||||
/* Encoding header bytes: high nibble = format, low nibble = logn. */
|
||||
#define FALCON_SIG_HEAD_COMPRESSED 0x30
|
||||
#define FALCON_PUB_HEAD 0x00
|
||||
|
||||
#ifdef WOLF_PRIVATE_KEY_ID
|
||||
#define FALCON_MAX_ID_LEN 32
|
||||
#define FALCON_MAX_LABEL_LEN 32
|
||||
@@ -78,6 +112,8 @@ struct falcon_key {
|
||||
WC_BITFIELD prvKeySet:1;
|
||||
byte level;
|
||||
|
||||
void* heap;
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
void* devCtx;
|
||||
int devId;
|
||||
@@ -100,6 +136,10 @@ struct falcon_key {
|
||||
|
||||
/* Functions */
|
||||
|
||||
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
|
||||
WOLFSSL_API
|
||||
int wc_falcon_make_key(falcon_key* key, WC_RNG* rng);
|
||||
#endif
|
||||
WOLFSSL_API
|
||||
int wc_falcon_sign_msg(const byte* in, word32 inLen, byte* out, word32 *outLen,
|
||||
falcon_key* key, WC_RNG* rng);
|
||||
@@ -172,6 +212,18 @@ WOLFSSL_API int wc_Falcon_PrivateKeyToDer(falcon_key* key, byte* output,
|
||||
WOLFSSL_API int wc_Falcon_PublicKeyToDer(falcon_key* key, byte* output,
|
||||
word32 inLen, int withAlg);
|
||||
|
||||
/* Native implementation core (internal). The public wc_falcon_* functions in
|
||||
* falcon.c wrap these with cryptocb dispatch and argument checking. */
|
||||
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
|
||||
/* Signals that native signing and key generation are available. */
|
||||
#define WC_FALCON_HAVE_NATIVE_SIGN
|
||||
WOLFSSL_LOCAL int falcon_native_make_key(falcon_key* key, WC_RNG* rng);
|
||||
WOLFSSL_LOCAL int falcon_native_sign_msg(const byte* in, word32 inLen,
|
||||
byte* out, word32* outLen, falcon_key* key, WC_RNG* rng);
|
||||
#endif
|
||||
WOLFSSL_LOCAL int falcon_native_verify_msg(const byte* sig, word32 sigLen,
|
||||
const byte* msg, word32 msgLen, int* res, falcon_key* key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -5170,15 +5170,9 @@ blinding by defining WC_BLINDING_NO_RNG_ACKNOWLEDGE_WEAKNESS."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Falcon is the only algorithm we still pull from liboqs, so the two options
|
||||
* go together: Falcon cannot be built without liboqs, and enabling liboqs
|
||||
* without Falcon leaves nothing for it to do. */
|
||||
#if defined(HAVE_LIBOQS) && !defined(HAVE_FALCON)
|
||||
#error "HAVE_LIBOQS without HAVE_FALCON has no effect; enable Falcon or drop liboqs."
|
||||
#endif
|
||||
#if defined(HAVE_FALCON) && !defined(HAVE_LIBOQS)
|
||||
#error "HAVE_FALCON requires HAVE_LIBOQS (enable liboqs via --with-liboqs)."
|
||||
#endif
|
||||
/* Falcon (the pre-standardization name for FN-DSA / FIPS 206) is provided by the
|
||||
* native wolfCrypt implementation in falcon.[ch] + wc_falcon*.[ch]; it no longer
|
||||
* requires liboqs. HAVE_FALCON is the build gate. */
|
||||
|
||||
#if (defined(HAVE_LIBOQS) || \
|
||||
defined(WOLFSSL_DUAL_ALG_CERTS) || \
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/* wc_falcon_bigint.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/*!
|
||||
\file wolfssl/wolfcrypt/wc_falcon_bigint.h
|
||||
*/
|
||||
|
||||
/* Self-contained big-integer / RNS arithmetic for native FN-DSA (Falcon)
|
||||
* key generation.
|
||||
*
|
||||
* FN-DSA key generation solves the NTRU equation g*F - f*G = q, which is
|
||||
* performed by the Falcon "ntru_solve" routine. That routine relies on a
|
||||
* specialized integer-only big-number layer using a residue number system
|
||||
* (RNS) of 31-bit prime moduli, with a small-modulus NTT for fast
|
||||
* polynomial arithmetic and an extended-binary-GCD (Bezout) solver.
|
||||
*
|
||||
* The algorithms and limb conventions here are ported faithfully from the
|
||||
* Falcon reference implementation keygen.c by Thomas Pornin (MIT licensed):
|
||||
* - big integers are little-endian arrays of word32 "limbs", each limb
|
||||
* holding 31 bits of value (the top bit is unused for carry handling);
|
||||
* - products use word64; signed reductions use sword32 / sword64;
|
||||
* - the RNS primes p satisfy 2^30 < p < 2^31 and p = 1 mod 2048.
|
||||
*
|
||||
* This module is INTEGER-ONLY and independent of the floating-point seam.
|
||||
* It is excluded from verify-only builds (keygen is not needed there). */
|
||||
|
||||
#ifndef WOLF_CRYPT_WC_FALCON_BIGINT_H
|
||||
#define WOLF_CRYPT_WC_FALCON_BIGINT_H
|
||||
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* One entry of the RNS small-prime table. Fields mirror the Falcon
|
||||
* reference small_prime structure:
|
||||
* p A prime modulus, with 2^30 < p < 2^31 and p = 1 mod 2048.
|
||||
* g A primitive root of phi = X^N+1 in the field Z_p.
|
||||
* s The inverse of the product of all previous primes in the table,
|
||||
* computed modulo p and in Montgomery representation.
|
||||
* The table is sorted in decreasing order of p and terminated with a
|
||||
* { 0, 0, 0 } sentinel. */
|
||||
typedef struct falcon_small_prime {
|
||||
word32 p;
|
||||
word32 g;
|
||||
word32 s;
|
||||
} falcon_small_prime;
|
||||
|
||||
/* RNS prime table (terminated with a { 0, 0, 0 } sentinel). */
|
||||
WOLFSSL_LOCAL extern const falcon_small_prime FALCON_PRIMES[];
|
||||
|
||||
/* ---- modular small-integer helpers (single 31-bit prime modulus) ---- */
|
||||
WOLFSSL_LOCAL word32 modp_set(sword32 x, word32 p);
|
||||
WOLFSSL_LOCAL sword32 modp_norm(word32 x, word32 p);
|
||||
WOLFSSL_LOCAL word32 modp_ninv31(word32 p);
|
||||
WOLFSSL_LOCAL word32 modp_R(word32 p);
|
||||
WOLFSSL_LOCAL word32 modp_add(word32 a, word32 b, word32 p);
|
||||
WOLFSSL_LOCAL word32 modp_sub(word32 a, word32 b, word32 p);
|
||||
WOLFSSL_LOCAL word32 modp_montymul(word32 a, word32 b, word32 p, word32 p0i);
|
||||
WOLFSSL_LOCAL word32 modp_R2(word32 p, word32 p0i);
|
||||
WOLFSSL_LOCAL word32 modp_Rx(unsigned int x, word32 p, word32 p0i, word32 R2);
|
||||
/* Modular division a/b mod p (returns 0 when b == 0). This is the
|
||||
* reference's modular-inverse helper (the canonical Falcon keygen.c has no
|
||||
* separately named "modp_get_inv"; modp_div(R,b,...) yields 1/b). */
|
||||
WOLFSSL_LOCAL word32 modp_div(word32 a, word32 b, word32 p, word32 p0i,
|
||||
word32 R);
|
||||
|
||||
/* ---- small-modulus NTT used in the RNS ---- */
|
||||
WOLFSSL_LOCAL void modp_mkgm2(word32* gm, word32* igm, unsigned int logn,
|
||||
word32 g, word32 p, word32 p0i);
|
||||
WOLFSSL_LOCAL void modp_NTT2_ext(word32* a, size_t stride, const word32* gm,
|
||||
unsigned int logn, word32 p, word32 p0i);
|
||||
WOLFSSL_LOCAL void modp_iNTT2_ext(word32* a, size_t stride, const word32* igm,
|
||||
unsigned int logn, word32 p, word32 p0i);
|
||||
|
||||
/* Convenience wrappers for unit-stride polynomials. */
|
||||
#define modp_NTT2(a, gm, logn, p, p0i) \
|
||||
modp_NTT2_ext(a, 1, gm, logn, p, p0i)
|
||||
#define modp_iNTT2(a, igm, logn, p, p0i) \
|
||||
modp_iNTT2_ext(a, 1, igm, logn, p, p0i)
|
||||
|
||||
/* ---- big-integer (zint) helpers ---- */
|
||||
WOLFSSL_LOCAL word32 zint_sub(word32* a, const word32* b, size_t len,
|
||||
word32 ctl);
|
||||
WOLFSSL_LOCAL word32 zint_mul_small(word32* m, size_t mlen, word32 x);
|
||||
WOLFSSL_LOCAL word32 zint_mod_small_unsigned(const word32* d, size_t dlen,
|
||||
word32 p, word32 p0i, word32 R2);
|
||||
WOLFSSL_LOCAL word32 zint_mod_small_signed(const word32* d, size_t dlen,
|
||||
word32 p, word32 p0i, word32 R2, word32 Rx);
|
||||
WOLFSSL_LOCAL void zint_add_mul_small(word32* x, const word32* y, size_t len,
|
||||
word32 s);
|
||||
WOLFSSL_LOCAL void zint_norm_zero(word32* x, const word32* p, size_t len);
|
||||
WOLFSSL_LOCAL void zint_rebuild_CRT(word32* xx, size_t xlen, size_t xstride,
|
||||
size_t num, const falcon_small_prime* primes, int normalize_signed,
|
||||
word32* tmp);
|
||||
WOLFSSL_LOCAL void zint_negate(word32* a, size_t len, word32 ctl);
|
||||
WOLFSSL_LOCAL word32 zint_co_reduce(word32* a, word32* b, size_t len,
|
||||
sword64 xa, sword64 xb, sword64 ya, sword64 yb);
|
||||
WOLFSSL_LOCAL void zint_finish_mod(word32* a, size_t len, const word32* m,
|
||||
word32 neg);
|
||||
WOLFSSL_LOCAL void zint_co_reduce_mod(word32* a, word32* b, const word32* m,
|
||||
size_t len, word32 m0i, sword64 xa, sword64 xb, sword64 ya,
|
||||
sword64 yb);
|
||||
WOLFSSL_LOCAL int zint_bezout(word32* u, word32* v, const word32* x,
|
||||
const word32* y, size_t len, word32* tmp);
|
||||
WOLFSSL_LOCAL void zint_add_scaled_mul_small(word32* x, size_t xlen,
|
||||
const word32* y, size_t ylen, sword32 k, word32 sch, word32 scl);
|
||||
WOLFSSL_LOCAL void zint_sub_scaled(word32* x, size_t xlen, const word32* y,
|
||||
size_t ylen, word32 sch, word32 scl);
|
||||
WOLFSSL_LOCAL sword32 zint_one_to_plain(const word32* x);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
#endif /* WOLF_CRYPT_WC_FALCON_BIGINT_H */
|
||||
@@ -0,0 +1,75 @@
|
||||
/* wc_falcon_codec.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* FN-DSA (FIPS 206 draft) / Falcon encode/decode routines for the
|
||||
* signing and key-generation paths. The verification-side decoders
|
||||
* (modq_decode, comp_decode) live as statics in wc_falcon.c and are not
|
||||
* referenced here. */
|
||||
|
||||
#ifndef FALCON_CODEC_H
|
||||
#define FALCON_CODEC_H
|
||||
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Golomb-Rice (k=7) compress of the signature polynomial s2. Exact inverse of
|
||||
* the reference comp_decode. Rejects any |x[i]| > 2047. Returns the number of
|
||||
* bytes written, or 0 on range violation / output overflow. */
|
||||
WOLFSSL_LOCAL size_t falcon_comp_encode(byte* out, size_t max_out,
|
||||
const sword16* x, unsigned logn);
|
||||
|
||||
/* 14-bit big-endian pack of the public-key polynomial h. Each coefficient must
|
||||
* be < q (12289). Returns the number of bytes written, or 0 on range violation
|
||||
* / output overflow. */
|
||||
WOLFSSL_LOCAL size_t falcon_modq_encode(byte* out, size_t max_out,
|
||||
const word16* x, unsigned logn);
|
||||
|
||||
/* Signed 8-bit polynomial pack/unpack using a fixed per-coefficient bit width.
|
||||
* The most-negative value -2^(bits-1) is forbidden (matching the reference). */
|
||||
WOLFSSL_LOCAL size_t falcon_trim_i8_encode(byte* out, size_t max_out,
|
||||
const sword8* x, unsigned logn, unsigned bits);
|
||||
WOLFSSL_LOCAL size_t falcon_trim_i8_decode(sword8* x, unsigned logn,
|
||||
unsigned bits, const byte* in, size_t max_in);
|
||||
|
||||
/* Decode a Falcon secret key: header byte (0x50 | logn), then trim_i8 encoded
|
||||
* f, g (max_fg_bits[logn]) and F (max_FG_bits[logn]). Validates the header and
|
||||
* that the input length is exactly consumed. Returns 0 on success or a negative
|
||||
* wolfCrypt error. */
|
||||
WOLFSSL_LOCAL int falcon_privkey_decode(const byte* sk, size_t sklen,
|
||||
sword8* f, sword8* g, sword8* F, unsigned logn);
|
||||
|
||||
/* Encode a Falcon secret key from (f, g, F). Inverse of falcon_privkey_decode.
|
||||
* Returns bytes written, or 0 on failure. */
|
||||
WOLFSSL_LOCAL size_t falcon_privkey_encode(byte* sk, size_t max_sk,
|
||||
const sword8* f, const sword8* g, const sword8* F, unsigned logn);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
|
||||
#endif /* FALCON_CODEC_H */
|
||||
@@ -0,0 +1,58 @@
|
||||
/* wc_falcon_fft.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/*!
|
||||
\file wolfssl/wolfcrypt/wc_falcon_fft.h
|
||||
*/
|
||||
|
||||
/* FN-DSA / Falcon FFT over the fpr seam. A real polynomial of n coefficients is
|
||||
* carried as n fpr values: the n/2 complex evaluations at the roots of x^n+1,
|
||||
* real parts in [0, n/2), imaginary parts in [n/2, n). Used by the Gaussian
|
||||
* sampler and signing; not needed for verification. */
|
||||
|
||||
#ifndef WOLF_CRYPT_WC_FALCON_FFT_H
|
||||
#define WOLF_CRYPT_WC_FALCON_FFT_H
|
||||
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_fpr.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Twiddle-factor table (correctly-rounded IEEE-754), shared with the poly_*
|
||||
* split/merge operations. falcon_gm_tab[2p+0]=cos, [2p+1]=sin. */
|
||||
WOLFSSL_LOCAL extern const fpr falcon_gm_tab[2048];
|
||||
|
||||
/* In-place forward FFT: coefficient representation -> FFT representation. */
|
||||
WOLFSSL_LOCAL void falcon_FFT(fpr* f, unsigned logn);
|
||||
/* In-place inverse FFT: FFT representation -> coefficient representation. */
|
||||
WOLFSSL_LOCAL void falcon_iFFT(fpr* f, unsigned logn);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
#endif /* WOLF_CRYPT_WC_FALCON_FFT_H */
|
||||
@@ -0,0 +1,142 @@
|
||||
/* wc_falcon_fpr.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/*!
|
||||
\file wolfssl/wolfcrypt/wc_falcon_fpr.h
|
||||
*/
|
||||
|
||||
/* The FN-DSA / Falcon floating-point primitive seam.
|
||||
*
|
||||
* Everything above this seam (FFT, Gaussian samplers, ffSampling, parts of
|
||||
* keygen) is written ONCE against the abstract fpr_* API declared here, and is
|
||||
* agnostic to the backend that implements it.
|
||||
*
|
||||
* Backends (selected at build time):
|
||||
* - EMULATED (default): fpr is the IEEE-754 bit pattern carried in a word64;
|
||||
* every operation is integer-only, fully deterministic and constant-time.
|
||||
* This is the portable wolfCrypt default (no floating-point unit required).
|
||||
* Implemented in wolfcrypt/src/wc_falcon_fpr.c.
|
||||
* - NATIVE/ASM (opt-in, WOLFSSL_FALCON_FPR_ASM): fpr is a C double; operations
|
||||
* map to per-architecture constant-time scalar FP (or DSP soft-float on
|
||||
* ARMv7/Cortex-M). Generated by ../wolfssl-scripts.
|
||||
*
|
||||
* CONTRACT: every backend MUST produce results bit-identical to round-to-
|
||||
* nearest-even IEEE-754 binary64. The Gaussian sampler's determinism and
|
||||
* side-channel resistance depend on this. Hardware VDIV/VSQRT and any denormal
|
||||
* path are forbidden in the asm backends (data-dependent timing). */
|
||||
|
||||
#ifndef WOLF_CRYPT_WC_FALCON_FPR_H
|
||||
#define WOLF_CRYPT_WC_FALCON_FPR_H
|
||||
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
|
||||
#if defined(HAVE_FALCON)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Backend selection. The emulated backend is the default; the native/asm
|
||||
* backend is opt-in and currently still carries the fpr value as a bit
|
||||
* pattern in a word64 so the seam type is uniform across translation units. */
|
||||
typedef word64 fpr;
|
||||
|
||||
/* -- Constructors / conversions / arithmetic / predicates --------------- */
|
||||
|
||||
#if defined(WOLFSSL_FALCON_FPR_DOUBLE)
|
||||
/* Inline native-double backend (opt-in). Maps the fpr seam onto the C double
|
||||
* type so the FFT/poly/sampler INLINE these scalar ops and keep values in FP
|
||||
* registers -- eliminating the per-op function call + GPR<->XMM shuffle that
|
||||
* dominate the out-of-line emulated/asm backends (~8x faster FP math, the bulk
|
||||
* of signing). Correctly-rounded IEEE-754 like the asm backend, with the same
|
||||
* constant-time-on-normals caveat: Falcon stays within normal range and the
|
||||
* caller must keep round-to-nearest-even (no FTZ/DAZ). fpr_expm_p63 and the fpr
|
||||
* constants still come from wc_falcon_fpr.c (which sees these inlines). */
|
||||
#include <math.h>
|
||||
static WC_INLINE double fpr__getd(fpr x) { double d; XMEMCPY(&d, &x, sizeof(d)); return d; }
|
||||
static WC_INLINE fpr fpr__setd(double d) { fpr x; XMEMCPY(&x, &d, sizeof(x)); return x; }
|
||||
static WC_INLINE fpr fpr_of(sword64 i) { return fpr__setd((double)i); }
|
||||
static WC_INLINE fpr fpr_scaled(sword64 i, int sc) { return fpr__setd(ldexp((double)i, sc)); }
|
||||
static WC_INLINE sword64 fpr_rint(fpr x) { double d = fpr__getd(x); return (sword64)llrint(d); }
|
||||
static WC_INLINE sword64 fpr_floor(fpr x) { double d = floor(fpr__getd(x)); return (sword64)d; }
|
||||
static WC_INLINE sword64 fpr_trunc(fpr x) { double d = trunc(fpr__getd(x)); return (sword64)d; }
|
||||
static WC_INLINE fpr fpr_add(fpr x, fpr y) { return fpr__setd(fpr__getd(x) + fpr__getd(y)); }
|
||||
static WC_INLINE fpr fpr_sub(fpr x, fpr y) { return fpr__setd(fpr__getd(x) - fpr__getd(y)); }
|
||||
static WC_INLINE fpr fpr_neg(fpr x) { return fpr__setd(-fpr__getd(x)); }
|
||||
static WC_INLINE fpr fpr_half(fpr x) { return fpr__setd(fpr__getd(x) * 0.5); }
|
||||
static WC_INLINE fpr fpr_double(fpr x) { return fpr__setd(fpr__getd(x) + fpr__getd(x)); }
|
||||
static WC_INLINE fpr fpr_mul(fpr x, fpr y) { return fpr__setd(fpr__getd(x) * fpr__getd(y)); }
|
||||
static WC_INLINE fpr fpr_sqr(fpr x) { double d = fpr__getd(x); return fpr__setd(d * d); }
|
||||
static WC_INLINE fpr fpr_inv(fpr x) { return fpr__setd(1.0 / fpr__getd(x)); }
|
||||
static WC_INLINE fpr fpr_div(fpr x, fpr y) { return fpr__setd(fpr__getd(x) / fpr__getd(y)); }
|
||||
static WC_INLINE fpr fpr_sqrt(fpr x) { return fpr__setd(sqrt(fpr__getd(x))); }
|
||||
static WC_INLINE int fpr_lt(fpr x, fpr y) { return fpr__getd(x) < fpr__getd(y); }
|
||||
#else
|
||||
/* Convert a signed integer to fpr (exact for |i| < 2^53). */
|
||||
WOLFSSL_LOCAL fpr fpr_of(sword64 i);
|
||||
/* Convert i*2^sc to fpr. */
|
||||
WOLFSSL_LOCAL fpr fpr_scaled(sword64 i, int sc);
|
||||
/* Round to nearest integer (ties to even); toward -inf; toward zero. */
|
||||
WOLFSSL_LOCAL sword64 fpr_rint(fpr x);
|
||||
WOLFSSL_LOCAL sword64 fpr_floor(fpr x);
|
||||
WOLFSSL_LOCAL sword64 fpr_trunc(fpr x);
|
||||
WOLFSSL_LOCAL fpr fpr_add(fpr x, fpr y);
|
||||
WOLFSSL_LOCAL fpr fpr_sub(fpr x, fpr y);
|
||||
WOLFSSL_LOCAL fpr fpr_neg(fpr x);
|
||||
WOLFSSL_LOCAL fpr fpr_half(fpr x);
|
||||
WOLFSSL_LOCAL fpr fpr_double(fpr x);
|
||||
WOLFSSL_LOCAL fpr fpr_mul(fpr x, fpr y);
|
||||
WOLFSSL_LOCAL fpr fpr_sqr(fpr x);
|
||||
WOLFSSL_LOCAL fpr fpr_inv(fpr x);
|
||||
WOLFSSL_LOCAL fpr fpr_div(fpr x, fpr y);
|
||||
WOLFSSL_LOCAL fpr fpr_sqrt(fpr x);
|
||||
/* Returns 1 if x < y, else 0. Must be constant-time w.r.t. operand values. */
|
||||
WOLFSSL_LOCAL int fpr_lt(fpr x, fpr y);
|
||||
#endif /* WOLFSSL_FALCON_FPR_DOUBLE */
|
||||
|
||||
/* -- Sampler support ---------------------------------------------------- */
|
||||
|
||||
/* Compute, in fixed point (scaled by 2^63), ccs * exp(-x), for the
|
||||
* Gaussian-sampler Bernoulli test (BerExp). x and ccs are non-negative and
|
||||
* x stays in a bounded range guaranteed by the caller. */
|
||||
WOLFSSL_LOCAL word64 fpr_expm_p63(fpr x, fpr ccs);
|
||||
|
||||
/* -- Named constants (defined by the active backend) -------------------- */
|
||||
|
||||
extern const fpr fpr_zero;
|
||||
extern const fpr fpr_one;
|
||||
extern const fpr fpr_two;
|
||||
extern const fpr fpr_onehalf;
|
||||
extern const fpr fpr_invsqrt2;
|
||||
extern const fpr fpr_invsqrt8;
|
||||
extern const fpr fpr_ptwo31; /* 2^31 */
|
||||
extern const fpr fpr_ptwo31m1; /* 2^31 - 1 */
|
||||
extern const fpr fpr_mtwo31m1; /* -(2^31 - 1) */
|
||||
extern const fpr fpr_ptwo63m1; /* 2^63 - 1 */
|
||||
extern const fpr fpr_mtwo63m1; /* -(2^63 - 1) */
|
||||
extern const fpr fpr_ptwo63; /* 2^63 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_FALCON */
|
||||
#endif /* WOLF_CRYPT_WC_FALCON_FPR_H */
|
||||
@@ -0,0 +1,80 @@
|
||||
/* wc_falcon_keygen.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/*!
|
||||
\file wolfssl/wolfcrypt/wc_falcon_keygen.h
|
||||
*/
|
||||
|
||||
/* FN-DSA / Falcon key-pair generation.
|
||||
*
|
||||
* Generates an (f, g, F, G) NTRU lattice basis together with the public key
|
||||
* h = g/f mod q. The procedure is a faithful port of the key-generation half
|
||||
* of the MIT-licensed Falcon reference implementation keygen.c (Thomas
|
||||
* Pornin):
|
||||
*
|
||||
* - sample f, g from a discrete Gaussian of standard deviation
|
||||
* 1.17*sqrt(q/(2n)), driven by a SHAKE256 stream seeded from a WC_RNG;
|
||||
* - reject (f, g) until the resultant with X^n+1 is odd, the (g,-f) norm
|
||||
* and the orthogonalized vector norm are below the 1.17*sqrt(q) bound,
|
||||
* and f is invertible modulo q;
|
||||
* - solve the NTRU equation f*G - g*F = q with the recursive "ntru_solve"
|
||||
* built on the validated big-integer / RNS layer (wc_falcon_bigint);
|
||||
* - return the basis and the public polynomial h.
|
||||
*
|
||||
* This module is excluded from verify-only builds (keygen is not needed
|
||||
* there) and depends on the floating-point seam (wc_falcon_fpr / fft / poly). */
|
||||
|
||||
#ifndef WOLF_CRYPT_WC_FALCON_KEYGEN_H
|
||||
#define WOLF_CRYPT_WC_FALCON_KEYGEN_H
|
||||
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#include <wolfssl/wolfcrypt/random.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Generate a complete FN-DSA / Falcon key pair of degree n = 2^logn.
|
||||
*
|
||||
* rng initialized WC_RNG used to seed the SHAKE256 sampler stream.
|
||||
* f,g output secret polynomials (n signed coefficients each).
|
||||
* F,G output NTRU completion polynomials (n signed coefficients each);
|
||||
* G may be reconstructed internally but is always written out here.
|
||||
* h output public key polynomial (n coefficients in [0, q)); may be
|
||||
* NULL if only the (f,g,F,G) basis is required.
|
||||
* logn base-2 logarithm of the ring degree (1..10; 9 and 10 are the
|
||||
* standardized FN-DSA-512 and FN-DSA-1024 levels).
|
||||
*
|
||||
* The routine loops, drawing fresh (f,g) until every acceptance test passes
|
||||
* and the NTRU equation is solved, exactly as the reference does. Returns 0
|
||||
* on success or a negative wolfCrypt error code. */
|
||||
WOLFSSL_LOCAL int falcon_keygen(WC_RNG* rng, sword8* f, sword8* g,
|
||||
sword8* F, sword8* G, word16* h, unsigned logn);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
#endif /* WOLF_CRYPT_WC_FALCON_KEYGEN_H */
|
||||
@@ -0,0 +1,126 @@
|
||||
/* wc_falcon_poly.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/*!
|
||||
\file wolfssl/wolfcrypt/wc_falcon_poly.h
|
||||
*/
|
||||
|
||||
/* FN-DSA / Falcon FFT-domain polynomial operations over the fpr seam. A real
|
||||
* polynomial of n coefficients is carried as n fpr values: the n/2 complex
|
||||
* evaluations at the roots of x^n+1, real parts in [0, n/2), imaginary parts in
|
||||
* [n/2, n) (see wc_falcon_fft.h). These primitives feed ffSampling and signing;
|
||||
* they are a faithful port of the poly_* functions from the MIT-licensed Falcon
|
||||
* reference implementation (fft.c, by Thomas Pornin). Not needed for
|
||||
* verification. */
|
||||
|
||||
#ifndef WOLF_CRYPT_WC_FALCON_POLY_H
|
||||
#define WOLF_CRYPT_WC_FALCON_POLY_H
|
||||
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_fpr.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* a <- a + b (coefficient-wise; valid in both coefficient and FFT domain). */
|
||||
WOLFSSL_LOCAL void falcon_poly_add(fpr* a, const fpr* b, unsigned logn);
|
||||
/* a <- a - b. */
|
||||
WOLFSSL_LOCAL void falcon_poly_sub(fpr* a, const fpr* b, unsigned logn);
|
||||
/* a <- -a. */
|
||||
WOLFSSL_LOCAL void falcon_poly_neg(fpr* a, unsigned logn);
|
||||
/* a <- adj(a): Hermitian adjoint (complex conjugate) in FFT representation. */
|
||||
WOLFSSL_LOCAL void falcon_poly_adj_fft(fpr* a, unsigned logn);
|
||||
/* a <- a * b (pointwise complex product) in FFT representation. */
|
||||
WOLFSSL_LOCAL void falcon_poly_mul_fft(fpr* a, const fpr* b, unsigned logn);
|
||||
/* a <- a * adj(b) (pointwise a * conj(b)) in FFT representation. */
|
||||
WOLFSSL_LOCAL void falcon_poly_muladj_fft(fpr* a, const fpr* b, unsigned logn);
|
||||
/* a <- a * adj(a) (real-valued result) in FFT representation. */
|
||||
WOLFSSL_LOCAL void falcon_poly_mulselfadj_fft(fpr* a, unsigned logn);
|
||||
/* a <- a * x (scalar multiply by fpr constant). */
|
||||
WOLFSSL_LOCAL void falcon_poly_mulconst(fpr* a, fpr x, unsigned logn);
|
||||
/* a <- a / b (pointwise complex divide) in FFT representation. */
|
||||
WOLFSSL_LOCAL void falcon_poly_div_fft(fpr* a, const fpr* b, unsigned logn);
|
||||
/* d <- 1 / (|a|^2 + |b|^2) (real-valued) in FFT representation. */
|
||||
WOLFSSL_LOCAL void falcon_poly_invnorm2_fft(fpr* d, const fpr* a, const fpr* b,
|
||||
unsigned logn);
|
||||
/* d <- F*adj(f) + G*adj(g) in FFT representation. */
|
||||
WOLFSSL_LOCAL void falcon_poly_add_muladj_fft(fpr* d, const fpr* F,
|
||||
const fpr* G, const fpr* f, const fpr* g, unsigned logn);
|
||||
/* a <- a * b where b is a self-adjoint (real) polynomial in FFT
|
||||
* representation; b is stored with only its real (lower) half meaningful. */
|
||||
WOLFSSL_LOCAL void falcon_poly_mul_autoadj_fft(fpr* a, const fpr* b,
|
||||
unsigned logn);
|
||||
/* a <- a / b where b is a self-adjoint (real) polynomial in FFT
|
||||
* representation; b is stored with only its real (lower) half meaningful. */
|
||||
WOLFSSL_LOCAL void falcon_poly_div_autoadj_fft(fpr* a, const fpr* b,
|
||||
unsigned logn);
|
||||
/* In-place LDL decomposition of the 2x2 Hermitian Gram matrix
|
||||
* [[g00, adj(g01)], [g01, g11]]: on output g11 holds D[1][1] and g01 holds
|
||||
* L[1][0]; g00 (= D[0][0]) is left unchanged. */
|
||||
WOLFSSL_LOCAL void falcon_poly_LDL_fft(const fpr* g00, fpr* g01, fpr* g11,
|
||||
unsigned logn);
|
||||
/* Same factorization as falcon_poly_LDL_fft but writing the results to
|
||||
* separate output buffers (d11, l10), leaving the inputs untouched. */
|
||||
WOLFSSL_LOCAL void falcon_poly_LDLmv_fft(fpr* d11, fpr* l10, const fpr* g00,
|
||||
const fpr* g01, const fpr* g11, unsigned logn);
|
||||
/* Split f (degree n) into the two half-degree polynomials f0, f1 (degree n/2)
|
||||
* in FFT representation. */
|
||||
WOLFSSL_LOCAL void falcon_poly_split_fft(fpr* f0, fpr* f1, const fpr* f,
|
||||
unsigned logn);
|
||||
/* Inverse of falcon_poly_split_fft: merge f0, f1 (degree n/2) into f (degree n)
|
||||
* in FFT representation. */
|
||||
WOLFSSL_LOCAL void falcon_poly_merge_fft(fpr* f, const fpr* f0, const fpr* f1,
|
||||
unsigned logn);
|
||||
|
||||
#if defined(WOLFSSL_FALCON_FFT_AVX2)
|
||||
/* AVX2 (__m256d + FMA) variants of the hot pointwise ops, provided by
|
||||
* wc_falcon_fft_avx2.c. The generic functions above delegate to these when the
|
||||
* AVX2 backend is selected. Semantically identical to their scalar twins
|
||||
* (FMA rounding differences are acceptable on the signing FFT path). */
|
||||
WOLFSSL_LOCAL void falcon_poly_mul_fft_avx2(fpr* a, const fpr* b, unsigned logn);
|
||||
WOLFSSL_LOCAL void falcon_poly_add_avx2(fpr* a, const fpr* b, unsigned logn);
|
||||
WOLFSSL_LOCAL void falcon_poly_sub_avx2(fpr* a, const fpr* b, unsigned logn);
|
||||
WOLFSSL_LOCAL void falcon_poly_mulconst_avx2(fpr* a, fpr x, unsigned logn);
|
||||
WOLFSSL_LOCAL void falcon_poly_muladj_fft_avx2(fpr* a, const fpr* b,
|
||||
unsigned logn);
|
||||
WOLFSSL_LOCAL void falcon_poly_mulselfadj_fft_avx2(fpr* a, unsigned logn);
|
||||
WOLFSSL_LOCAL void falcon_poly_invnorm2_fft_avx2(fpr* d, const fpr* a,
|
||||
const fpr* b, unsigned logn);
|
||||
WOLFSSL_LOCAL void falcon_poly_add_muladj_fft_avx2(fpr* d, const fpr* F,
|
||||
const fpr* G, const fpr* f, const fpr* g, unsigned logn);
|
||||
WOLFSSL_LOCAL void falcon_poly_LDLmv_fft_avx2(fpr* d11, fpr* l10,
|
||||
const fpr* g00, const fpr* g01, const fpr* g11, unsigned logn);
|
||||
WOLFSSL_LOCAL void falcon_poly_split_fft_avx2(fpr* f0, fpr* f1, const fpr* f,
|
||||
unsigned logn);
|
||||
WOLFSSL_LOCAL void falcon_poly_merge_fft_avx2(fpr* f, const fpr* f0,
|
||||
const fpr* f1, unsigned logn);
|
||||
#endif /* WOLFSSL_FALCON_FFT_AVX2 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
#endif /* WOLF_CRYPT_WC_FALCON_POLY_H */
|
||||
@@ -0,0 +1,107 @@
|
||||
/* wc_falcon_sampler.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/*!
|
||||
\file wolfssl/wolfcrypt/wc_falcon_sampler.h
|
||||
*/
|
||||
|
||||
/* Discrete Gaussian sampler for FN-DSA / Falcon signing (SamplerZ).
|
||||
*
|
||||
* This is a faithful port of the constant-time reference sampler by Thomas
|
||||
* Pornin (MIT-licensed Falcon reference implementation; the same code ships in
|
||||
* PQClean as PQCLEAN_FALCONxxx_CLEAN_gaussian0_sampler / BerExp / sampler).
|
||||
* The floating-point work is done exclusively through the abstract fpr_* seam
|
||||
* (wolfssl/wolfcrypt/wc_falcon_fpr.h), so the sampler inherits the deterministic
|
||||
* bit-exact, branch-free IEEE-754 behaviour of whatever fpr backend is active.
|
||||
*
|
||||
* SECURITY: the sampler is constant-time with respect to the secret center
|
||||
* (mu) and the secret inverse standard deviation (isigma). There are no
|
||||
* secret-dependent branches or memory accesses; see the notes in
|
||||
* wc_falcon_sampler.c. Randomness is drawn from a SHAKE256 stream seeded from a
|
||||
* WC_RNG instance. This file is compiled only on the signing side. */
|
||||
|
||||
#ifndef WOLF_CRYPT_WC_FALCON_SAMPLER_H
|
||||
#define WOLF_CRYPT_WC_FALCON_SAMPLER_H
|
||||
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_fpr.h>
|
||||
#include <wolfssl/wolfcrypt/sha3.h>
|
||||
#include <wolfssl/wolfcrypt/random.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* PRNG buffer: an integral number of SHAKE256 squeeze blocks (rate = 136
|
||||
* bytes). 136 is divisible by 8, so 8-byte reads never straddle the boundary
|
||||
* that triggers a refill. */
|
||||
#define FALCON_PRNG_BLOCKS 8
|
||||
#define FALCON_PRNG_BUFLEN (FALCON_PRNG_BLOCKS * WC_SHA3_256_BLOCK_SIZE)
|
||||
|
||||
/* SHAKE256-backed pseudo-random byte stream.
|
||||
*
|
||||
* Construction: the SHAKE256 sponge absorbs a seed obtained from WC_RNG
|
||||
* (FALCON_PRNG_SEED_LEN fresh random bytes), then is squeezed in fixed-size
|
||||
* blocks. get_u8 returns the next stream byte; get_u64 returns the next 8
|
||||
* stream bytes interpreted little-endian. */
|
||||
typedef struct falcon_prng {
|
||||
wc_Shake shake; /* SHAKE256 sponge state */
|
||||
byte buf[FALCON_PRNG_BUFLEN];/* squeezed stream buffer */
|
||||
word32 ptr; /* index of next byte to consume */
|
||||
word32 len; /* number of valid bytes in buf */
|
||||
} falcon_prng;
|
||||
|
||||
/* Sampler context: the PRNG plus the parameter-set-dependent sigma_min. */
|
||||
typedef struct falcon_sampler_ctx {
|
||||
falcon_prng p;
|
||||
fpr sigma_min; /* sigma_min for the active logn */
|
||||
} falcon_sampler_ctx;
|
||||
|
||||
/* Seed length (bytes) drawn from WC_RNG to key the SHAKE256 stream. */
|
||||
#define FALCON_PRNG_SEED_LEN 56
|
||||
|
||||
/* PRNG primitives. */
|
||||
WOLFSSL_LOCAL int falcon_prng_init(falcon_prng* p, WC_RNG* rng);
|
||||
WOLFSSL_LOCAL byte falcon_prng_get_u8(falcon_prng* p);
|
||||
WOLFSSL_LOCAL word64 falcon_prng_get_u64(falcon_prng* p);
|
||||
|
||||
/* Initialise a sampler context for the given degree (logn = 9 or 10), seeding
|
||||
* the PRNG from rng. Returns 0 on success or a negative wolfCrypt error. */
|
||||
WOLFSSL_LOCAL int falcon_sampler_init(falcon_sampler_ctx* spc, int logn,
|
||||
WC_RNG* rng);
|
||||
|
||||
/* The base half-Gaussian sampler (z >= 0, sigma0 = 1.8205). Exposed for test
|
||||
* harnesses; consumes 9 PRNG bytes. */
|
||||
WOLFSSL_LOCAL int falcon_gaussian0(falcon_prng* p);
|
||||
|
||||
/* SamplerZ: return an integer sampled from the discrete Gaussian of center mu
|
||||
* and standard deviation 1/isigma. ctx is a (falcon_sampler_ctx*). */
|
||||
WOLFSSL_LOCAL int falcon_sampler_z(void* ctx, fpr mu, fpr isigma);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
#endif /* WOLF_CRYPT_WC_FALCON_SAMPLER_H */
|
||||
@@ -0,0 +1,124 @@
|
||||
/* wc_falcon_sign.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/*!
|
||||
\file wolfssl/wolfcrypt/wc_falcon_sign.h
|
||||
*/
|
||||
|
||||
/* FN-DSA / Falcon signing orchestration (the "tree" signer).
|
||||
*
|
||||
* Faithful port of the signature-generation core of the MIT-licensed Falcon
|
||||
* reference implementation sign.c (Thomas Pornin, Falcon Project, 2017-2019):
|
||||
*
|
||||
* - falcon_complete_private: recompute G from (f, g, F) using the NTRU
|
||||
* relation f*G - g*F = q (so G = (g*F + q)/f), via the FFT seam.
|
||||
* - falcon_expand_privkey: build the B0 = [[g, -f], [G, -F]] basis in FFT
|
||||
* representation, the Gram matrix G = B*B^*, and the normalized ffLDL
|
||||
* tree (the "expanded private key").
|
||||
* - falcon_ffSampling_fft: the Fast Fourier sampling recursion driving the
|
||||
* discrete Gaussian sampler over the ffLDL tree.
|
||||
* - falcon_do_sign_tree / falcon_sign_core: produce the signature short
|
||||
* vector s2, looping over the sampler until the (s1, s2) squared l2-norm
|
||||
* is within the Falcon acceptance bound.
|
||||
*
|
||||
* The floating-point work flows exclusively through the abstract fpr_* seam
|
||||
* (wc_falcon_fpr.h), the FFT (wc_falcon_fft.h) and the FFT-domain polynomial
|
||||
* primitives (wc_falcon_poly.h); randomness for the sampler comes from the
|
||||
* SHAKE256-backed sampler context (wc_falcon_sampler.h). This module is
|
||||
* compiled only on the signing side. */
|
||||
|
||||
#ifndef WOLF_CRYPT_WC_FALCON_SIGN_H
|
||||
#define WOLF_CRYPT_WC_FALCON_SIGN_H
|
||||
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
|
||||
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
|
||||
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_fpr.h>
|
||||
#include <wolfssl/wolfcrypt/wc_falcon_sampler.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Number of fpr elements in an expanded private key for degree n = 2^logn.
|
||||
* Layout: the four B0 matrix polynomials (b00, b01, b10, b11), each of n
|
||||
* elements, followed by the ffLDL tree of (logn+1)*2^logn elements. The total
|
||||
* is therefore (logn+5)*2^logn fpr (matching the reference's (8*logn+40)*2^logn
|
||||
* bytes). */
|
||||
#define FALCON_EXPANDED_KEY_FPR(logn) (((size_t)((logn) + 5)) << (logn))
|
||||
|
||||
/* Number of fpr elements of scratch required by falcon_do_sign_tree /
|
||||
* falcon_sign_core (six polynomials of degree n), matching the reference's
|
||||
* 48*2^logn bytes. */
|
||||
#define FALCON_SIGN_TMP_FPR(logn) ((size_t)6 << (logn))
|
||||
|
||||
/* The discrete-Gaussian sampler callback type used by ffSampling. The second
|
||||
* argument is the center mu, the third the inverse standard deviation isigma.
|
||||
* falcon_sampler_z (wc_falcon_sampler.h) implements this contract. */
|
||||
typedef int (*falcon_samplerZ)(void* ctx, fpr mu, fpr isigma);
|
||||
|
||||
/* Recompute the NTRU completion polynomial G from (f, g, F) such that
|
||||
* f*G - g*F = q (G = (g*F + q)/f), computed over the FFT seam and rounded to
|
||||
* integers. G receives n signed coefficients. For a well-formed key the
|
||||
* quotient is exact; a rounded coefficient outside the [-127, 127] range is
|
||||
* rejected (this also catches a grossly inconsistent/corrupt key). Returns 0 on
|
||||
* success, or a negative wolfCrypt error on out-of-range coefficient or memory
|
||||
* allocation failure. */
|
||||
WOLFSSL_LOCAL int falcon_complete_private(sword8* G, const sword8* f,
|
||||
const sword8* g, const sword8* F, unsigned logn);
|
||||
|
||||
/* Expand the private basis (f, g, F, G) into 'expanded' (which must hold
|
||||
* FALCON_EXPANDED_KEY_FPR(logn) fpr elements): the B0 matrix in FFT
|
||||
* representation and the normalized ffLDL tree. Allocates an internal scratch
|
||||
* of FALCON_SIGN_TMP_FPR(logn) fpr. Returns 0 on success or a negative
|
||||
* wolfCrypt error. */
|
||||
WOLFSSL_LOCAL int falcon_expand_privkey(fpr* expanded, const sword8* f,
|
||||
const sword8* g, const sword8* F, const sword8* G, unsigned logn);
|
||||
|
||||
/* Fast Fourier sampling: sample the target (t0, t1) against the ffLDL 'tree',
|
||||
* writing the sampled lattice coordinates into (z0, z1). 'tmp' needs room for
|
||||
* at least two polynomials of degree 2^logn. Faithful port of the reference
|
||||
* ffSampling_fft. */
|
||||
WOLFSSL_LOCAL void falcon_ffSampling_fft(falcon_samplerZ samp, void* samp_ctx,
|
||||
fpr* z0, fpr* z1, const fpr* tree, const fpr* t0, const fpr* t1,
|
||||
unsigned logn, fpr* tmp);
|
||||
|
||||
/* Produce the signature short vector s2 (n sword16 values) from the expanded
|
||||
* key and hashed point hm (n word16 values in [0, q)). Loops over the sampler
|
||||
* until the (s1, s2) squared l2-norm is within the Falcon bound. 'tmp' must
|
||||
* hold FALCON_SIGN_TMP_FPR(logn) fpr. Returns 0 on success. */
|
||||
WOLFSSL_LOCAL int falcon_do_sign_tree(falcon_samplerZ samp, void* samp_ctx,
|
||||
sword16* s2, const fpr* expanded, const word16* hm, unsigned logn,
|
||||
fpr* tmp);
|
||||
|
||||
/* Convenience top-level: sign hashed point c with the expanded key, using the
|
||||
* provided (already initialized) sampler context, writing s2. 'tmp' must hold
|
||||
* FALCON_SIGN_TMP_FPR(logn) fpr. Returns 0 on success. */
|
||||
WOLFSSL_LOCAL int falcon_sign_core(falcon_sampler_ctx* spc, const fpr* expanded,
|
||||
const word16* c, sword16* s2, fpr* tmp, unsigned logn);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_FALCON && !WOLFSSL_FALCON_VERIFY_ONLY */
|
||||
#endif /* WOLF_CRYPT_WC_FALCON_SIGN_H */
|
||||
Reference in New Issue
Block a user