![jonathan@leto.net](/assets/img/avatar_default.png)
committed by
GitHub
![GitHub](/assets/img/avatar_default.png)
244 changed files with 3494 additions and 2796 deletions
@ -0,0 +1,568 @@ |
|||
# =========================================================================== |
|||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html |
|||
# =========================================================================== |
|||
# |
|||
# SYNOPSIS |
|||
# |
|||
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) |
|||
# |
|||
# DESCRIPTION |
|||
# |
|||
# Check for baseline language coverage in the compiler for the specified |
|||
# version of the C++ standard. If necessary, add switches to CXX and |
|||
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) |
|||
# or '14' (for the C++14 standard). |
|||
# |
|||
# The second argument, if specified, indicates whether you insist on an |
|||
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. |
|||
# -std=c++11). If neither is specified, you get whatever works, with |
|||
# preference for an extended mode. |
|||
# |
|||
# The third argument, if specified 'mandatory' or if left unspecified, |
|||
# indicates that baseline support for the specified C++ standard is |
|||
# required and that the macro should error out if no mode with that |
|||
# support is found. If specified 'optional', then configuration proceeds |
|||
# regardless, after defining HAVE_CXX${VERSION} if and only if a |
|||
# supporting mode is found. |
|||
# |
|||
# LICENSE |
|||
# |
|||
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com> |
|||
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com> |
|||
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu> |
|||
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com> |
|||
# Copyright (c) 2015 Paul Norman <penorman@mac.com> |
|||
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu> |
|||
# |
|||
# Copying and distribution of this file, with or without modification, are |
|||
# permitted in any medium without royalty provided the copyright notice |
|||
# and this notice are preserved. This file is offered as-is, without any |
|||
# warranty. |
|||
|
|||
#serial 4 |
|||
|
|||
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro |
|||
dnl (serial version number 13). |
|||
|
|||
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl |
|||
m4_if([$1], [11], [], |
|||
[$1], [14], [], |
|||
[$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])], |
|||
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl |
|||
m4_if([$2], [], [], |
|||
[$2], [ext], [], |
|||
[$2], [noext], [], |
|||
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl |
|||
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], |
|||
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], |
|||
[$3], [optional], [ax_cxx_compile_cxx$1_required=false], |
|||
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) |
|||
m4_if([$4], [], [ax_cxx_compile_cxx$1_try_default=true], |
|||
[$4], [default], [ax_cxx_compile_cxx$1_try_default=true], |
|||
[$4], [nodefault], [ax_cxx_compile_cxx$1_try_default=false], |
|||
[m4_fatal([invalid fourth argument `$4' to AX_CXX_COMPILE_STDCXX])]) |
|||
AC_LANG_PUSH([C++])dnl |
|||
ac_success=no |
|||
|
|||
m4_if([$4], [nodefault], [], [dnl |
|||
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, |
|||
ax_cv_cxx_compile_cxx$1, |
|||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], |
|||
[ax_cv_cxx_compile_cxx$1=yes], |
|||
[ax_cv_cxx_compile_cxx$1=no])]) |
|||
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then |
|||
ac_success=yes |
|||
fi]) |
|||
|
|||
m4_if([$2], [noext], [], [dnl |
|||
if test x$ac_success = xno; then |
|||
for switch in -std=gnu++$1 -std=gnu++0x; do |
|||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) |
|||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, |
|||
$cachevar, |
|||
[ac_save_CXX="$CXX" |
|||
CXX="$CXX $switch" |
|||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], |
|||
[eval $cachevar=yes], |
|||
[eval $cachevar=no]) |
|||
CXX="$ac_save_CXX"]) |
|||
if eval test x\$$cachevar = xyes; then |
|||
CXX="$CXX $switch" |
|||
if test -n "$CXXCPP" ; then |
|||
CXXCPP="$CXXCPP $switch" |
|||
fi |
|||
ac_success=yes |
|||
break |
|||
fi |
|||
done |
|||
fi]) |
|||
|
|||
m4_if([$2], [ext], [], [dnl |
|||
if test x$ac_success = xno; then |
|||
dnl HP's aCC needs +std=c++11 according to: |
|||
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf |
|||
dnl Cray's crayCC needs "-h std=c++11" |
|||
for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do |
|||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) |
|||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, |
|||
$cachevar, |
|||
[ac_save_CXX="$CXX" |
|||
CXX="$CXX $switch" |
|||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], |
|||
[eval $cachevar=yes], |
|||
[eval $cachevar=no]) |
|||
CXX="$ac_save_CXX"]) |
|||
if eval test x\$$cachevar = xyes; then |
|||
CXX="$CXX $switch" |
|||
if test -n "$CXXCPP" ; then |
|||
CXXCPP="$CXXCPP $switch" |
|||
fi |
|||
ac_success=yes |
|||
break |
|||
fi |
|||
done |
|||
fi]) |
|||
AC_LANG_POP([C++]) |
|||
if test x$ax_cxx_compile_cxx$1_required = xtrue; then |
|||
if test x$ac_success = xno; then |
|||
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) |
|||
fi |
|||
fi |
|||
if test x$ac_success = xno; then |
|||
HAVE_CXX$1=0 |
|||
AC_MSG_NOTICE([No compiler with C++$1 support was found]) |
|||
else |
|||
HAVE_CXX$1=1 |
|||
AC_DEFINE(HAVE_CXX$1,1, |
|||
[define if the compiler supports basic C++$1 syntax]) |
|||
fi |
|||
AC_SUBST(HAVE_CXX$1) |
|||
]) |
|||
|
|||
|
|||
dnl Test body for checking C++11 support |
|||
|
|||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], |
|||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 |
|||
) |
|||
|
|||
|
|||
dnl Test body for checking C++14 support |
|||
|
|||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], |
|||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 |
|||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14 |
|||
) |
|||
|
|||
|
|||
dnl Tests for new features in C++11 |
|||
|
|||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ |
|||
|
|||
// If the compiler admits that it is not ready for C++11, why torture it? |
|||
// Hopefully, this will speed up the test. |
|||
|
|||
#ifndef __cplusplus |
|||
|
|||
#error "This is not a C++ compiler" |
|||
|
|||
#elif __cplusplus < 201103L |
|||
|
|||
#error "This is not a C++11 compiler" |
|||
|
|||
#else |
|||
|
|||
namespace cxx11 |
|||
{ |
|||
|
|||
namespace test_static_assert |
|||
{ |
|||
|
|||
template <typename T> |
|||
struct check |
|||
{ |
|||
static_assert(sizeof(int) <= sizeof(T), "not big enough"); |
|||
}; |
|||
|
|||
} |
|||
|
|||
namespace test_final_override |
|||
{ |
|||
|
|||
struct Base |
|||
{ |
|||
virtual void f() {} |
|||
}; |
|||
|
|||
struct Derived : public Base |
|||
{ |
|||
virtual void f() override {} |
|||
}; |
|||
|
|||
} |
|||
|
|||
namespace test_double_right_angle_brackets |
|||
{ |
|||
|
|||
template < typename T > |
|||
struct check {}; |
|||
|
|||
typedef check<void> single_type; |
|||
typedef check<check<void>> double_type; |
|||
typedef check<check<check<void>>> triple_type; |
|||
typedef check<check<check<check<void>>>> quadruple_type; |
|||
|
|||
} |
|||
|
|||
namespace test_decltype |
|||
{ |
|||
|
|||
int |
|||
f() |
|||
{ |
|||
int a = 1; |
|||
decltype(a) b = 2; |
|||
return a + b; |
|||
} |
|||
|
|||
} |
|||
|
|||
namespace test_type_deduction |
|||
{ |
|||
|
|||
template < typename T1, typename T2 > |
|||
struct is_same |
|||
{ |
|||
static const bool value = false; |
|||
}; |
|||
|
|||
template < typename T > |
|||
struct is_same<T, T> |
|||
{ |
|||
static const bool value = true; |
|||
}; |
|||
|
|||
template < typename T1, typename T2 > |
|||
auto |
|||
add(T1 a1, T2 a2) -> decltype(a1 + a2) |
|||
{ |
|||
return a1 + a2; |
|||
} |
|||
|
|||
int |
|||
test(const int c, volatile int v) |
|||
{ |
|||
static_assert(is_same<int, decltype(0)>::value == true, ""); |
|||
static_assert(is_same<int, decltype(c)>::value == false, ""); |
|||
static_assert(is_same<int, decltype(v)>::value == false, ""); |
|||
auto ac = c; |
|||
auto av = v; |
|||
auto sumi = ac + av + 'x'; |
|||
auto sumf = ac + av + 1.0; |
|||
static_assert(is_same<int, decltype(ac)>::value == true, ""); |
|||
static_assert(is_same<int, decltype(av)>::value == true, ""); |
|||
static_assert(is_same<int, decltype(sumi)>::value == true, ""); |
|||
static_assert(is_same<int, decltype(sumf)>::value == false, ""); |
|||
static_assert(is_same<int, decltype(add(c, v))>::value == true, ""); |
|||
return (sumf > 0.0) ? sumi : add(c, v); |
|||
} |
|||
|
|||
} |
|||
|
|||
namespace test_noexcept |
|||
{ |
|||
|
|||
int f() { return 0; } |
|||
int g() noexcept { return 0; } |
|||
|
|||
static_assert(noexcept(f()) == false, ""); |
|||
static_assert(noexcept(g()) == true, ""); |
|||
|
|||
} |
|||
|
|||
namespace test_constexpr |
|||
{ |
|||
|
|||
template < typename CharT > |
|||
unsigned long constexpr |
|||
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept |
|||
{ |
|||
return *s ? strlen_c_r(s + 1, acc + 1) : acc; |
|||
} |
|||
|
|||
template < typename CharT > |
|||
unsigned long constexpr |
|||
strlen_c(const CharT *const s) noexcept |
|||
{ |
|||
return strlen_c_r(s, 0UL); |
|||
} |
|||
|
|||
static_assert(strlen_c("") == 0UL, ""); |
|||
static_assert(strlen_c("1") == 1UL, ""); |
|||
static_assert(strlen_c("example") == 7UL, ""); |
|||
static_assert(strlen_c("another\0example") == 7UL, ""); |
|||
|
|||
} |
|||
|
|||
namespace test_rvalue_references |
|||
{ |
|||
|
|||
template < int N > |
|||
struct answer |
|||
{ |
|||
static constexpr int value = N; |
|||
}; |
|||
|
|||
answer<1> f(int&) { return answer<1>(); } |
|||
answer<2> f(const int&) { return answer<2>(); } |
|||
answer<3> f(int&&) { return answer<3>(); } |
|||
|
|||
void |
|||
test() |
|||
{ |
|||
int i = 0; |
|||
const int c = 0; |
|||
static_assert(decltype(f(i))::value == 1, ""); |
|||
static_assert(decltype(f(c))::value == 2, ""); |
|||
static_assert(decltype(f(0))::value == 3, ""); |
|||
} |
|||
|
|||
} |
|||
|
|||
namespace test_uniform_initialization |
|||
{ |
|||
|
|||
struct test |
|||
{ |
|||
static const int zero {}; |
|||
static const int one {1}; |
|||
}; |
|||
|
|||
static_assert(test::zero == 0, ""); |
|||
static_assert(test::one == 1, ""); |
|||
|
|||
} |
|||
|
|||
namespace test_lambdas |
|||
{ |
|||
|
|||
void |
|||
test1() |
|||
{ |
|||
auto lambda1 = [](){}; |
|||
auto lambda2 = lambda1; |
|||
lambda1(); |
|||
lambda2(); |
|||
} |
|||
|
|||
int |
|||
test2() |
|||
{ |
|||
auto a = [](int i, int j){ return i + j; }(1, 2); |
|||
auto b = []() -> int { return '0'; }(); |
|||
auto c = [=](){ return a + b; }(); |
|||
auto d = [&](){ return c; }(); |
|||
auto e = [a, &b](int x) mutable { |
|||
const auto identity = [](int y){ return y; }; |
|||
for (auto i = 0; i < a; ++i) |
|||
a += b--; |
|||
return x + identity(a + b); |
|||
}(0); |
|||
return a + b + c + d + e; |
|||
} |
|||
|
|||
int |
|||
test3() |
|||
{ |
|||
const auto nullary = [](){ return 0; }; |
|||
const auto unary = [](int x){ return x; }; |
|||
using nullary_t = decltype(nullary); |
|||
using unary_t = decltype(unary); |
|||
const auto higher1st = [](nullary_t f){ return f(); }; |
|||
const auto higher2nd = [unary](nullary_t f1){ |
|||
return [unary, f1](unary_t f2){ return f2(unary(f1())); }; |
|||
}; |
|||
return higher1st(nullary) + higher2nd(nullary)(unary); |
|||
} |
|||
|
|||
} |
|||
|
|||
namespace test_variadic_templates |
|||
{ |
|||
|
|||
template <int...> |
|||
struct sum; |
|||
|
|||
template <int N0, int... N1toN> |
|||
struct sum<N0, N1toN...> |
|||
{ |
|||
static constexpr auto value = N0 + sum<N1toN...>::value; |
|||
}; |
|||
|
|||
template <> |
|||
struct sum<> |
|||
{ |
|||
static constexpr auto value = 0; |
|||
}; |
|||
|
|||
static_assert(sum<>::value == 0, ""); |
|||
static_assert(sum<1>::value == 1, ""); |
|||
static_assert(sum<23>::value == 23, ""); |
|||
static_assert(sum<1, 2>::value == 3, ""); |
|||
static_assert(sum<5, 5, 11>::value == 21, ""); |
|||
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); |
|||
|
|||
} |
|||
|
|||
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae |
|||
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function |
|||
// because of this. |
|||
namespace test_template_alias_sfinae |
|||
{ |
|||
|
|||
struct foo {}; |
|||
|
|||
template<typename T> |
|||
using member = typename T::member_type; |
|||
|
|||
template<typename T> |
|||
void func(...) {} |
|||
|
|||
template<typename T> |
|||
void func(member<T>*) {} |
|||
|
|||
void test(); |
|||
|
|||
void test() { func<foo>(0); } |
|||
|
|||
} |
|||
|
|||
} // namespace cxx11 |
|||
|
|||
#endif // __cplusplus >= 201103L |
|||
|
|||
]]) |
|||
|
|||
|
|||
dnl Tests for new features in C++14 |
|||
|
|||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ |
|||
|
|||
// If the compiler admits that it is not ready for C++14, why torture it? |
|||
// Hopefully, this will speed up the test. |
|||
|
|||
#ifndef __cplusplus |
|||
|
|||
#error "This is not a C++ compiler" |
|||
|
|||
#elif __cplusplus < 201402L |
|||
|
|||
#error "This is not a C++14 compiler" |
|||
|
|||
#else |
|||
|
|||
namespace cxx14 |
|||
{ |
|||
|
|||
namespace test_polymorphic_lambdas |
|||
{ |
|||
|
|||
int |
|||
test() |
|||
{ |
|||
const auto lambda = [](auto&&... args){ |
|||
const auto istiny = [](auto x){ |
|||
return (sizeof(x) == 1UL) ? 1 : 0; |
|||
}; |
|||
const int aretiny[] = { istiny(args)... }; |
|||
return aretiny[0]; |
|||
}; |
|||
return lambda(1, 1L, 1.0f, '1'); |
|||
} |
|||
|
|||
} |
|||
|
|||
namespace test_binary_literals |
|||
{ |
|||
|
|||
constexpr auto ivii = 0b0000000000101010; |
|||
static_assert(ivii == 42, "wrong value"); |
|||
|
|||
} |
|||
|
|||
namespace test_generalized_constexpr |
|||
{ |
|||
|
|||
template < typename CharT > |
|||
constexpr unsigned long |
|||
strlen_c(const CharT *const s) noexcept |
|||
{ |
|||
auto length = 0UL; |
|||
for (auto p = s; *p; ++p) |
|||
++length; |
|||
return length; |
|||
} |
|||
|
|||
static_assert(strlen_c("") == 0UL, ""); |
|||
static_assert(strlen_c("x") == 1UL, ""); |
|||
static_assert(strlen_c("test") == 4UL, ""); |
|||
static_assert(strlen_c("another\0test") == 7UL, ""); |
|||
|
|||
} |
|||
|
|||
namespace test_lambda_init_capture |
|||
{ |
|||
|
|||
int |
|||
test() |
|||
{ |
|||
auto x = 0; |
|||
const auto lambda1 = [a = x](int b){ return a + b; }; |
|||
const auto lambda2 = [a = lambda1(x)](){ return a; }; |
|||
return lambda2(); |
|||
} |
|||
|
|||
} |
|||
|
|||
namespace test_digit_seperators |
|||
{ |
|||
|
|||
constexpr auto ten_million = 100'000'000; |
|||
static_assert(ten_million == 100000000, ""); |
|||
|
|||
} |
|||
|
|||
namespace test_return_type_deduction |
|||
{ |
|||
|
|||
auto f(int& x) { return x; } |
|||
decltype(auto) g(int& x) { return x; } |
|||
|
|||
template < typename T1, typename T2 > |
|||
struct is_same |
|||
{ |
|||
static constexpr auto value = false; |
|||
}; |
|||
|
|||
template < typename T > |
|||
struct is_same<T, T> |
|||
{ |
|||
static constexpr auto value = true; |
|||
}; |
|||
|
|||
int |
|||
test() |
|||
{ |
|||
auto x = 0; |
|||
static_assert(is_same<int, decltype(f(x))>::value, ""); |
|||
static_assert(is_same<int&, decltype(g(x))>::value, ""); |
|||
return x; |
|||
} |
|||
|
|||
} |
|||
|
|||
} // namespace cxx14 |
|||
|
|||
#endif // __cplusplus >= 201402L |
|||
|
|||
]]) |
@ -0,0 +1,123 @@ |
|||
# =========================================================================== |
|||
# https://www.gnu.org/software/autoconf-archive/ax_openmp.html |
|||
# =========================================================================== |
|||
# |
|||
# SYNOPSIS |
|||
# |
|||
# AX_OPENMP([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) |
|||
# |
|||
# DESCRIPTION |
|||
# |
|||
# This macro tries to find out how to compile programs that use OpenMP a |
|||
# standard API and set of compiler directives for parallel programming |
|||
# (see http://www-unix.mcs/) |
|||
# |
|||
# On success, it sets the OPENMP_CFLAGS/OPENMP_CXXFLAGS/OPENMP_F77FLAGS |
|||
# output variable to the flag (e.g. -omp) used both to compile *and* link |
|||
# OpenMP programs in the current language. |
|||
# |
|||
# NOTE: You are assumed to not only compile your program with these flags, |
|||
# but also link it with them as well. |
|||
# |
|||
# If you want to compile everything with OpenMP, you should set: |
|||
# |
|||
# CFLAGS="$CFLAGS $OPENMP_CFLAGS" |
|||
# #OR# CXXFLAGS="$CXXFLAGS $OPENMP_CXXFLAGS" |
|||
# #OR# FFLAGS="$FFLAGS $OPENMP_FFLAGS" |
|||
# |
|||
# (depending on the selected language). |
|||
# |
|||
# The user can override the default choice by setting the corresponding |
|||
# environment variable (e.g. OPENMP_CFLAGS). |
|||
# |
|||
# ACTION-IF-FOUND is a list of shell commands to run if an OpenMP flag is |
|||
# found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it is |
|||
# not found. If ACTION-IF-FOUND is not specified, the default action will |
|||
# define HAVE_OPENMP. |
|||
# |
|||
# LICENSE |
|||
# |
|||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu> |
|||
# Copyright (c) 2015 John W. Peterson <jwpeterson@gmail.com> |
|||
# Copyright (c) 2016 Nick R. Papior <nickpapior@gmail.com> |
|||
# |
|||
# This program 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. |
|||
# |
|||
# This program 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, see <https://www.gnu.org/licenses/>. |
|||
# |
|||
# As a special exception, the respective Autoconf Macro's copyright owner |
|||
# gives unlimited permission to copy, distribute and modify the configure |
|||
# scripts that are the output of Autoconf when processing the Macro. You |
|||
# need not follow the terms of the GNU General Public License when using |
|||
# or distributing such scripts, even though portions of the text of the |
|||
# Macro appear in them. The GNU General Public License (GPL) does govern |
|||
# all other use of the material that constitutes the Autoconf Macro. |
|||
# |
|||
# This special exception to the GPL applies to versions of the Autoconf |
|||
# Macro released by the Autoconf Archive. When you make and distribute a |
|||
# modified version of the Autoconf Macro, you may extend this special |
|||
# exception to the GPL to apply to your modified version as well. |
|||
|
|||
#serial 13 |
|||
|
|||
AC_DEFUN([AX_OPENMP], [ |
|||
AC_PREREQ([2.69]) dnl for _AC_LANG_PREFIX |
|||
|
|||
AC_CACHE_CHECK([for OpenMP flag of _AC_LANG compiler], ax_cv_[]_AC_LANG_ABBREV[]_openmp, [save[]_AC_LANG_PREFIX[]FLAGS=$[]_AC_LANG_PREFIX[]FLAGS |
|||
ax_cv_[]_AC_LANG_ABBREV[]_openmp=unknown |
|||
# Flags to try: -fopenmp (gcc), -mp (SGI & PGI), |
|||
# -qopenmp (icc>=15), -openmp (icc), |
|||
# -xopenmp (Sun), -omp (Tru64), |
|||
# -qsmp=omp (AIX), |
|||
# none |
|||
ax_openmp_flags="-fopenmp -openmp -qopenmp -mp -xopenmp -omp -qsmp=omp none" |
|||
if test "x$OPENMP_[]_AC_LANG_PREFIX[]FLAGS" != x; then |
|||
ax_openmp_flags="$OPENMP_[]_AC_LANG_PREFIX[]FLAGS $ax_openmp_flags" |
|||
fi |
|||
for ax_openmp_flag in $ax_openmp_flags; do |
|||
case $ax_openmp_flag in |
|||
none) []_AC_LANG_PREFIX[]FLAGS=$save[]_AC_LANG_PREFIX[] ;; |
|||
*) []_AC_LANG_PREFIX[]FLAGS="$save[]_AC_LANG_PREFIX[]FLAGS $ax_openmp_flag" ;; |
|||
esac |
|||
AC_LINK_IFELSE([AC_LANG_SOURCE([[ |
|||
@%:@include <omp.h> |
|||
|
|||
static void |
|||
parallel_fill(int * data, int n) |
|||
{ |
|||
int i; |
|||
@%:@pragma omp parallel for |
|||
for (i = 0; i < n; ++i) |
|||
data[i] = i; |
|||
} |
|||
|
|||
int |
|||
main() |
|||
{ |
|||
int arr[100000]; |
|||
omp_set_num_threads(2); |
|||
parallel_fill(arr, 100000); |
|||
return 0; |
|||
} |
|||
]])],[ax_cv_[]_AC_LANG_ABBREV[]_openmp=$ax_openmp_flag; break],[]) |
|||
done |
|||
[]_AC_LANG_PREFIX[]FLAGS=$save[]_AC_LANG_PREFIX[]FLAGS |
|||
]) |
|||
if test "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" = "xunknown"; then |
|||
m4_default([$2],:) |
|||
else |
|||
if test "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" != "xnone"; then |
|||
OPENMP_[]_AC_LANG_PREFIX[]FLAGS=$ax_cv_[]_AC_LANG_ABBREV[]_openmp |
|||
fi |
|||
m4_default([$1], [AC_DEFINE(HAVE_OPENMP,1,[Define if OpenMP is enabled])]) |
|||
fi |
|||
])dnl AX_OPENMP |
@ -0,0 +1,40 @@ |
|||
# Some versions of gcc/libstdc++ require linking with -latomic if |
|||
# using the C++ atomic library. |
|||
# |
|||
# Sourced from http://bugs.debian.org/797228 |
|||
|
|||
m4_define([_CHECK_ATOMIC_testbody], [[ |
|||
#include <atomic> |
|||
#include <cstdint> |
|||
|
|||
int main() { |
|||
std::atomic<int64_t> a{}; |
|||
|
|||
int64_t v = 5; |
|||
int64_t r = a.fetch_add(v); |
|||
return static_cast<int>(r); |
|||
} |
|||
]]) |
|||
|
|||
AC_DEFUN([CHECK_ATOMIC], [ |
|||
|
|||
AC_LANG_PUSH(C++) |
|||
|
|||
AC_MSG_CHECKING([whether std::atomic can be used without link library]) |
|||
|
|||
AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[ |
|||
AC_MSG_RESULT([yes]) |
|||
],[ |
|||
AC_MSG_RESULT([no]) |
|||
LIBS="$LIBS -latomic" |
|||
AC_MSG_CHECKING([whether std::atomic needs -latomic]) |
|||
AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[ |
|||
AC_MSG_RESULT([yes]) |
|||
],[ |
|||
AC_MSG_RESULT([no]) |
|||
AC_MSG_FAILURE([cannot figure our how to use std::atomic]) |
|||
]) |
|||
]) |
|||
|
|||
AC_LANG_POP |
|||
]) |
@ -1,2 +1,2 @@ |
|||
build_linux_SHA256SUM = sha256sum |
|||
build_linux_DOWNLOAD = wget --timeout=$(DOWNLOAD_CONNECT_TIMEOUT) --tries=$(DOWNLOAD_RETRIES) -nv -O |
|||
build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o |
|||
|
@ -1,26 +1,19 @@ |
|||
package=googletest |
|||
$(package)_version=1.7.0 |
|||
$(package)_version=1.8.0 |
|||
$(package)_download_path=https://github.com/google/$(package)/archive/ |
|||
$(package)_file_name=$(package)-$($(package)_version).tar.gz |
|||
$(package)_download_file=release-$($(package)_version).tar.gz |
|||
$(package)_sha256_hash=f73a6546fdf9fce9ff93a5015e0333a8af3062a152a9ad6bcb772c96687016cc |
|||
|
|||
define $(package)_set_vars |
|||
$(package)_build_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" CXX="$($(package)_cxx)" CXXFLAGS="$($(package)_cxxflags)" |
|||
endef |
|||
|
|||
BUILD_OS := $(shell uname) |
|||
ifeq ($(BUILD_OS),Darwin) |
|||
$(package)_install=ginstall |
|||
else |
|||
$(package)_install=install |
|||
endif |
|||
$(package)_sha256_hash=58a6f4277ca2bc8565222b3bbd58a177609e9c488e8a72649359ba51450db7d8 |
|||
|
|||
define $(package)_build_cmds |
|||
$(MAKE) -C make gtest.a |
|||
$(MAKE) -C googlemock/make CXXFLAGS=-fPIC gmock.a && \
|
|||
$(MAKE) -C googletest/make CXXFLAGS=-fPIC gtest.a |
|||
endef |
|||
|
|||
define $(package)_stage_cmds |
|||
$($(package)_install) -D ./make/gtest.a $($(package)_staging_dir)$(host_prefix)/lib/libgtest.a && \
|
|||
cp -a ./include $($(package)_staging_dir)$(host_prefix)/include |
|||
endef |
|||
mkdir -p $($(package)_staging_dir)$(host_prefix)/lib && \
|
|||
install ./googlemock/make/gmock.a $($(package)_staging_dir)$(host_prefix)/lib/libgmock.a && \
|
|||
install ./googletest/make/gtest.a $($(package)_staging_dir)$(host_prefix)/lib/libgtest.a && \
|
|||
cp -a ./googlemock/include $($(package)_staging_dir)$(host_prefix)/ && \
|
|||
cp -a ./googletest/include $($(package)_staging_dir)$(host_prefix)/ |
|||
endef |
|||
|
@ -1,7 +1,7 @@ |
|||
rust_packages := rust librustzcash |
|||
proton_packages := proton |
|||
zcash_packages := libgmp libsodium |
|||
packages := boost openssl libevent zeromq $(zcash_packages) googletest googlemock |
|||
packages := boost openssl libevent zeromq $(zcash_packages) googletest |
|||
native_packages := native_ccache |
|||
|
|||
wallet_packages=bdb |
|||
|
@ -0,0 +1,189 @@ |
|||
#!/usr/bin/env python2 |
|||
# Copyright (c) 2017 The Zcash developers |
|||
# Distributed under the MIT software license, see the accompanying |
|||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. |
|||
|
|||
from decimal import Decimal |
|||
from test_framework.test_framework import BitcoinTestFramework |
|||
from test_framework.util import assert_equal, assert_greater_than, start_nodes, initialize_chain_clean, connect_nodes_bi |
|||
|
|||
import logging |
|||
import time |
|||
import math |
|||
|
|||
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO) |
|||
|
|||
|
|||
class ZkeyImportExportTest (BitcoinTestFramework): |
|||
|
|||
def setup_chain(self): |
|||
print("Initializing test directory "+self.options.tmpdir) |
|||
initialize_chain_clean(self.options.tmpdir, 5) |
|||
|
|||
def setup_network(self, split=False): |
|||
self.nodes = start_nodes(5, self.options.tmpdir ) |
|||
connect_nodes_bi(self.nodes,0,1) |
|||
connect_nodes_bi(self.nodes,1,2) |
|||
connect_nodes_bi(self.nodes,0,2) |
|||
connect_nodes_bi(self.nodes,0,3) |
|||
connect_nodes_bi(self.nodes,0,4) |
|||
self.is_network_split=False |
|||
self.sync_all() |
|||
|
|||
# TODO: Refactor in z_addr test_framework file |
|||
# Returns txid if operation was a success or None |
|||
def wait_and_assert_operationid_status(self, node, myopid, in_status='success', in_errormsg=None): |
|||
print('waiting for async operation {}'.format(myopid)) |
|||
opids = [] |
|||
opids.append(myopid) |
|||
timeout = 300 |
|||
status = None |
|||
errormsg = None |
|||
txid = None |
|||
for x in xrange(1, timeout): |
|||
results = node.z_getoperationresult(opids) |
|||
if len(results)==0: |
|||
time.sleep(1) |
|||
else: |
|||
print("Results", results[0]) |
|||
status = results[0]["status"] |
|||
if status == "failed": |
|||
errormsg = results[0]['error']['message'] |
|||
elif status == "success": |
|||
txid = results[0]['result']['txid'] |
|||
break |
|||
print('...returned status: {}'.format(status)) |
|||
assert_equal(in_status, status) |
|||
if errormsg is not None: |
|||
assert(in_errormsg is not None) |
|||
assert_equal(in_errormsg in errormsg, True) |
|||
print('...returned error: {}'.format(errormsg)) |
|||
return txid |
|||
|
|||
def run_test(self): |
|||
[alice, bob, charlie, david, miner] = self.nodes |
|||
|
|||
def z_send(from_node, from_addr, to_addr, amount): |
|||
opid = from_node.z_sendmany(from_addr, [{"address": to_addr, "amount": Decimal(amount)}]) |
|||
self.wait_and_assert_operationid_status(from_node, opid) |
|||
self.sync_all() |
|||
miner.generate(1) |
|||
self.sync_all() |
|||
|
|||
def z_getbalance(node, zaddr): |
|||
bal = node.z_getbalance(zaddr) |
|||
# Ignore fees for sake of comparison |
|||
round_balance = math.ceil(bal*100)/100 |
|||
return round_balance |
|||
|
|||
def verify_utxos(node, amts, zaddr): |
|||
amts.sort(reverse=True) |
|||
txs = node.z_listreceivedbyaddress(zaddr) |
|||
|
|||
def cmp_confirmations_high_to_low(a, b): |
|||
return cmp(b["amount"], a["amount"]) |
|||
|
|||
txs.sort(cmp_confirmations_high_to_low) |
|||
print("Sorted txs", txs) |
|||
print("amts", amts) |
|||
|
|||
try: |
|||
assert_equal(amts, [tx["amount"] for tx in txs]) |
|||
except AssertionError: |
|||
logging.error( |
|||
'Expected amounts: %r; txs: %r', |
|||
amts, txs) |
|||
raise |
|||
|
|||
def get_private_balance(node): |
|||
balance = node.z_gettotalbalance() |
|||
return balance['private'] |
|||
|
|||
def find_imported_key(node, import_zaddr): |
|||
zaddrs = node.z_listaddresses() |
|||
assert(import_zaddr in zaddrs) |
|||
return import_zaddr |
|||
|
|||
# Seed Alice with some funds |
|||
alice.generate(10) |
|||
self.sync_all() |
|||
miner.generate(100) |
|||
self.sync_all() |
|||
# Shield Alice's coinbase funds to her zaddr |
|||
alice_zaddr = alice.z_getnewaddress() |
|||
res = alice.z_shieldcoinbase("*", alice_zaddr) |
|||
self.wait_and_assert_operationid_status(alice, res['opid']) |
|||
miner.generate(6) |
|||
self.sync_all() |
|||
|
|||
# Now get a pristine z-address for receiving transfers: |
|||
bob_zaddr = bob.z_getnewaddress() |
|||
verify_utxos(bob, [], bob_zaddr) |
|||
# TODO: Verify that charlie doesn't have funds in addr |
|||
# verify_utxos(charlie, []) |
|||
|
|||
# the amounts of each txn embodied which generates a single UTXO: |
|||
amounts = map(Decimal, ['2.3', '3.7', '0.1', '0.5', '1.0', '0.19']) |
|||
|
|||
# Internal test consistency assertion: |
|||
assert_greater_than( |
|||
get_private_balance(alice), |
|||
reduce(Decimal.__add__, amounts)) |
|||
|
|||
logging.info("Sending pre-export txns...") |
|||
for amount in amounts[0:2]: |
|||
z_send(alice, alice_zaddr, bob_zaddr, amount) |
|||
|
|||
logging.info("Exporting privkey from bob...") |
|||
privkey = bob.z_exportkey(bob_zaddr) |
|||
|
|||
logging.info("Sending post-export txns...") |
|||
for amount in amounts[2:4]: |
|||
z_send(alice, alice_zaddr, bob_zaddr, amount) |
|||
|
|||
print("Bob amounts:", amounts[:4]) |
|||
verify_utxos(bob, amounts[:4], bob_zaddr) |
|||
# verify_utxos(charlie, []) |
|||
|
|||
logging.info("Importing privkey into charlie...") |
|||
# z_importkey rescan defaults to "whenkeyisnew", so should rescan here |
|||
charlie.z_importkey(privkey) |
|||
ipk_zaddr = find_imported_key(charlie, bob_zaddr) |
|||
|
|||
# z_importkey should have rescanned for new key, so this should pass: |
|||
verify_utxos(charlie, amounts[:4], ipk_zaddr) |
|||
|
|||
# Verify idempotent behavior: |
|||
charlie.z_importkey(privkey) |
|||
ipk_zaddr2 = find_imported_key(charlie, bob_zaddr) |
|||
|
|||
# amounts should be unchanged |
|||
verify_utxos(charlie, amounts[:4], ipk_zaddr2) |
|||
|
|||
logging.info("Sending post-import txns...") |
|||
for amount in amounts[4:]: |
|||
z_send(alice, alice_zaddr, bob_zaddr, amount) |
|||
|
|||
verify_utxos(bob, amounts, bob_zaddr) |
|||
verify_utxos(charlie, amounts, ipk_zaddr) |
|||
verify_utxos(charlie, amounts, ipk_zaddr2) |
|||
|
|||
# Try to reproduce zombie balance reported in #1936 |
|||
# At generated zaddr, receive ZEC, and send ZEC back out. bob -> alice |
|||
for amount in amounts[:2]: |
|||
print("Sending amount from bob to alice: ", amount) |
|||
z_send(bob, bob_zaddr, alice_zaddr, amount) |
|||
|
|||
balance = float(sum(amounts) - sum(amounts[:2])) |
|||
assert_equal(z_getbalance(bob, bob_zaddr), balance) |
|||
|
|||
# z_import onto new node "david" (blockchain rescan, default or True?) |
|||
david.z_importkey(privkey) |
|||
d_ipk_zaddr = find_imported_key(david, bob_zaddr) |
|||
|
|||
# Check if amt bob spent is deducted for charlie and david |
|||
assert_equal(z_getbalance(charlie, ipk_zaddr), balance) |
|||
assert_equal(z_getbalance(david, d_ipk_zaddr), balance) |
|||
|
|||
if __name__ == '__main__': |
|||
ZkeyImportExportTest().main() |
@ -1,48 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the "extended radix-2" evaluation domain. |
|||
|
|||
Roughly, the domain has size m = 2^{k+1} and consists of |
|||
"the m-th roots of unity" union "a coset of these roots". |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef EXTENDED_RADIX2_DOMAIN_HPP_ |
|||
#define EXTENDED_RADIX2_DOMAIN_HPP_ |
|||
|
|||
#include "algebra/evaluation_domain/evaluation_domain.hpp" |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<typename FieldT> |
|||
class extended_radix2_domain : public evaluation_domain<FieldT> { |
|||
public: |
|||
|
|||
size_t small_m; |
|||
FieldT omega; |
|||
FieldT shift; |
|||
|
|||
extended_radix2_domain(const size_t m); |
|||
|
|||
void FFT(std::vector<FieldT> &a); |
|||
void iFFT(std::vector<FieldT> &a); |
|||
void cosetFFT(std::vector<FieldT> &a, const FieldT &g); |
|||
void icosetFFT(std::vector<FieldT> &a, const FieldT &g); |
|||
std::vector<FieldT> lagrange_coeffs(const FieldT &t); |
|||
FieldT get_element(const size_t idx); |
|||
FieldT compute_Z(const FieldT &t); |
|||
void add_poly_Z(const FieldT &coeff, std::vector<FieldT> &H); |
|||
void divide_by_Z_on_coset(std::vector<FieldT> &P); |
|||
|
|||
}; |
|||
|
|||
} // libsnark
|
|||
|
|||
#include "algebra/evaluation_domain/domains/extended_radix2_domain.tcc" |
|||
|
|||
#endif // EXTENDED_RADIX2_DOMAIN_HPP_
|
@ -1,180 +0,0 @@ |
|||
/** @file |
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the "extended radix-2" evaluation domain. |
|||
|
|||
See extended_radix2_domain.hpp . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef EXTENDED_RADIX2_DOMAIN_TCC_ |
|||
|
|||
#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<typename FieldT> |
|||
extended_radix2_domain<FieldT>::extended_radix2_domain(const size_t m) : evaluation_domain<FieldT>(m) |
|||
{ |
|||
assert(m > 1); |
|||
|
|||
const size_t logm = log2(m); |
|||
|
|||
assert(logm == FieldT::s + 1); |
|||
|
|||
small_m = m/2; |
|||
omega = get_root_of_unity<FieldT>(small_m); |
|||
shift = coset_shift<FieldT>(); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::FFT(std::vector<FieldT> &a) |
|||
{ |
|||
assert(a.size() == this->m); |
|||
|
|||
std::vector<FieldT> a0(small_m, FieldT::zero()); |
|||
std::vector<FieldT> a1(small_m, FieldT::zero()); |
|||
|
|||
const FieldT shift_to_small_m = shift^bigint<1>(small_m); |
|||
|
|||
FieldT shift_i = FieldT::one(); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a0[i] = a[i] + a[small_m + i]; |
|||
a1[i] = shift_i * (a[i] + shift_to_small_m * a[small_m + i]); |
|||
|
|||
shift_i *= shift; |
|||
} |
|||
|
|||
_basic_radix2_FFT(a0, omega); |
|||
_basic_radix2_FFT(a1, omega); |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a[i] = a0[i]; |
|||
a[i+small_m] = a1[i]; |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::iFFT(std::vector<FieldT> &a) |
|||
{ |
|||
assert(a.size() == this->m); |
|||
|
|||
// note: this is not in-place |
|||
std::vector<FieldT> a0(a.begin(), a.begin() + small_m); |
|||
std::vector<FieldT> a1(a.begin() + small_m, a.end()); |
|||
|
|||
const FieldT omega_inverse = omega.inverse(); |
|||
_basic_radix2_FFT(a0, omega_inverse); |
|||
_basic_radix2_FFT(a1, omega_inverse); |
|||
|
|||
const FieldT shift_to_small_m = shift^bigint<1>(small_m); |
|||
const FieldT sconst = (FieldT(small_m) * (FieldT::one()-shift_to_small_m)).inverse(); |
|||
|
|||
const FieldT shift_inverse = shift.inverse(); |
|||
FieldT shift_inverse_i = FieldT::one(); |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a[i] = sconst * (-shift_to_small_m * a0[i] + shift_inverse_i * a1[i]); |
|||
a[i+small_m] = sconst * (a0[i] - shift_inverse_i * a1[i]); |
|||
|
|||
shift_inverse_i *= shift_inverse; |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::cosetFFT(std::vector<FieldT> &a, const FieldT &g) |
|||
{ |
|||
_multiply_by_coset(a, g); |
|||
FFT(a); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::icosetFFT(std::vector<FieldT> &a, const FieldT &g) |
|||
{ |
|||
iFFT(a); |
|||
_multiply_by_coset(a, g.inverse()); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
std::vector<FieldT> extended_radix2_domain<FieldT>::lagrange_coeffs(const FieldT &t) |
|||
{ |
|||
const std::vector<FieldT> T0 = _basic_radix2_lagrange_coeffs(small_m, t); |
|||
const std::vector<FieldT> T1 = _basic_radix2_lagrange_coeffs(small_m, t * shift.inverse()); |
|||
|
|||
std::vector<FieldT> result(this->m, FieldT::zero()); |
|||
|
|||
const FieldT t_to_small_m = t ^ bigint<1>(small_m); |
|||
const FieldT shift_to_small_m = shift ^ bigint<1>(small_m); |
|||
const FieldT one_over_denom = (shift_to_small_m - FieldT::one()).inverse(); |
|||
const FieldT T0_coeff = (t_to_small_m - shift_to_small_m) * (-one_over_denom); |
|||
const FieldT T1_coeff = (t_to_small_m - FieldT::one()) * one_over_denom; |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
result[i] = T0[i] * T0_coeff; |
|||
result[i+small_m] = T1[i] * T1_coeff; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
FieldT extended_radix2_domain<FieldT>::get_element(const size_t idx) |
|||
{ |
|||
if (idx < small_m) |
|||
{ |
|||
return omega^idx; |
|||
} |
|||
else |
|||
{ |
|||
return shift*(omega^(idx-small_m)); |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
FieldT extended_radix2_domain<FieldT>::compute_Z(const FieldT &t) |
|||
{ |
|||
return ((t^small_m) - FieldT::one()) * ((t^small_m) - (shift^small_m)); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::add_poly_Z(const FieldT &coeff, std::vector<FieldT> &H) |
|||
{ |
|||
assert(H.size() == this->m+1); |
|||
const FieldT shift_to_small_m = shift^small_m; |
|||
|
|||
H[this->m] += coeff; |
|||
H[small_m] -= coeff * (shift_to_small_m + FieldT::one()); |
|||
H[0] += coeff * shift_to_small_m; |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void extended_radix2_domain<FieldT>::divide_by_Z_on_coset(std::vector<FieldT> &P) |
|||
{ |
|||
const FieldT coset = FieldT::multiplicative_generator; |
|||
|
|||
const FieldT coset_to_small_m = coset^small_m; |
|||
const FieldT shift_to_small_m = shift^small_m; |
|||
|
|||
const FieldT Z0 = (coset_to_small_m - FieldT::one()) * (coset_to_small_m - shift_to_small_m); |
|||
const FieldT Z1 = (coset_to_small_m*shift_to_small_m - FieldT::one()) * (coset_to_small_m * shift_to_small_m - shift_to_small_m); |
|||
|
|||
const FieldT Z0_inverse = Z0.inverse(); |
|||
const FieldT Z1_inverse = Z1.inverse(); |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
P[i] *= Z0_inverse; |
|||
P[i+small_m] *= Z1_inverse; |
|||
} |
|||
} |
|||
|
|||
} // libsnark |
|||
|
|||
#endif // EXTENDED_RADIX2_DOMAIN_TCC_ |
@ -1,50 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
|
|||
Declaration of interfaces for the "step radix-2" evaluation domain. |
|||
|
|||
Roughly, the domain has size m = 2^k + 2^r and consists of |
|||
"the 2^k-th roots of unity" union "a coset of 2^r-th roots of unity". |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef STEP_RADIX2_DOMAIN_HPP_ |
|||
#define STEP_RADIX2_DOMAIN_HPP_ |
|||
|
|||
#include "algebra/evaluation_domain/evaluation_domain.hpp" |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<typename FieldT> |
|||
class step_radix2_domain : public evaluation_domain<FieldT> { |
|||
public: |
|||
|
|||
size_t big_m; |
|||
size_t small_m; |
|||
FieldT omega; |
|||
FieldT big_omega; |
|||
FieldT small_omega; |
|||
|
|||
step_radix2_domain(const size_t m); |
|||
|
|||
void FFT(std::vector<FieldT> &a); |
|||
void iFFT(std::vector<FieldT> &a); |
|||
void cosetFFT(std::vector<FieldT> &a, const FieldT &g); |
|||
void icosetFFT(std::vector<FieldT> &a, const FieldT &g); |
|||
std::vector<FieldT> lagrange_coeffs(const FieldT &t); |
|||
FieldT get_element(const size_t idx); |
|||
FieldT compute_Z(const FieldT &t); |
|||
void add_poly_Z(const FieldT &coeff, std::vector<FieldT> &H); |
|||
void divide_by_Z_on_coset(std::vector<FieldT> &P); |
|||
|
|||
}; |
|||
|
|||
} // libsnark
|
|||
|
|||
#include "algebra/evaluation_domain/domains/step_radix2_domain.tcc" |
|||
|
|||
#endif // STEP_RADIX2_DOMAIN_HPP_
|
@ -1,247 +0,0 @@ |
|||
/** @file |
|||
***************************************************************************** |
|||
|
|||
Implementation of interfaces for the "step radix-2" evaluation domain. |
|||
|
|||
See step_radix2_domain.hpp . |
|||
|
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef STEP_RADIX2_DOMAIN_TCC_ |
|||
|
|||
#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<typename FieldT> |
|||
step_radix2_domain<FieldT>::step_radix2_domain(const size_t m) : evaluation_domain<FieldT>(m) |
|||
{ |
|||
assert(m > 1); |
|||
|
|||
big_m = UINT64_C(1)<<(log2(m)-1); |
|||
small_m = m - big_m; |
|||
|
|||
assert(small_m == UINT64_C(1)<<log2(small_m)); |
|||
|
|||
omega = get_root_of_unity<FieldT>(UINT64_C(1)<<log2(m)); // rounded! |
|||
big_omega = omega.squared(); |
|||
small_omega = get_root_of_unity<FieldT>(small_m); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::FFT(std::vector<FieldT> &a) |
|||
{ |
|||
assert(a.size() == this->m); |
|||
std::vector<FieldT> c(big_m, FieldT::zero()); |
|||
std::vector<FieldT> d(big_m, FieldT::zero()); |
|||
|
|||
FieldT omega_i = FieldT::one(); |
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
c[i] = (i < small_m ? a[i] + a[i+big_m] : a[i]); |
|||
d[i] = omega_i * (i < small_m ? a[i] - a[i+big_m] : a[i]); |
|||
omega_i *= omega; |
|||
} |
|||
|
|||
std::vector<FieldT> e(small_m, FieldT::zero()); |
|||
const size_t compr = UINT64_C(1)<<(log2(big_m) - log2(small_m)); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
for (size_t j = 0; j < compr; ++j) |
|||
{ |
|||
e[i] += d[i + j * small_m]; |
|||
} |
|||
} |
|||
|
|||
_basic_radix2_FFT(c, omega.squared()); |
|||
_basic_radix2_FFT(e, get_root_of_unity<FieldT>(small_m)); |
|||
|
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
a[i] = c[i]; |
|||
} |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a[i+big_m] = e[i]; |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::iFFT(std::vector<FieldT> &a) |
|||
{ |
|||
assert(a.size() == this->m); |
|||
|
|||
std::vector<FieldT> U0(a.begin(), a.begin() + big_m); |
|||
std::vector<FieldT> U1(a.begin() + big_m, a.end()); |
|||
|
|||
_basic_radix2_FFT(U0, omega.squared().inverse()); |
|||
_basic_radix2_FFT(U1, get_root_of_unity<FieldT>(small_m).inverse()); |
|||
|
|||
const FieldT U0_size_inv = FieldT(big_m).inverse(); |
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
U0[i] *= U0_size_inv; |
|||
} |
|||
|
|||
const FieldT U1_size_inv = FieldT(small_m).inverse(); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
U1[i] *= U1_size_inv; |
|||
} |
|||
|
|||
std::vector<FieldT> tmp = U0; |
|||
FieldT omega_i = FieldT::one(); |
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
tmp[i] *= omega_i; |
|||
omega_i *= omega; |
|||
} |
|||
|
|||
// save A_suffix |
|||
for (size_t i = small_m; i < big_m; ++i) |
|||
{ |
|||
a[i] = U0[i]; |
|||
} |
|||
|
|||
const size_t compr = UINT64_C(1)<<(log2(big_m) - log2(small_m)); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
for (size_t j = 1; j < compr; ++j) |
|||
{ |
|||
U1[i] -= tmp[i + j * small_m]; |
|||
} |
|||
} |
|||
|
|||
const FieldT omega_inv = omega.inverse(); |
|||
FieldT omega_inv_i = FieldT::one(); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
U1[i] *= omega_inv_i; |
|||
omega_inv_i *= omega_inv; |
|||
} |
|||
|
|||
// compute A_prefix |
|||
const FieldT over_two = FieldT(2).inverse(); |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a[i] = (U0[i]+U1[i]) * over_two; |
|||
} |
|||
|
|||
// compute B2 |
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
a[big_m + i] = (U0[i]-U1[i]) * over_two; |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::cosetFFT(std::vector<FieldT> &a, const FieldT &g) |
|||
{ |
|||
_multiply_by_coset(a, g); |
|||
FFT(a); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::icosetFFT(std::vector<FieldT> &a, const FieldT &g) |
|||
{ |
|||
iFFT(a); |
|||
_multiply_by_coset(a, g.inverse()); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
std::vector<FieldT> step_radix2_domain<FieldT>::lagrange_coeffs(const FieldT &t) |
|||
{ |
|||
std::vector<FieldT> inner_big = _basic_radix2_lagrange_coeffs(big_m, t); |
|||
std::vector<FieldT> inner_small = _basic_radix2_lagrange_coeffs(small_m, t * omega.inverse()); |
|||
|
|||
std::vector<FieldT> result(this->m, FieldT::zero()); |
|||
|
|||
const FieldT L0 = (t^small_m)-(omega^small_m); |
|||
const FieldT omega_to_small_m = omega^small_m; |
|||
const FieldT big_omega_to_small_m = big_omega ^ small_m; |
|||
FieldT elt = FieldT::one(); |
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
result[i] = inner_big[i] * L0 * (elt - omega_to_small_m).inverse(); |
|||
elt *= big_omega_to_small_m; |
|||
} |
|||
|
|||
const FieldT L1 = ((t^big_m)-FieldT::one()) * ((omega^big_m) - FieldT::one()).inverse(); |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
result[big_m + i] = L1 * inner_small[i]; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
FieldT step_radix2_domain<FieldT>::get_element(const size_t idx) |
|||
{ |
|||
if (idx < big_m) |
|||
{ |
|||
return big_omega^idx; |
|||
} |
|||
else |
|||
{ |
|||
return omega * (small_omega^(idx-big_m)); |
|||
} |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
FieldT step_radix2_domain<FieldT>::compute_Z(const FieldT &t) |
|||
{ |
|||
return ((t^big_m) - FieldT::one()) * ((t^small_m) - (omega^small_m)); |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::add_poly_Z(const FieldT &coeff, std::vector<FieldT> &H) |
|||
{ |
|||
assert(H.size() == this->m+1); |
|||
const FieldT omega_to_small_m = omega^small_m; |
|||
|
|||
H[this->m] += coeff; |
|||
H[big_m] -= coeff * omega_to_small_m; |
|||
H[small_m] -= coeff; |
|||
H[0] += coeff * omega_to_small_m; |
|||
} |
|||
|
|||
template<typename FieldT> |
|||
void step_radix2_domain<FieldT>::divide_by_Z_on_coset(std::vector<FieldT> &P) |
|||
{ |
|||
// (c^{2^k}-1) * (c^{2^r} * w^{2^{r+1}*i) - w^{2^r}) |
|||
const FieldT coset = FieldT::multiplicative_generator; |
|||
|
|||
const FieldT Z0 = (coset^big_m) - FieldT::one(); |
|||
const FieldT coset_to_small_m_times_Z0 = (coset^small_m) * Z0; |
|||
const FieldT omega_to_small_m_times_Z0 = (omega^small_m) * Z0; |
|||
const FieldT omega_to_2small_m = omega^(2*small_m); |
|||
FieldT elt = FieldT::one(); |
|||
|
|||
for (size_t i = 0; i < big_m; ++i) |
|||
{ |
|||
P[i] *= (coset_to_small_m_times_Z0 * elt - omega_to_small_m_times_Z0).inverse(); |
|||
elt *= omega_to_2small_m; |
|||
} |
|||
|
|||
// (c^{2^k}*w^{2^k}-1) * (c^{2^k} * w^{2^r} - w^{2^r}) |
|||
|
|||
const FieldT Z1 = ((((coset*omega)^big_m) - FieldT::one()) * (((coset * omega)^small_m) - (omega^small_m))); |
|||
const FieldT Z1_inverse = Z1.inverse(); |
|||
|
|||
for (size_t i = 0; i < small_m; ++i) |
|||
{ |
|||
P[big_m + i] *= Z1_inverse; |
|||
} |
|||
|
|||
} |
|||
|
|||
} // libsnark |
|||
|
|||
#endif // STEP_RADIX2_DOMAIN_TCC_ |
@ -1,122 +0,0 @@ |
|||
/** @file
|
|||
***************************************************************************** |
|||
Declaration of arithmetic in the finite field F[p^3]. |
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef FP3_HPP_ |
|||
#define FP3_HPP_ |
|||
#include "algebra/fields/fp.hpp" |
|||
#include <vector> |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
class Fp3_model; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::ostream& operator<<(std::ostream &, const Fp3_model<n, modulus> &); |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::istream& operator>>(std::istream &, Fp3_model<n, modulus> &); |
|||
|
|||
/**
|
|||
* Arithmetic in the field F[p^3]. |
|||
* |
|||
* Let p := modulus. This interface provides arithmetic for the extension field |
|||
* Fp3 = Fp[U]/(U^3-non_residue), where non_residue is in Fp. |
|||
* |
|||
* ASSUMPTION: p = 1 (mod 6) |
|||
*/ |
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
class Fp3_model { |
|||
public: |
|||
typedef Fp_model<n, modulus> my_Fp; |
|||
|
|||
static bigint<3*n> euler; // (modulus^3-1)/2
|
|||
static unsigned long long s; // modulus^3 = 2^s * t + 1
|
|||
static bigint<3*n> t; // with t odd
|
|||
static bigint<3*n> t_minus_1_over_2; // (t-1)/2
|
|||
static my_Fp non_residue; // X^6-non_residue irreducible over Fp; used for constructing Fp3 = Fp[X] / (X^3 - non_residue)
|
|||
static Fp3_model<n, modulus> nqr; // a quadratic nonresidue in Fp3
|
|||
static Fp3_model<n, modulus> nqr_to_t; // nqr^t
|
|||
static my_Fp Frobenius_coeffs_c1[3]; // non_residue^((modulus^i-1)/3) for i=0,1,2
|
|||
static my_Fp Frobenius_coeffs_c2[3]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2
|
|||
|
|||
my_Fp c0, c1, c2; |
|||
Fp3_model() {}; |
|||
Fp3_model(const my_Fp& c0, const my_Fp& c1, const my_Fp& c2) : c0(c0), c1(c1), c2(c2) {}; |
|||
|
|||
void clear() { c0.clear(); c1.clear(); c2.clear(); } |
|||
void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } |
|||
|
|||
static Fp3_model<n, modulus> zero(); |
|||
static Fp3_model<n, modulus> one(); |
|||
static Fp3_model<n, modulus> random_element(); |
|||
|
|||
bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } |
|||
bool operator==(const Fp3_model &other) const; |
|||
bool operator!=(const Fp3_model &other) const; |
|||
|
|||
Fp3_model operator+(const Fp3_model &other) const; |
|||
Fp3_model operator-(const Fp3_model &other) const; |
|||
Fp3_model operator*(const Fp3_model &other) const; |
|||
Fp3_model operator-() const; |
|||
Fp3_model squared() const; |
|||
Fp3_model inverse() const; |
|||
Fp3_model Frobenius_map(unsigned long power) const; |
|||
Fp3_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate)
|
|||
|
|||
template<mp_size_t m> |
|||
Fp3_model operator^(const bigint<m> &other) const; |
|||
|
|||
static unsigned long long size_in_bits() { return 3*my_Fp::size_in_bits(); } |
|||
static bigint<n> base_field_char() { return modulus; } |
|||
|
|||
friend std::ostream& operator<< <n, modulus>(std::ostream &out, const Fp3_model<n, modulus> &el); |
|||
friend std::istream& operator>> <n, modulus>(std::istream &in, Fp3_model<n, modulus> &el); |
|||
}; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::ostream& operator<<(std::ostream& out, const std::vector<Fp3_model<n, modulus> > &v); |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::istream& operator>>(std::istream& in, std::vector<Fp3_model<n, modulus> > &v); |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n, modulus> operator*(const Fp_model<n, modulus> &lhs, const Fp3_model<n, modulus> &rhs); |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
bigint<3*n> Fp3_model<n, modulus>::euler; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
unsigned long long Fp3_model<n, modulus>::s; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
bigint<3*n> Fp3_model<n, modulus>::t; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
bigint<3*n> Fp3_model<n, modulus>::t_minus_1_over_2; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp_model<n, modulus> Fp3_model<n, modulus>::non_residue; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n, modulus> Fp3_model<n, modulus>::nqr; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n, modulus> Fp3_model<n, modulus>::nqr_to_t; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp_model<n, modulus> Fp3_model<n, modulus>::Frobenius_coeffs_c1[3]; |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp_model<n, modulus> Fp3_model<n, modulus>::Frobenius_coeffs_c2[3]; |
|||
|
|||
} // libsnark
|
|||
#include "algebra/fields/fp3.tcc" |
|||
|
|||
#endif // FP3_HPP_
|
@ -1,259 +0,0 @@ |
|||
/** @file |
|||
***************************************************************************** |
|||
Implementation of arithmetic in the finite field F[p^3]. |
|||
***************************************************************************** |
|||
* @author This file is part of libsnark, developed by SCIPR Lab |
|||
* and contributors (see AUTHORS). |
|||
* @copyright MIT license (see LICENSE file) |
|||
*****************************************************************************/ |
|||
|
|||
#ifndef FP3_TCC_ |
|||
#define FP3_TCC_ |
|||
|
|||
#include "algebra/fields/field_utils.hpp" |
|||
|
|||
namespace libsnark { |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::zero() |
|||
{ |
|||
return Fp3_model<n, modulus>(my_Fp::zero(), my_Fp::zero(), my_Fp::zero()); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::one() |
|||
{ |
|||
return Fp3_model<n, modulus>(my_Fp::one(), my_Fp::zero(), my_Fp::zero()); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::random_element() |
|||
{ |
|||
Fp3_model<n, modulus> r; |
|||
r.c0 = my_Fp::random_element(); |
|||
r.c1 = my_Fp::random_element(); |
|||
r.c2 = my_Fp::random_element(); |
|||
|
|||
return r; |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
bool Fp3_model<n,modulus>::operator==(const Fp3_model<n,modulus> &other) const |
|||
{ |
|||
return (this->c0 == other.c0 && this->c1 == other.c1 && this->c2 == other.c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
bool Fp3_model<n,modulus>::operator!=(const Fp3_model<n,modulus> &other) const |
|||
{ |
|||
return !(operator==(other)); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::operator+(const Fp3_model<n,modulus> &other) const |
|||
{ |
|||
return Fp3_model<n,modulus>(this->c0 + other.c0, |
|||
this->c1 + other.c1, |
|||
this->c2 + other.c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::operator-(const Fp3_model<n,modulus> &other) const |
|||
{ |
|||
return Fp3_model<n,modulus>(this->c0 - other.c0, |
|||
this->c1 - other.c1, |
|||
this->c2 - other.c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n, modulus> operator*(const Fp_model<n, modulus> &lhs, const Fp3_model<n, modulus> &rhs) |
|||
{ |
|||
return Fp3_model<n,modulus>(lhs*rhs.c0, |
|||
lhs*rhs.c1, |
|||
lhs*rhs.c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::operator*(const Fp3_model<n,modulus> &other) const |
|||
{ |
|||
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ |
|||
const my_Fp |
|||
&A = other.c0, &B = other.c1, &C = other.c2, |
|||
&a = this->c0, &b = this->c1, &c = this->c2; |
|||
const my_Fp aA = a*A; |
|||
const my_Fp bB = b*B; |
|||
const my_Fp cC = c*C; |
|||
|
|||
return Fp3_model<n,modulus>(aA + non_residue*((b+c)*(B+C)-bB-cC), |
|||
(a+b)*(A+B)-aA-bB+non_residue*cC, |
|||
(a+c)*(A+C)-aA+bB-cC); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::operator-() const |
|||
{ |
|||
return Fp3_model<n,modulus>(-this->c0, |
|||
-this->c1, |
|||
-this->c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::squared() const |
|||
{ |
|||
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ |
|||
const my_Fp |
|||
&a = this->c0, &b = this->c1, &c = this->c2; |
|||
const my_Fp s0 = a.squared(); |
|||
const my_Fp ab = a*b; |
|||
const my_Fp s1 = ab + ab; |
|||
const my_Fp s2 = (a - b + c).squared(); |
|||
const my_Fp bc = b*c; |
|||
const my_Fp s3 = bc + bc; |
|||
const my_Fp s4 = c.squared(); |
|||
|
|||
return Fp3_model<n,modulus>(s0 + non_residue * s3, |
|||
s1 + non_residue * s4, |
|||
s1 + s2 + s3 - s0 - s4); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::inverse() const |
|||
{ |
|||
const my_Fp |
|||
&a = this->c0, &b = this->c1, &c = this->c2; |
|||
|
|||
/* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */ |
|||
const my_Fp t0 = a.squared(); |
|||
const my_Fp t1 = b.squared(); |
|||
const my_Fp t2 = c.squared(); |
|||
const my_Fp t3 = a*b; |
|||
const my_Fp t4 = a*c; |
|||
const my_Fp t5 = b*c; |
|||
const my_Fp c0 = t0 - non_residue * t5; |
|||
const my_Fp c1 = non_residue * t2 - t3; |
|||
const my_Fp c2 = t1 - t4; // typo in paper referenced above. should be "-" as per Scott, but is "*" |
|||
const my_Fp t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inverse(); |
|||
return Fp3_model<n,modulus>(t6 * c0, t6 * c1, t6 * c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::Frobenius_map(unsigned long power) const |
|||
{ |
|||
return Fp3_model<n,modulus>(c0, |
|||
Frobenius_coeffs_c1[power % 3] * c1, |
|||
Frobenius_coeffs_c2[power % 3] * c2); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::sqrt() const |
|||
{ |
|||
Fp3_model<n,modulus> one = Fp3_model<n,modulus>::one(); |
|||
|
|||
unsigned long long v = Fp3_model<n,modulus>::s; |
|||
Fp3_model<n,modulus> z = Fp3_model<n,modulus>::nqr_to_t; |
|||
Fp3_model<n,modulus> w = (*this)^Fp3_model<n,modulus>::t_minus_1_over_2; |
|||
Fp3_model<n,modulus> x = (*this) * w; |
|||
Fp3_model<n,modulus> b = x * w; // b = (*this)^t |
|||
|
|||
#if DEBUG |
|||
// check if square with euler's criterion |
|||
Fp3_model<n,modulus> check = b; |
|||
for (size_t i = 0; i < v-1; ++i) |
|||
{ |
|||
check = check.squared(); |
|||
} |
|||
if (check != one) |
|||
{ |
|||
assert(0); |
|||
} |
|||
#endif |
|||
|
|||
// compute square root with Tonelli--Shanks |
|||
// (does not terminate if not a square!) |
|||
|
|||
while (b != one) |
|||
{ |
|||
unsigned long long m = 0; |
|||
Fp3_model<n,modulus> b2m = b; |
|||
while (b2m != one) |
|||
{ |
|||
/* invariant: b2m = b^(2^m) after entering this loop */ |
|||
b2m = b2m.squared(); |
|||
m += 1; |
|||
} |
|||
|
|||
int j = v-m-1; |
|||
w = z; |
|||
while (j > 0) |
|||
{ |
|||
w = w.squared(); |
|||
--j; |
|||
} // w = z^2^(v-m-1) |
|||
|
|||
z = w.squared(); |
|||
b = b * z; |
|||
x = x * w; |
|||
v = m; |
|||
} |
|||
|
|||
return x; |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
template<mp_size_t m> |
|||
Fp3_model<n,modulus> Fp3_model<n,modulus>::operator^(const bigint<m> &pow) const |
|||
{ |
|||
return power<Fp3_model<n, modulus> >(*this, pow); |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::ostream& operator<<(std::ostream &out, const Fp3_model<n, modulus> &el) |
|||
{ |
|||
out << el.c0 << OUTPUT_SEPARATOR << el.c1 << OUTPUT_SEPARATOR << el.c2; |
|||
return out; |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::istream& operator>>(std::istream &in, Fp3_model<n, modulus> &el) |
|||
{ |
|||
in >> el.c0 >> el.c1 >> el.c2; |
|||
return in; |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::ostream& operator<<(std::ostream& out, const std::vector<Fp3_model<n, modulus> > &v) |
|||
{ |
|||
out << v.size() << "\n"; |
|||
for (const Fp3_model<n, modulus>& t : v) |
|||
{ |
|||
out << t << OUTPUT_NEWLINE; |
|||
} |
|||
|
|||
return out; |
|||
} |
|||
|
|||
template<mp_size_t n, const bigint<n>& modulus> |
|||
std::istream& operator>>(std::istream& in, std::vector<Fp3_model<n, modulus> > &v) |
|||
{ |
|||
v.clear(); |
|||
|
|||
unsigned long long s; |
|||
in >> s; |
|||
|
|||
char b; |
|||
in.read(&b, 1); |
|||
|
|||
v.reserve(s); |
|||
|
|||
for (size_t i = 0; i < s; ++i) |
|||
{ |
|||
Fp3_model<n, modulus> el; |
|||
in >> el; |
|||
v.emplace_back(el); |
|||
} |
|||
|
|||
return in; |
|||
} |
|||
|
|||
} // libsnark |
|||
#endif // FP3_TCC_ |
Loading…
Reference in new issue