Browse Source

Delete libsnark source code

dev-aarch64
Duke Leto 5 years ago
parent
commit
aa3775f57a
  1. 51
      src/snark/.gitignore
  2. 22
      src/snark/AUTHORS
  3. 24
      src/snark/LICENSE
  4. 289
      src/snark/Makefile
  5. 628
      src/snark/README.md
  6. 1807
      src/snark/doxygen.conf
  7. 525
      src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp
  8. 95
      src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.hpp
  9. 506
      src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp
  10. 96
      src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.hpp
  11. 273
      src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp
  12. 57
      src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.hpp
  13. 547
      src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp
  14. 92
      src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.hpp
  15. 58
      src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp
  16. 50
      src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.hpp
  17. 22
      src/snark/libsnark/algebra/curves/curve_utils.hpp
  18. 37
      src/snark/libsnark/algebra/curves/curve_utils.tcc
  19. 103
      src/snark/libsnark/algebra/curves/public_params.hpp
  20. 139
      src/snark/libsnark/algebra/curves/tests/test_bilinearity.cpp
  21. 176
      src/snark/libsnark/algebra/curves/tests/test_groups.cpp
  22. 45
      src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.hpp
  23. 113
      src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.tcc
  24. 48
      src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp
  25. 243
      src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc
  26. 125
      src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.hpp
  27. 118
      src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.tcc
  28. 31
      src/snark/libsnark/algebra/exponentiation/exponentiation.hpp
  29. 53
      src/snark/libsnark/algebra/exponentiation/exponentiation.tcc
  30. 70
      src/snark/libsnark/algebra/fields/bigint.hpp
  31. 280
      src/snark/libsnark/algebra/fields/bigint.tcc
  32. 51
      src/snark/libsnark/algebra/fields/field_utils.hpp
  33. 184
      src/snark/libsnark/algebra/fields/field_utils.tcc
  34. 182
      src/snark/libsnark/algebra/fields/fp.hpp
  35. 790
      src/snark/libsnark/algebra/fields/fp.tcc
  36. 116
      src/snark/libsnark/algebra/fields/fp12_2over3over2.hpp
  37. 412
      src/snark/libsnark/algebra/fields/fp12_2over3over2.tcc
  38. 120
      src/snark/libsnark/algebra/fields/fp2.hpp
  39. 261
      src/snark/libsnark/algebra/fields/fp2.tcc
  40. 104
      src/snark/libsnark/algebra/fields/fp6_3over2.hpp
  41. 216
      src/snark/libsnark/algebra/fields/fp6_3over2.tcc
  42. 389
      src/snark/libsnark/algebra/fields/fp_aux.tcc
  43. 106
      src/snark/libsnark/algebra/fields/tests/test_bigint.cpp
  44. 245
      src/snark/libsnark/algebra/fields/tests/test_fields.cpp
  45. 84
      src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.hpp
  46. 111
      src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.tcc
  47. 55
      src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.hpp
  48. 276
      src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.tcc
  49. 110
      src/snark/libsnark/algebra/scalar_multiplication/multiexp.hpp
  50. 591
      src/snark/libsnark/algebra/scalar_multiplication/multiexp.tcc
  51. 39
      src/snark/libsnark/algebra/scalar_multiplication/wnaf.hpp
  52. 123
      src/snark/libsnark/algebra/scalar_multiplication/wnaf.tcc
  53. 12
      src/snark/libsnark/common/assert_except.hpp
  54. 74
      src/snark/libsnark/common/data_structures/accumulation_vector.hpp
  55. 84
      src/snark/libsnark/common/data_structures/accumulation_vector.tcc
  56. 71
      src/snark/libsnark/common/data_structures/merkle_tree.hpp
  57. 246
      src/snark/libsnark/common/data_structures/merkle_tree.tcc
  58. 79
      src/snark/libsnark/common/data_structures/sparse_vector.hpp
  59. 316
      src/snark/libsnark/common/data_structures/sparse_vector.tcc
  60. 53
      src/snark/libsnark/common/default_types/ec_pp.hpp
  61. 22
      src/snark/libsnark/common/default_types/r1cs_ppzksnark_pp.hpp
  62. 399
      src/snark/libsnark/common/profiling.cpp
  63. 51
      src/snark/libsnark/common/profiling.hpp
  64. 104
      src/snark/libsnark/common/serialization.hpp
  65. 181
      src/snark/libsnark/common/serialization.tcc
  66. 26
      src/snark/libsnark/common/template_utils.hpp
  67. 102
      src/snark/libsnark/common/utils.cpp
  68. 62
      src/snark/libsnark/common/utils.hpp
  69. 31
      src/snark/libsnark/common/utils.tcc
  70. 48
      src/snark/libsnark/gadgetlib1/constraint_profiling.cpp
  71. 42
      src/snark/libsnark/gadgetlib1/constraint_profiling.hpp
  72. 23
      src/snark/libsnark/gadgetlib1/examples/simple_example.hpp
  73. 54
      src/snark/libsnark/gadgetlib1/examples/simple_example.tcc
  74. 27
      src/snark/libsnark/gadgetlib1/gadget.hpp
  75. 23
      src/snark/libsnark/gadgetlib1/gadget.tcc
  76. 351
      src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.hpp
  77. 705
      src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.tcc
  78. 45
      src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.hpp
  79. 123
      src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.tcc
  80. 42
      src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp
  81. 62
      src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc
  82. 63
      src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.hpp
  83. 105
      src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.tcc
  84. 160
      src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp
  85. 297
      src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc
  86. 108
      src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp
  87. 250
      src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc
  88. 98
      src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp
  89. 230
      src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc
  90. 55
      src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py
  91. 263
      src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py
  92. 46
      src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp
  93. 38
      src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp
  94. 76
      src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc
  95. 73
      src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp
  96. 196
      src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc
  97. 91
      src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp
  98. 265
      src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc
  99. 48
      src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp
  100. 144
      src/snark/libsnark/gadgetlib1/pb_variable.hpp
  101. 330
      src/snark/libsnark/gadgetlib1/pb_variable.tcc
  102. 75
      src/snark/libsnark/gadgetlib1/protoboard.hpp
  103. 189
      src/snark/libsnark/gadgetlib1/protoboard.tcc
  104. 12
      src/snark/libsnark/gtests.cpp
  105. 70
      src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.hpp
  106. 338
      src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.tcc
  107. 193
      src/snark/libsnark/relations/arithmetic_programs/qap/qap.hpp
  108. 324
      src/snark/libsnark/relations/arithmetic_programs/qap/qap.tcc
  109. 109
      src/snark/libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp
  110. 73
      src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp
  111. 164
      src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc
  112. 153
      src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp
  113. 310
      src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc
  114. 213
      src/snark/libsnark/relations/variable.hpp
  115. 512
      src/snark/libsnark/relations/variable.tcc
  116. 35
      src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp
  117. 114
      src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc
  118. 71
      src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp
  119. 485
      src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp
  120. 886
      src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc
  121. 34
      src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp
  122. 42
      src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp

51
src/snark/.gitignore

@ -1,51 +0,0 @@
*.o
*.a
*.so
*.d
libsnark/gtests
depinst/
depsrc/
README.html
doxygen/
libsnark/gtests
libsnark/gadgetlib2/examples/tutorial
libsnark/gadgetlib2/tests/gadgetlib2_test
libsnark/algebra/curves/tests/test_bilinearity
libsnark/algebra/curves/tests/test_groups
libsnark/algebra/fields/tests/test_fields
libsnark/common/routing_algorithms/profiling/profile_routing_algorithms
libsnark/common/routing_algorithms/tests/test_routing_algorithms
libsnark/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram
libsnark/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget
libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget
libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets
libsnark/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets
libsnark/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget
libsnark/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget
libsnark/reductions/ram_to_r1cs/examples/demo_arithmetization
libsnark/relations/arithmetic_programs/qap/tests/test_qap
libsnark/relations/arithmetic_programs/ssp/tests/test_ssp
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd
libsnark/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark
libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark
libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark
libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark
libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark
libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark
libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark
libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark
libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark
libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark
libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark
libsnark/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark
libsnark/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark

22
src/snark/AUTHORS

@ -1,22 +0,0 @@
SCIPR Lab:
Eli Ben-Sasson
Alessandro Chiesa
Daniel Genkin
Shaul Kfir
Eran Tromer
Madars Virza
External contributors:
Michael Backes
Manuel Barbosa
Dario Fiore
Jens Groth
Joshua A. Kroll
Shigeo MITSUNARI
Raphael Reischuk
Tadanori TERUYA
Sean Bowe
Daira Hopwood
@mugatu on forum.z.cash
David Mercer
Joshua Yabut

24
src/snark/LICENSE

@ -1,24 +0,0 @@
The libsnark library is developed by SCIPR Lab (http://scipr-lab.org)
and contributors.
Copyright (c) 2012-2014 SCIPR Lab and contributors (see AUTHORS file).
All files, with the exceptions below, are released under the MIT License:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

289
src/snark/Makefile

@ -1,289 +0,0 @@
#********************************************************************************
# Makefile for the libsnark library.
#********************************************************************************
#* @author This file is part of libsnark, developed by SCIPR Lab
#* and contributors (see AUTHORS).
#* @copyright MIT license (see LICENSE file)
#*******************************************************************************/
# Determine building operating system
ifeq ($(OS),Windows_NT)
uname_S := Windows
else
uname_S := $(shell uname -s)
endif
# To override these, use "make OPTFLAGS=..." etc.
CURVE = BN128
OPTFLAGS = -O2 -march=x86-64 -g -mtune=x86-64
ifneq ($(PLATFORM),darwin)
FEATUREFLAGS = -DUSE_ASM -DMONTGOMERY_OUTPUT
else
FEATUREFLAGS = -DUSE_ASM -DMONTGOMERY_OUTPUT -D__SIZE_TYPE__="unsigned long long"
endif
# Initialize this using "CXXFLAGS=... make". The makefile appends to that.
CXXFLAGS += -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wno-comment -Wfatal-errors $(OPTFLAGS) $(FEATUREFLAGS) -DCURVE_$(CURVE)
DEPSRC = depsrc
DEPINST = depinst
CXXFLAGS += -I$(DEPINST)/include -Ilibsnark
LDFLAGS += -L$(DEPINST)/lib -Wl,-rpath,$(DEPINST)/lib
LDLIBS += -lgmpxx -lgmp -lboost_program_options -lsodium
# List of .a files to include within libsnark.a and libsnark.so:
AR_LIBS =
# List of library files to install:
INSTALL_LIBS = $(LIB_FILE)
# Sentinel file to check existence of this directory (since directories don't work as a Make dependency):
DEPINST_EXISTS = $(DEPINST)/.exists
ifneq ($(NO_GTEST),1)
# Compile GTest from sourcecode if we can (e.g., Ubuntu). Otherwise use precompiled one (e.g., Fedora).
# See https://github.com/google/googletest/blob/master/googletest/docs/FAQ.md#why-is-it-not-recommended-to-install-a-pre-compiled-copy-of-google-test-for-example-into-usrlocal
ifneq ($(NO_COMPILE_LIBGTEST),1)
GTESTDIR=/usr/src/gtest
COMPILE_LIBGTEST = $(shell test -d $(GTESTDIR) && echo -n 1)
endif
GTEST_LDLIBS += -lgtest -lpthread
endif
ifneq ($(NO_SUPERCOP),1)
SUPERCOP_LDLIBS += -lsupercop
INSTALL_LIBS += depinst/lib/libsupercop.a
# Would have been nicer to roll supercop into libsnark.a ("AR_LIBS += $(DEPINST)/lib/libsupercop.a"), but it doesn't support position-independent code (libsnark issue #20).
endif
LIB_SRCS = \
libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp \
libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp \
libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp \
libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp \
libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp \
libsnark/common/profiling.cpp \
libsnark/common/utils.cpp \
libsnark/gadgetlib1/constraint_profiling.cpp \
ifeq ($(CURVE),BN128)
LIB_SRCS += \
libsnark/algebra/curves/bn128/bn128_g1.cpp \
libsnark/algebra/curves/bn128/bn128_g2.cpp \
libsnark/algebra/curves/bn128/bn128_gt.cpp \
libsnark/algebra/curves/bn128/bn128_init.cpp \
libsnark/algebra/curves/bn128/bn128_pairing.cpp \
libsnark/algebra/curves/bn128/bn128_pp.cpp
CXXFLAGS += -DBN_SUPPORT_SNARK
AR_LIBS += $(DEPINST)/lib/libzm.a
endif
# FIXME: most of these are broken due to removed code.
DISABLED_EXECUTABLES = \
libsnark/common/routing_algorithms/profiling/profile_routing_algorithms \
libsnark/common/routing_algorithms/tests/test_routing_algorithms \
libsnark/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram \
libsnark/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget \
libsnark/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets \
libsnark/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget \
libsnark/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget \
libsnark/reductions/ram_to_r1cs/examples/demo_arithmetization \
libsnark/relations/arithmetic_programs/ssp/tests/test_ssp \
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd \
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd \
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd \
libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd \
libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark \
libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark \
libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark \
libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark \
libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark \
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark \
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator \
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover \
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier \
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark \
libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark \
libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark \
libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark \
libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark \
libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark \
libsnark/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark \
libsnark/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark
EXECUTABLES =
EXECUTABLES_WITH_GTEST =
EXECUTABLES_WITH_SUPERCOP = \
libsnark/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark
GTEST_TESTS =
GTEST_SRCS =
DOCS = README.html
LIBSNARK_A = libsnark.a
# For documentation of the following options, see README.md .
ifeq ($(NO_PROCPS),1)
CXXFLAGS += -DNO_PROCPS
else
LDLIBS += -lprocps
endif
ifeq ($(LOWMEM),1)
CXXFLAGS += -DLOWMEM
endif
ifeq ($(PROFILE_OP_COUNTS),1)
STATIC = 1
CXXFLAGS += -DPROFILE_OP_COUNTS
endif
ifeq ($(STATIC),1)
ifneq ($(PLATFORM),darwin)
CXXFLAGS += -static
endif
CXXFLAGS += -DSTATIC
else
CXXFLAGS += -fPIC
endif
ifeq ($(MULTICORE),1)
CXXFLAGS += -DMULTICORE -fopenmp
endif
ifeq ($(CPPDEBUG),1)
CXXFLAGS += -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC
DEBUG = 1
endif
ifeq ($(DEBUG),1)
CXXFLAGS += -DDEBUG -ggdb3
endif
ifeq ($(PERFORMANCE),1)
OPTFLAGS = -O3 -march=x86-64 -g -mtune=x86-64
CXXFLAGS += -DNDEBUG
# Enable link-time optimization:
CXXFLAGS += -flto -fuse-linker-plugin
LDFLAGS += -flto
endif
LIB_OBJS =$(patsubst %.cpp,%.o,$(LIB_SRCS))
EXEC_OBJS =$(patsubst %,%.o,$(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP))
GTEST_OBJS =$(patsubst %.cpp,%.o,$(GTEST_SRCS))
all: \
$(if $(NO_GTEST),,$(EXECUTABLES_WITH_GTEST) $(GTEST_TESTS)) \
$(if $(NO_SUPERCOP),,$(EXECUTABLES_WITH_SUPERCOP)) \
$(EXECUTABLES) \
$(LIBSNARK_A) \
$(if $(NO_DOCS),,doc)
doc: $(DOCS)
$(DEPINST_EXISTS):
# Create placeholder directories for installed dependencies. Some make settings (including the default) require actually running ./prepare-depends.sh to populate this directory.
mkdir -p $(DEPINST)/lib $(DEPINST)/include
touch $@
# In order to detect changes to #include dependencies. -MMD below generates a .d file for each .o file. Include the .d file.
-include $(patsubst %.o,%.d, $(LIB_OBJS) $(GTEST_OBJS) $(EXEC_OBJS) )
$(LIB_OBJS) $(if $(NO_GTEST),,$(GTEST_OBJS)) $(EXEC_OBJS): %.o: %.cpp
$(CXX) -o $@ $< -c -MMD $(CXXFLAGS)
LIBGTEST_A = $(DEPINST)/lib/libgtest.a
$(LIBGTEST_A): $(GTESTDIR)/libsnark/gtest-all.cc $(DEPINST_EXISTS)
$(CXX) -o $(DEPINST)/lib/gtest-all.o -I $(GTESTDIR) -c -isystem $(GTESTDIR)/include $< $(CXXFLAGS)
$(AR) -rv $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o
# libsnark.a will contains all of our relevant object files, and we also mash in the .a files of relevant dependencies built by ./prepare-depends.sh
$(LIBSNARK_A): $(LIB_OBJS) $(AR_LIBS)
$(AR) q $(LIBSNARK_A) $(LIB_OBJS)
if [ -n "$(AR_LIBS)" ]; then mkdir -p tmp-ar; cd tmp-ar; for AR_LIB in $(AR_LIBS); do $(AR) x $$AR_LIB; done; $(AR) qc $(LIBSNARK_A) tmp-ar/*; cd ..; rm -r tmp-ar; fi;
$(AR) s $(LIBSNARK_A)
libsnark.so: $(LIBSNARK_A) $(DEPINST_EXISTS)
$(CXX) -o $@ --shared -Wl,--whole-archive $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) -Wl,--no-whole-archive $(LDLIBS)
libsnark/gadgetlib2/tests/gadgetlib2_test: \
libsnark/gadgetlib2/tests/adapters_UTEST.cpp \
libsnark/gadgetlib2/tests/constraint_UTEST.cpp \
libsnark/gadgetlib2/tests/gadget_UTEST.cpp \
libsnark/gadgetlib2/tests/integration_UTEST.cpp \
libsnark/gadgetlib2/tests/protoboard_UTEST.cpp \
libsnark/gadgetlib2/tests/variable_UTEST.cpp
$(EXECUTABLES): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS)
$(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
$(EXECUTABLES_WITH_GTEST): %: %.o $(LIBSNARK_A) $(if $(COMPILE_LIBGTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS)
$(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(GTEST_LDLIBS) $(LDLIBS)
$(EXECUTABLES_WITH_SUPERCOP): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS)
$(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(SUPERCOP_LDLIBS) $(LDLIBS)
$(GTEST_TESTS): %: $(GTEST_OBJS) $(LIBSNARK_A) $(if $(COMPILE_LIBGTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS)
$(CXX) -o $@ $(GTEST_OBJS) $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(GTEST_LDLIBS) $(LDLIBS)
ifeq ($(STATIC),1)
LIB_FILE = $(LIBSNARK_A)
else
LIB_FILE = libsnark.so
endif
lib: $(LIB_FILE)
$(DOCS): %.html: %.md
markdown_py -f $@ $^ -x toc -x extra --noisy
# TODO: Would be nice to enable "-x smartypants" but Ubuntu 12.04 doesn't support that.
# TODO: switch to redcarpet, to produce same output as GitHub's processing of README.md. But what about TOC?
ifeq ($(PREFIX),)
install:
$(error Please provide PREFIX. E.g. make install PREFIX=/usr)
else
HEADERS_SRC=$(shell find libsnark -name '*.hpp' -o -name '*.tcc')
HEADERS_DEST=$(patsubst libsnark/%,$(PREFIX)/include/libsnark/%,$(HEADERS_SRC))
$(HEADERS_DEST): $(PREFIX)/include/libsnark/%: libsnark/%
mkdir -p $(shell dirname $@)
cp $< $@
install: $(INSTALL_LIBS) $(HEADERS_DEST) $(DEPINST_EXISTS)
mkdir -p $(PREFIX)/lib
cp -v $(INSTALL_LIBS) $(PREFIX)/lib/
ifneq ($(NO_COPY_DEPINST),1)
cp -rv $(DEPINST)/include $(PREFIX)
endif
endif
check: $(GTEST_TESTS)
$(GTEST_TESTS)
doxy:
doxygen doxygen.conf
# Clean generated files, except locally-compiled dependencies
clean:
$(RM) \
$(LIB_OBJS) $(GTEST_OBJS) $(EXEC_OBJS) \
$(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP) $(GTEST_TESTS) \
$(DOCS) \
${patsubst %.o,%.d,${LIB_OBJS} ${GTEST_OBJS} ${EXEC_OBJS}} \
libsnark.so $(LIBSNARK_A) \
$(RM) -fr doxygen/ \
$(RM) $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o
# Clean all, including locally-compiled dependencies
clean-all: clean
$(RM) -fr $(DEPSRC) $(DEPINST)
.PHONY: all clean clean-all doc doxy lib install

628
src/snark/README.md

@ -1,628 +0,0 @@
libsnark: a C++ library for zkSNARK proofs
================================================================================
--------------------------------------------------------------------------------
Authors
--------------------------------------------------------------------------------
The libsnark library is developed by the [SCIPR Lab] project and contributors
and is released under the MIT License (see the [LICENSE] file).
Copyright (c) 2012-2014 SCIPR Lab and contributors (see [AUTHORS] file).
--------------------------------------------------------------------------------
[TOC]
<!---
NOTE: the file you are reading is in Markdown format, which is is fairly readable
directly, but can be converted into an HTML file with much nicer formatting.
To do so, run "make doc" (this requires the python-markdown package) and view
the resulting file README.html. Alternatively, view the latest HTML version at
https://github.com/scipr-lab/libsnark .
-->
--------------------------------------------------------------------------------
Overview
--------------------------------------------------------------------------------
This library implements __zkSNARK__ schemes, which are a cryptographic method
for proving/verifying, in zero knowledge, the integrity of computations.
A computation can be expressed as an NP statement, in forms such as the following:
- "The C program _foo_, when executed, returns exit code 0 if given the input _bar_ and some additional input _qux_."
- "The Boolean circuit _foo_ is satisfiable by some input _qux_."
- "The arithmetic circuit _foo_ accepts the partial assignment _bar_, when extended into some full assignment _qux_."
- "The set of constraints _foo_ is satisfiable by the partial assignment _bar_, when extended into some full assignment _qux_."
A prover who knows the witness for the NP statement (i.e., a satisfying input/assignment) can produce a short proof attesting to the truth of the NP statement. This proof can be verified by anyone, and offers the following properties.
- __Zero knowledge:__
the verifier learns nothing from the proof beside the truth of the statement (i.e., the value _qux_, in the above examples, remains secret).
- __Succinctness:__
the proof is short and easy to verify.
- __Non-interactivity:__
the proof is a string (i.e. it does not require back-and-forth interaction between the prover and the verifier).
- __Soundness:__
the proof is computationally sound (i.e., it is infeasible to fake a proof of a false NP statement). Such a proof system is also called an _argument_.
- __Proof of knowledge:__
the proof attests not just that the NP statement is true, but also that the
prover knows why (e.g., knows a valid _qux_).
These properties are summarized by the _zkSNARK_ acronym, which stands for _Zero-Knowledge Succinct Non-interactive ARgument of Knowledge_ (though zkSNARKs are also knows as
_succinct non-interactive computationally-sound zero-knowledge proofs of knowledge_).
For formal definitions and theoretical discussions about these, see
\[BCCT12], \[BCIOP13], and the references therein.
The libsnark library currently provides a C++ implementation of:
1. General-purpose proof systems:
1. A preprocessing zkSNARK for the NP-complete language "R1CS"
(_Rank-1 Constraint Systems_), which is a language that is similar to arithmetic
circuit satisfiability.
2. A preprocessing SNARK for a language of arithmetic circuits, "BACS"
(_Bilinear Arithmetic Circuit Satisfiability_). This simplifies the writing
of NP statements when the additional flexibility of R1CS is not needed.
Internally, it reduces to R1CS.
3. A preprocessing SNARK for the language "USCS"
(_Unitary-Square Constraint Systems_). This abstracts and implements the core
contribution of \[DFGK14]
4. A preprocessing SNARK for a language of Boolean circuits, "TBCS"
(_Two-input Boolean Circuit Satisfiability_). Internally, it reduces to USCS.
This is much more efficient than going through R1CS.
5. ADSNARK, a preprocessing SNARKs for proving statements on authenticated
data, as described in \[BBFR15].
6. Proof-Carrying Data (PCD). This uses recursive composition of SNARKs, as
explained in \[BCCT13] and optimized in \[BCTV14b].
2. Gadget libraries (gadgetlib1 and gadgetlib2) for constructing R1CS
instances out of modular "gadget" classes.
3. Examples of applications that use the above proof systems to prove
statements about:
1. Several toy examples.
2. Execution of TinyRAM machine code, as explained in \[BCTV14a] and
\[BCGTV13]. (Such machine code can be obtained, e.g., by compiling from C.)
This is easily adapted to any other Random Access Machine that satisfies a
simple load-store interface.
3. A scalable for TinyRAM using Proof-Carrying Data, as explained in \[BCTV14b]
4. Zero-knowldge cluster MapReduce, as explained in \[CTV15].
The zkSNARK construction implemented by libsnark follows, extends, and
optimizes the approach described in \[BCTV14], itself an extension of
\[BCGTV13], following the approach of \[BCIOP13] and \[GGPR13]. An alternative
implementation of the basic approach is the _Pinocchio_ system of \[PGHR13].
See these references for discussions of efficiency aspects that arise in
practical use of such constructions, as well as security and trust
considerations.
This scheme is a _preprocessing zkSNARK_ (_ppzkSNARK_): before proofs can be
created and verified, one needs to first decide on a size/circuit/system
representing the NP statements to be proved, and run a _generator_ algorithm to
create corresponding public parameters (a long proving key and a short
verification key).
Using the library involves the following high-level steps:
1. Express the statements to be proved as an R1CS (or any of the other
languages above, such as arithmetic circuits, Boolean circuits, or TinyRAM).
This is done by writing C++ code that constructs an R1CS, and linking this code
together with libsnark
2. Use libsnark's generator algorithm to create the public parameters for this
statement (once and for all).
3. Use libsnark's prover algorithm to create proofs of true statements about
the satisfiability of the R1CS.
4. Use libsnark's verifier algorithm to check proofs for alleged statements.
--------------------------------------------------------------------------------
The NP-complete language R1CS
--------------------------------------------------------------------------------
The ppzkSNARK supports proving/verifying membership in a specific NP-complete
language: R1CS (*rank-1 constraint systems*). An instance of the language is
specified by a set of equations over a prime field F, and each equation looks like:
< A, (1,X) > * < B , (1,X) > = < C, (1,X) >
where A,B,C are vectors over F, and X is a vector of variables.
In particular, arithmetic (as well as boolean) circuits are easily reducible to
this language by converting each gate into a rank-1 constraint. See \[BCGTV13]
Appendix E (and "System of Rank 1 Quadratic Equations") for more details about this.
--------------------------------------------------------------------------------
Elliptic curve choices
--------------------------------------------------------------------------------
The ppzkSNARK can be instantiated with different parameter choices, depending on
which elliptic curve is used. The libsnark library currently provides three
options:
* "edwards":
an instantiation based on an Edwards curve, providing 80 bits of security.
* "bn128":
an instantiation based on a Barreto-Naehrig curve, providing 128
bits of security. The underlying curve implementation is
\[ate-pairing], which has incorporated our patch that changes the
BN curve to one suitable for SNARK applications.
* This implementation uses dynamically-generated machine code for the curve
arithmetic. Some modern systems disallow execution of code on the heap, and
will thus block this implementation.
For example, on Fedora 20 at its default settings, you will get the error
`zmInit ERR:can't protect` when running this code. To solve this,
run `sudo setsebool -P allow_execheap 1` to allow execution,
or use `make CURVE=ALT_BN128` instead.
* "alt_bn128":
an alternative to "bn128", somewhat slower but avoids dynamic code generation.
Note that bn128 requires an x86-64 CPU while the other curve choices
should be architecture-independent; see [portability](#portability).
--------------------------------------------------------------------------------
Gadget libraries
--------------------------------------------------------------------------------
The libsnark library currently provides two libraries for conveniently constructing
R1CS instances out of reusable "gadgets". Both libraries provide a way to construct
gadgets on other gadgets as well as additional explicit equations. In this way,
complex R1CS instances can be built bottom up.
### gadgetlib1
This is a low-level library which expose all features of the preprocessing
zkSNARK for R1CS. Its design is based on templates (as does the ppzkSNARK code)
to efficiently support working on multiple elliptic curves simultaneously. This
library is used for most of the constraint-building in libsnark, both internal
(reductions and Proof-Carrying Data) and examples applications.
### gadgetlib2
This is an alternative library for constructing systems of polynomial equations
and, in particular, also R1CS instances. It is better documented and easier to
use than gadgetlib1, and its interface does not use templates. However, fewer
useful gadgets are provided.
--------------------------------------------------------------------------------
Security
--------------------------------------------------------------------------------
The theoretical security of the underlying mathematical constructions, and the
requisite assumptions, are analyzed in detailed in the aforementioned research
papers.
**
This code is a research-quality proof of concept, and has not
yet undergone extensive review or testing. It is thus not suitable,
as is, for use in critical or production systems.
**
Known issues include the following:
* The ppzkSNARK's generator and prover exhibit data-dependent running times
and memory usage. These form timing and cache-contention side channels,
which may be an issue in some applications.
* Randomness is retrieved from /dev/urandom, but this should be
changed to a carefully considered (depending on system and threat
model) external, high-quality randomness source when creating
long-term proving/verification keys.
--------------------------------------------------------------------------------
Build instructions
--------------------------------------------------------------------------------
The libsnark library relies on the following:
- C++ build environment
- GMP for certain bit-integer arithmetic
- libprocps for reporting memory usage
- GTest for some of the unit tests
So far we have tested these only on Linux, though we have been able to make the library work,
with some features disabled (such as memory profiling or GTest tests), on Windows via Cygwin
and on Mac OS X. (If you succeed in achieving more complete ports of the library, please
let us know!) See also the notes on [portability](#portability) below.
For example, on a fresh install of Ubuntu 14.04, install the following packages:
$ sudo apt-get install build-essential git libgmp3-dev libprocps3-dev libgtest-dev python-markdown libboost-all-dev libssl-dev
Or, on Fedora 20:
$ sudo yum install gcc-c++ make git gmp-devel procps-ng-devel gtest-devel python-markdown
Run the following, to fetch dependencies from their GitHub repos and compile them.
(Not required if you set `CURVE` to other than the default `BN128` and also set `NO_SUPERCOP=1`.)
$ ./prepare-depends.sh
Then, to compile the library, tests, profiling harness and documentation, run:
$ make
To create just the HTML documentation, run
$ make doc
and then view the resulting `README.html` (which contains the very text you are reading now).
To create Doxygen documentation summarizing all files, classes and functions,
with some (currently sparse) comments, install the `doxygen` and `graphviz` packages, then run
$ make doxy
(this may take a few minutes). Then view the resulting [`doxygen/index.html`](doxygen/index.html).
### Using libsnark as a library
To develop an application that uses libsnark, you could add it within the libsnark directory tree and adjust the Makefile, but it is far better to build libsnark as a (shared or static) library. You can then write your code in a separate directory tree, and link it against libsnark.
To build just the shared object library `libsnark.so`, run:
$ make lib
To build just the static library `libsnark.a`, run:
$ make lib STATIC=1
Note that static compilation requires static versions of all libraries it depends on.
It may help to minize these dependencies by appending
`CURVE=ALT_BN128 NO_PROCPS=1 NO_GTEST=1 NO_SUPERCOP=1`. On Fedora 21, the requisite
library RPM dependencies are then:
`boost-static glibc-static gmp-static libstdc++-static openssl-static zlib-static
boost-devel glibc-devel gmp-devel gmp-devel libstdc++-devel openssl-devel openssl-devel`.
To build *and install* the libsnark library:
$ make install PREFIX=/install/path
This will install `libsnark.so` into `/install/path/lib`; so your application should be linked using `-L/install/path/lib -lsnark`. It also installs the requisite headers into `/install/path/include`; so your application should be compiled using `-I/install/path/include`.
In addition, unless you use `NO_SUPERCOP=1`, `libsupercop.a` will be installed and should be linked in using `-lsupercop`.
### Building on Windows using Cygwin
Install Cygwin using the graphical installer, including the `g++`, `libgmp`
and `git` packages. Then disable the dependencies not easily supported under CygWin,
using:
$ make NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1
### Building on Mac OS X
On Mac OS X, install GMP from MacPorts (`port install gmp`). Then disable the
dependencies not easily supported under CygWin, using:
$ make NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1
MacPorts does not write its libraries into standard system folders, so you
might need to explicitly provide the paths to the header files and libraries by
appending `CXXFLAGS=-I/opt/local/include LDFLAGS=-L/opt/local/lib` to the line
above. Similarly, to pass the paths to ate-pairing you would run
`INC_DIR=-I/opt/local/include LIB_DIR=-L/opt/local/lib ./prepare-depends.sh`
instead of `./prepare-depends.sh` above.
--------------------------------------------------------------------------------
Tutorials
--------------------------------------------------------------------------------
libsnark includes a tutorial, and some usage examples, for the high-level API.
* `src/gadgetlib1/examples1` contains a simple example for constructing a
constraint system using gadgetlib1.
* `src/gadgetlib2/examples` contains a tutorial for using gadgetlib2 to express
NP statements as constraint systems. It introduces basic terminology, design
overview, and recommended programming style. It also shows how to invoke
ppzkSNARKs on such constraint systems. The main file, `tutorial.cpp`, builds
into a standalone executable.
* `src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp`
constructs a simple constraint system and runs the ppzksnark. See below for how to
run it.
--------------------------------------------------------------------------------
Executing profiling example
--------------------------------------------------------------------------------
The command
$ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 Fr
exercises the ppzkSNARK (first generator, then prover, then verifier) on an
R1CS instance with 1000 equations and an input consisting of 10 field elements.
(If you get the error `zmInit ERR:can't protect`, see the discussion
[above](#elliptic-curve-choices).)
The command
$ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 bytes
does the same but now the input consists of 10 bytes.
--------------------------------------------------------------------------------
Build options
--------------------------------------------------------------------------------
The following flags change the behavior of the compiled code.
* `make FEATUREFLAGS='-Dname1 -Dname2 ...'`
Override the active conditional #define names (you can see the default at the top of the Makefile).
The next bullets list the most important conditionally-#defined features.
For example, `make FEATUREFLAGS='-DBINARY_OUTPUT'` enables binary output and disables the default
assembly optimizations and Montgomery-representation output.
* define `BINARY_OUTPUT`
In serialization, output raw binary data (instead of decimal, when not set).
* `make CURVE=choice` / define `CURVE_choice` (where `choice` is one of:
ALT_BN128, BN128, EDWARDS, MNT4, MNT6)
Set the default curve to one of the above (see [elliptic curve choices](#elliptic-curve-choices)).
* `make DEBUG=1` / define `DEBUG`
Print additional information for debugging purposes.
* `make LOWMEM=1` / define `LOWMEM`
Limit the size of multi-exponentiation tables, for low-memory platforms.
* `make NO_DOCS=1`
Do not generate HTML documentation, e.g. on platforms where Markdown is not easily available.
* `make NO_PROCPS=1`
Do not link against libprocps. This disables memory profiling.
* `make NO_GTEST=1`
Do not link against GTest. The tutorial and test suite of gadgetlib2 tutorial won't be compiled.
* `make NO_SUPERCOP=1`
Do not link against SUPERCOP for optimized crypto. The ADSNARK executables will not be built.
* `make MULTICORE=1`
Enable parallelized execution of the ppzkSNARK generator and prover, using OpenMP.
This will utilize all cores on the CPU for heavyweight parallelizabe operations such as
FFT and multiexponentiation. The default is single-core.
To override the maximum number of cores used, set the environment variable `OMP_NUM_THREADS`
at runtime (not compile time), e.g., `OMP_NUM_THREADS=8 test_r1cs_sp_ppzkpc`. It defaults
to the autodetected number of cores, but on some devices, dynamic core management confused
OpenMP's autodetection, so setting `OMP_NUM_THREADS` is necessary for full utilization.
* define `NO_PT_COMPRESSION`
Do not use point compression.
This gives much faster serialization times, at the expense of ~2x larger
sizes for serialized keys and proofs.
* define `MONTGOMERY_OUTPUT` (on by default)
Serialize Fp elements as their Montgomery representations. If this
option is disabled then Fp elements are serialized as their
equivalence classes, which is slower but produces human-readable
output.
* `make PROFILE_OP_COUNTS=1` / define `PROFILE_OP_COUNTS`
Collect counts for field and curve operations inside static variables
of the corresponding algebraic objects. This option works for all
curves except bn128.
* define `USE_ASM` (on by default)
Use unrolled assembly routines for F[p] arithmetic and faster heap in
multi-exponentiation. (When not set, use GMP's `mpn_*` routines instead.)
* define `USE_MIXED_ADDITION`
Convert each element of the proving key and verification key to
affine coordinates. This allows using mixed addition formulas in
multiexponentiation and results in slightly faster prover and
verifier runtime at expense of increased proving time.
* `make PERFORMANCE=1`
Enables compiler optimizations such as link-time optimization, and disables debugging aids.
(On some distributions this causes a `plugin needed to handle lto object` link error and `undefined reference`s, which can be remedied by `AR=gcc-ar make ...`.)
Not all combinations are tested together or supported by every part of the codebase.
--------------------------------------------------------------------------------
Portability
--------------------------------------------------------------------------------
libsnark is written in fairly standard C++11.
However, having been developed on Linux on x86-64 CPUs, libsnark has some limitations
with respect to portability. Specifically:
1. libsnark's algebraic data structures assume little-endian byte order.
2. Profiling routines use `clock_gettime` and `readproc` calls, which are Linux-specific.
3. Random-number generation is done by reading from `/dev/urandom`, which is
specific to Unix-like systems.
4. libsnark binary serialization routines (see `BINARY_OUTPUT` above) assume
a fixed machine word size (i.e. sizeof(mp_limb_t) for GMP's limb data type).
Objects serialized in binary on a 64-bit system cannot be de-serialized on
a 32-bit system, and vice versa.
(The decimal serialization routines have no such limitation.)
5. libsnark requires a C++ compiler with good C++11 support. It has been
tested with g++ 4.7, g++ 4.8, and clang 3.4.
6. On x86-64, we by default use highly optimized assembly implementations for some
operations (see `USE_ASM` above). On other architectures we fall back to a
portable C++ implementation, which is slower.
Tested configurations include:
* Debian jessie with g++ 4.7 on x86-64
* Debian jessie with clang 3.4 on x86-64
* Fedora 20/21 with g++ 4.8.2/4.9.2 on x86-64 and i686
* Ubuntu 14.04 LTS with g++ 4.8 on x86-64
* Ubuntu 14.04 LTS with g++ 4.8 on x86-32, for EDWARDS and ALT_BN128 curve choices
* Debian wheezy with g++ 4.7 on ARM little endian (Debian armel port) inside QEMU, for EDWARDS and ALT_BN128 curve choices
* Windows 7 with g++ 4.8.3 under Cygwin 1.7.30 on x86-64 with NO_PROCPS=1, NO_GTEST=1 and NO_DOCS=1, for EDWARDS and ALT_BN128 curve choices
* Mac OS X 10.9.4 (Mavericks) with Apple LLVM version 5.1 (based on LLVM 3.4svn) on x86-64 with NO_PROCPS=1, NO_GTEST=1 and NO_DOCS=1
--------------------------------------------------------------------------------
Directory structure
--------------------------------------------------------------------------------
The directory structure of the libsnark library is as follows:
* src/ --- main C++ source code, containing the following modules:
* algebra/ --- fields and elliptic curve groups
* common/ --- miscellaneous utilities
* gadgetlib1/ --- gadgetlib1, a library to construct R1CS instances
* gadgets/ --- basic gadgets for gadgetlib1
* gadgetlib2/ --- gadgetlib2, a library to construct R1CS instances
* qap/ --- quadratic arithmetic program
* domains/ --- support for fast interpolation/evaluation, by providing
FFTs and Lagrange-coefficient computations for various domains
* relations/ --- interfaces for expressing statement (relations between instances and witnesses) as various NP-complete languages
* constraint_satisfaction_problems/ --- R1CS and USCS languages
* circuit_satisfaction_problems/ --- Boolean and arithmetic circuit satisfiability languages
* ram_computations/ --- RAM computation languages
* zk_proof_systems --- interfaces and implementations of the proof systems
* reductions --- reductions between languages (used internally, but contains many examples of building constraints)
Some of these module directories have the following subdirectories:
* ...
* examples/ --- example code and tutorials for this module
* tests/ --- unit tests for this module
In particular, the top-level API examples are at `src/r1cs_ppzksnark/examples/` and `src/gadgetlib2/examples/`.
* depsrc/ --- created by `prepare_depends.sh` for retrieved sourcecode and local builds of external code
(currently: \[ate-pairing], and its dependency xbyak).
* depinst/ --- created by `prepare_depends.sh` and `Makefile`
for local installation of locally-compiled dependencies.
* doxygen/ --- created by `make doxy` and contains a Doxygen summary of all files, classes etc. in libsnark.
--------------------------------------------------------------------------------
Further considerations
--------------------------------------------------------------------------------
### Multiexponentiation window size
The ppzkSNARK's generator has to solve a fixed-base multi-exponentiation
problem. We use a window-based method in which the optimal window size depends
on the size of the multiexponentiation instance *and* the platform.
On our benchmarking platform (a 3.40 GHz Intel Core i7-4770 CPU), we have
computed for each curve optimal windows, provided as
"fixed_base_exp_window_table" initialization sequences, for each curve; see
`X_init.cpp` for X=edwards,bn128,alt_bn128.
Performance on other platforms may not be optimal (but probably not be far off).
Future releases of the libsnark library will include a tool that generates
optimal window sizes.
--------------------------------------------------------------------------------
References
--------------------------------------------------------------------------------
\[BBFR15] [
_ADSNARK: nearly practical and privacy-preserving proofs on authenticated data_
](https://eprint.iacr.org/2014/617),
Michael Backes, Manuel Barbosa, Dario Fiore, Raphael M. Reischuk,
IEEE Symposium on Security and Privacy (Oakland) 2015
\[BCCT12] [
_From extractable collision resistance to succinct non-Interactive arguments of knowledge, and back again_
](http://eprint.iacr.org/2011/443),
Nir Bitansky, Ran Canetti, Alessandro Chiesa, Eran Tromer,
Innovations in Computer Science (ITCS) 2012
\[BCCT13] [
_Recursive composition and bootstrapping for SNARKs and proof-carrying data_
](http://eprint.iacr.org/2012/095)
Nir Bitansky, Ran Canetti, Alessandro Chiesa, Eran Tromer,
Symposium on Theory of Computing (STOC) 13
\[BCGTV13] [
_SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge_
](http://eprint.iacr.org/2013/507),
Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza,
CRYPTO 2013
\[BCIOP13] [
_Succinct Non-Interactive Arguments via Linear Interactive Proofs_
](http://eprint.iacr.org/2012/718),
Nir Bitansky, Alessandro Chiesa, Yuval Ishai, Rafail Ostrovsky, Omer Paneth,
Theory of Cryptography Conference 2013
\[BCTV14a] [
_Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture_
](http://eprint.iacr.org/2013/879),
Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza,
USENIX Security 2014
\[BCTV14b] [
_Scalable succinct non-interactive arguments via cycles of elliptic curves_
](https://eprint.iacr.org/2014/595),
Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza,
CRYPTO 2014
\[CTV15] [
_Cluster computing in zero knowledge_
](https://eprint.iacr.org/2015/377),
Alessandro Chiesa, Eran Tromer, Madars Virza,
Eurocrypt 2015
\[DFGK14] [
Square span programs with applications to succinct NIZK arguments
](https://eprint.iacr.org/2014/718),
George Danezis, Cedric Fournet, Jens Groth, Markulf Kohlweiss,
ASIACCS 2014
\[GGPR13] [
_Quadratic span programs and succinct NIZKs without PCPs_
](http://eprint.iacr.org/2012/215),
Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova,
EUROCRYPT 2013
\[ate-pairing] [
_High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves_
](https://github.com/herumi/ate-pairing),
MITSUNARI Shigeo, TERUYA Tadanori
\[PGHR13] [
_Pinocchio: Nearly Practical Verifiable Computation_
](http://eprint.iacr.org/2013/279),
Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova,
IEEE Symposium on Security and Privacy (Oakland) 2013
[SCIPR Lab]: http://www.scipr-lab.org/ (Succinct Computational Integrity and Privacy Research Lab)
[LICENSE]: LICENSE (LICENSE file in top directory of libsnark distribution)
[AUTHORS]: AUTHORS (AUTHORS file in top directory of libsnark distribution)

1807
src/snark/doxygen.conf

File diff suppressed because it is too large

525
src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp

@ -1,525 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp"
#include "common/assert_except.hpp"
namespace libsnark {
#ifdef PROFILE_OP_COUNTS
int64_t alt_bn128_G1::add_cnt = 0;
int64_t alt_bn128_G1::dbl_cnt = 0;
#endif
std::vector<uint64_t> alt_bn128_G1::wnaf_window_table;
std::vector<uint64_t> alt_bn128_G1::fixed_base_exp_window_table;
alt_bn128_G1 alt_bn128_G1::G1_zero;
alt_bn128_G1 alt_bn128_G1::G1_one;
alt_bn128_G1::alt_bn128_G1()
{
this->X = G1_zero.X;
this->Y = G1_zero.Y;
this->Z = G1_zero.Z;
}
void alt_bn128_G1::print() const
{
if (this->is_zero())
{
printf("O\n");
}
else
{
alt_bn128_G1 copy(*this);
copy.to_affine_coordinates();
gmp_printf("(%Nd , %Nd)\n",
copy.X.as_bigint().data, alt_bn128_Fq::num_limbs,
copy.Y.as_bigint().data, alt_bn128_Fq::num_limbs);
}
}
void alt_bn128_G1::print_coordinates() const
{
if (this->is_zero())
{
printf("O\n");
}
else
{
gmp_printf("(%Nd : %Nd : %Nd)\n",
this->X.as_bigint().data, alt_bn128_Fq::num_limbs,
this->Y.as_bigint().data, alt_bn128_Fq::num_limbs,
this->Z.as_bigint().data, alt_bn128_Fq::num_limbs);
}
}
void alt_bn128_G1::to_affine_coordinates()
{
if (this->is_zero())
{
this->X = alt_bn128_Fq::zero();
this->Y = alt_bn128_Fq::one();
this->Z = alt_bn128_Fq::zero();
}
else
{
alt_bn128_Fq Z_inv = Z.inverse();
alt_bn128_Fq Z2_inv = Z_inv.squared();
alt_bn128_Fq Z3_inv = Z2_inv * Z_inv;
this->X = this->X * Z2_inv;
this->Y = this->Y * Z3_inv;
this->Z = alt_bn128_Fq::one();
}
}
void alt_bn128_G1::to_special()
{
this->to_affine_coordinates();
}
bool alt_bn128_G1::is_special() const
{
return (this->is_zero() || this->Z == alt_bn128_Fq::one());
}
bool alt_bn128_G1::is_zero() const
{
return (this->Z.is_zero());
}
bool alt_bn128_G1::operator==(const alt_bn128_G1 &other) const
{
if (this->is_zero())
{
return other.is_zero();
}
if (other.is_zero())
{
return false;
}
/* now neither is O */
// using Jacobian coordinates so:
// (X1:Y1:Z1) = (X2:Y2:Z2)
// iff
// X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3
// iff
// X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3
alt_bn128_Fq Z1_squared = (this->Z).squared();
alt_bn128_Fq Z2_squared = (other.Z).squared();
if ((this->X * Z2_squared) != (other.X * Z1_squared))
{
return false;
}
alt_bn128_Fq Z1_cubed = (this->Z) * Z1_squared;
alt_bn128_Fq Z2_cubed = (other.Z) * Z2_squared;
if ((this->Y * Z2_cubed) != (other.Y * Z1_cubed))
{
return false;
}
return true;
}
bool alt_bn128_G1::operator!=(const alt_bn128_G1& other) const
{
return !(operator==(other));
}
alt_bn128_G1 alt_bn128_G1::operator+(const alt_bn128_G1 &other) const
{
// handle special cases having to do with O
if (this->is_zero())
{
return other;
}
if (other.is_zero())
{
return *this;
}
// no need to handle points of order 2,4
// (they cannot exist in a prime-order subgroup)
// check for doubling case
// using Jacobian coordinates so:
// (X1:Y1:Z1) = (X2:Y2:Z2)
// iff
// X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3
// iff
// X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3
alt_bn128_Fq Z1Z1 = (this->Z).squared();
alt_bn128_Fq Z2Z2 = (other.Z).squared();
alt_bn128_Fq U1 = this->X * Z2Z2;
alt_bn128_Fq U2 = other.X * Z1Z1;
alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1;
alt_bn128_Fq Z2_cubed = (other.Z) * Z2Z2;
alt_bn128_Fq S1 = (this->Y) * Z2_cubed; // S1 = Y1 * Z2 * Z2Z2
alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1
if (U1 == U2 && S1 == S2)
{
// dbl case; nothing of above can be reused
return this->dbl();
}
// rest of add case
alt_bn128_Fq H = U2 - U1; // H = U2-U1
alt_bn128_Fq S2_minus_S1 = S2-S1;
alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2
alt_bn128_Fq J = H * I; // J = H * I
alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1)
alt_bn128_Fq V = U1 * I; // V = U1 * I
alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V
alt_bn128_Fq S1_J = S1 * J;
alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J
alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
return alt_bn128_G1(X3, Y3, Z3);
}
alt_bn128_G1 alt_bn128_G1::operator-() const
{
return alt_bn128_G1(this->X, -(this->Y), this->Z);
}
alt_bn128_G1 alt_bn128_G1::operator-(const alt_bn128_G1 &other) const
{
return (*this) + (-other);
}
alt_bn128_G1 alt_bn128_G1::add(const alt_bn128_G1 &other) const
{
// handle special cases having to do with O
if (this->is_zero())
{
return other;
}
if (other.is_zero())
{
return *this;
}
// no need to handle points of order 2,4
// (they cannot exist in a prime-order subgroup)
// handle double case
if (this->operator==(other))
{
return this->dbl();
}
#ifdef PROFILE_OP_COUNTS
this->add_cnt++;
#endif
// NOTE: does not handle O and pts of order 2,4
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
alt_bn128_Fq Z1Z1 = (this->Z).squared(); // Z1Z1 = Z1^2
alt_bn128_Fq Z2Z2 = (other.Z).squared(); // Z2Z2 = Z2^2
alt_bn128_Fq U1 = (this->X) * Z2Z2; // U1 = X1 * Z2Z2
alt_bn128_Fq U2 = (other.X) * Z1Z1; // U2 = X2 * Z1Z1
alt_bn128_Fq S1 = (this->Y) * (other.Z) * Z2Z2; // S1 = Y1 * Z2 * Z2Z2
alt_bn128_Fq S2 = (other.Y) * (this->Z) * Z1Z1; // S2 = Y2 * Z1 * Z1Z1
alt_bn128_Fq H = U2 - U1; // H = U2-U1
alt_bn128_Fq S2_minus_S1 = S2-S1;
alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2
alt_bn128_Fq J = H * I; // J = H * I
alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1)
alt_bn128_Fq V = U1 * I; // V = U1 * I
alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V
alt_bn128_Fq S1_J = S1 * J;
alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J
alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
return alt_bn128_G1(X3, Y3, Z3);
}
alt_bn128_G1 alt_bn128_G1::mixed_add(const alt_bn128_G1 &other) const
{
#ifdef DEBUG
assert_except(other.is_special());
#endif
// handle special cases having to do with O
if (this->is_zero())
{
return other;
}
if (other.is_zero())
{
return *this;
}
// no need to handle points of order 2,4
// (they cannot exist in a prime-order subgroup)
// check for doubling case
// using Jacobian coordinates so:
// (X1:Y1:Z1) = (X2:Y2:Z2)
// iff
// X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3
// iff
// X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3
// we know that Z2 = 1
const alt_bn128_Fq Z1Z1 = (this->Z).squared();
const alt_bn128_Fq &U1 = this->X;
const alt_bn128_Fq U2 = other.X * Z1Z1;
const alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1;
const alt_bn128_Fq &S1 = (this->Y); // S1 = Y1 * Z2 * Z2Z2
const alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1
if (U1 == U2 && S1 == S2)
{
// dbl case; nothing of above can be reused
return this->dbl();
}
#ifdef PROFILE_OP_COUNTS
this->add_cnt++;
#endif
// NOTE: does not handle O and pts of order 2,4
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
alt_bn128_Fq H = U2-(this->X); // H = U2-X1
alt_bn128_Fq HH = H.squared() ; // HH = H&2
alt_bn128_Fq I = HH+HH; // I = 4*HH
I = I + I;
alt_bn128_Fq J = H*I; // J = H*I
alt_bn128_Fq r = S2-(this->Y); // r = 2*(S2-Y1)
r = r + r;
alt_bn128_Fq V = (this->X) * I ; // V = X1*I
alt_bn128_Fq X3 = r.squared()-J-V-V; // X3 = r^2-J-2*V
alt_bn128_Fq Y3 = (this->Y)*J; // Y3 = r*(V-X3)-2*Y1*J
Y3 = r*(V-X3) - Y3 - Y3;
alt_bn128_Fq Z3 = ((this->Z)+H).squared() - Z1Z1 - HH; // Z3 = (Z1+H)^2-Z1Z1-HH
return alt_bn128_G1(X3, Y3, Z3);
}
alt_bn128_G1 alt_bn128_G1::dbl() const
{
#ifdef PROFILE_OP_COUNTS
this->dbl_cnt++;
#endif
// handle point at infinity
if (this->is_zero())
{
return (*this);
}
// no need to handle points of order 2,4
// (they cannot exist in a prime-order subgroup)
// NOTE: does not handle O and pts of order 2,4
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
alt_bn128_Fq A = (this->X).squared(); // A = X1^2
alt_bn128_Fq B = (this->Y).squared(); // B = Y1^2
alt_bn128_Fq C = B.squared(); // C = B^2
alt_bn128_Fq D = (this->X + B).squared() - A - C;
D = D+D; // D = 2 * ((X1 + B)^2 - A - C)
alt_bn128_Fq E = A + A + A; // E = 3 * A
alt_bn128_Fq F = E.squared(); // F = E^2
alt_bn128_Fq X3 = F - (D+D); // X3 = F - 2 D
alt_bn128_Fq eightC = C+C;
eightC = eightC + eightC;
eightC = eightC + eightC;
alt_bn128_Fq Y3 = E * (D - X3) - eightC; // Y3 = E * (D - X3) - 8 * C
alt_bn128_Fq Y1Z1 = (this->Y)*(this->Z);
alt_bn128_Fq Z3 = Y1Z1 + Y1Z1; // Z3 = 2 * Y1 * Z1
return alt_bn128_G1(X3, Y3, Z3);
}
bool alt_bn128_G1::is_well_formed() const
{
if (this->is_zero())
{
return true;
}
else
{
/*
y^2 = x^3 + b
We are using Jacobian coordinates, so equation we need to check is actually
(y/z^3)^2 = (x/z^2)^3 + b
y^2 / z^6 = x^3 / z^6 + b
y^2 = x^3 + b z^6
*/
alt_bn128_Fq X2 = this->X.squared();
alt_bn128_Fq Y2 = this->Y.squared();
alt_bn128_Fq Z2 = this->Z.squared();
alt_bn128_Fq X3 = this->X * X2;
alt_bn128_Fq Z3 = this->Z * Z2;
alt_bn128_Fq Z6 = Z3.squared();
return (Y2 == X3 + alt_bn128_coeff_b * Z6);
}
}
alt_bn128_G1 alt_bn128_G1::zero()
{
return G1_zero;
}
alt_bn128_G1 alt_bn128_G1::one()
{
return G1_one;
}
alt_bn128_G1 alt_bn128_G1::random_element()
{
return (scalar_field::random_element().as_bigint()) * G1_one;
}
std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g)
{
alt_bn128_G1 copy(g);
copy.to_affine_coordinates();
out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR;
#ifdef NO_PT_COMPRESSION
out << copy.X << OUTPUT_SEPARATOR << copy.Y;
#else
/* storing LSB of Y */
out << copy.X << OUTPUT_SEPARATOR << (copy.Y.as_bigint().data[0] & 1);
#endif
return out;
}
std::istream& operator>>(std::istream &in, alt_bn128_G1 &g)
{
char is_zero;
alt_bn128_Fq tX, tY;
#ifdef NO_PT_COMPRESSION
in >> is_zero >> tX >> tY;
is_zero -= '0';
#else
in.read((char*)&is_zero, 1); // this reads is_zero;
is_zero -= '0';
consume_OUTPUT_SEPARATOR(in);
unsigned char Y_lsb;
in >> tX;
consume_OUTPUT_SEPARATOR(in);
in.read((char*)&Y_lsb, 1);
Y_lsb -= '0';
// y = +/- sqrt(x^3 + b)
if (!is_zero)
{
alt_bn128_Fq tX2 = tX.squared();
alt_bn128_Fq tY2 = tX2*tX + alt_bn128_coeff_b;
tY = tY2.sqrt();
if ((tY.as_bigint().data[0] & 1) != Y_lsb)
{
tY = -tY;
}
}
#endif
// using Jacobian coordinates
if (!is_zero)
{
g.X = tX;
g.Y = tY;
g.Z = alt_bn128_Fq::one();
}
else
{
g = alt_bn128_G1::zero();
}
return in;
}
std::ostream& operator<<(std::ostream& out, const std::vector<alt_bn128_G1> &v)
{
out << v.size() << "\n";
for (const alt_bn128_G1& t : v)
{
out << t << OUTPUT_NEWLINE;
}
return out;
}
std::istream& operator>>(std::istream& in, std::vector<alt_bn128_G1> &v)
{
v.clear();
size_t s;
in >> s;
consume_newline(in);
v.reserve(s);
for (size_t i = 0; i < s; ++i)
{
alt_bn128_G1 g;
in >> g;
consume_OUTPUT_NEWLINE(in);
v.emplace_back(g);
}
return in;
}
template<>
void batch_to_special_all_non_zeros<alt_bn128_G1>(std::vector<alt_bn128_G1> &vec)
{
std::vector<alt_bn128_Fq> Z_vec;
Z_vec.reserve(vec.size());
for (auto &el: vec)
{
Z_vec.emplace_back(el.Z);
}
batch_invert<alt_bn128_Fq>(Z_vec);
const alt_bn128_Fq one = alt_bn128_Fq::one();
for (size_t i = 0; i < vec.size(); ++i)
{
alt_bn128_Fq Z2 = Z_vec[i].squared();
alt_bn128_Fq Z3 = Z_vec[i] * Z2;
vec[i].X = vec[i].X * Z2;
vec[i].Y = vec[i].Y * Z3;
vec[i].Z = one;
}
}
} // libsnark

95
src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.hpp

@ -1,95 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef ALT_BN128_G1_HPP_
#define ALT_BN128_G1_HPP_
#include <vector>
#include "algebra/curves/alt_bn128/alt_bn128_init.hpp"
#include "algebra/curves/curve_utils.hpp"
namespace libsnark {
class alt_bn128_G1;
std::ostream& operator<<(std::ostream &, const alt_bn128_G1&);
std::istream& operator>>(std::istream &, alt_bn128_G1&);
class alt_bn128_G1 {
public:
#ifdef PROFILE_OP_COUNTS
static int64_t add_cnt;
static int64_t dbl_cnt;
#endif
static std::vector<uint64_t> wnaf_window_table;
static std::vector<uint64_t> fixed_base_exp_window_table;
static alt_bn128_G1 G1_zero;
static alt_bn128_G1 G1_one;
typedef alt_bn128_Fq base_field;
typedef alt_bn128_Fr scalar_field;
alt_bn128_Fq X, Y, Z;
// using Jacobian coordinates
alt_bn128_G1();
alt_bn128_G1(const alt_bn128_Fq& X, const alt_bn128_Fq& Y, const alt_bn128_Fq& Z) : X(X), Y(Y), Z(Z) {};
void print() const;
void print_coordinates() const;
void to_affine_coordinates();
void to_special();
bool is_special() const;
bool is_zero() const;
bool operator==(const alt_bn128_G1 &other) const;
bool operator!=(const alt_bn128_G1 &other) const;
alt_bn128_G1 operator+(const alt_bn128_G1 &other) const;
alt_bn128_G1 operator-() const;
alt_bn128_G1 operator-(const alt_bn128_G1 &other) const;
alt_bn128_G1 add(const alt_bn128_G1 &other) const;
alt_bn128_G1 mixed_add(const alt_bn128_G1 &other) const;
alt_bn128_G1 dbl() const;
bool is_well_formed() const;
static alt_bn128_G1 zero();
static alt_bn128_G1 one();
static alt_bn128_G1 random_element();
static size_t size_in_bits() { return base_field::size_in_bits() + 1; }
static bigint<base_field::num_limbs> base_field_char() { return base_field::field_char(); }
static bigint<scalar_field::num_limbs> order() { return scalar_field::field_char(); }
friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g);
friend std::istream& operator>>(std::istream &in, alt_bn128_G1 &g);
};
template<mp_size_t m>
alt_bn128_G1 operator*(const bigint<m> &lhs, const alt_bn128_G1 &rhs)
{
return scalar_mul<alt_bn128_G1, m>(rhs, lhs);
}
template<mp_size_t m, const bigint<m>& modulus_p>
alt_bn128_G1 operator*(const Fp_model<m,modulus_p> &lhs, const alt_bn128_G1 &rhs)
{
return scalar_mul<alt_bn128_G1, m>(rhs, lhs.as_bigint());
}
std::ostream& operator<<(std::ostream& out, const std::vector<alt_bn128_G1> &v);
std::istream& operator>>(std::istream& in, std::vector<alt_bn128_G1> &v);
template<typename T>
void batch_to_special_all_non_zeros(std::vector<T> &vec);
template<>
void batch_to_special_all_non_zeros<alt_bn128_G1>(std::vector<alt_bn128_G1> &vec);
} // libsnark
#endif // ALT_BN128_G1_HPP_

506
src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp

@ -1,506 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp"
#include "common/assert_except.hpp"
namespace libsnark {
#ifdef PROFILE_OP_COUNTS
int64_t alt_bn128_G2::add_cnt = 0;
int64_t alt_bn128_G2::dbl_cnt = 0;
#endif
std::vector<uint64_t> alt_bn128_G2::wnaf_window_table;
std::vector<uint64_t> alt_bn128_G2::fixed_base_exp_window_table;
alt_bn128_G2 alt_bn128_G2::G2_zero;
alt_bn128_G2 alt_bn128_G2::G2_one;
alt_bn128_G2::alt_bn128_G2()
{
this->X = G2_zero.X;
this->Y = G2_zero.Y;
this->Z = G2_zero.Z;
}
alt_bn128_Fq2 alt_bn128_G2::mul_by_b(const alt_bn128_Fq2 &elt)
{
return alt_bn128_Fq2(alt_bn128_twist_mul_by_b_c0 * elt.c0, alt_bn128_twist_mul_by_b_c1 * elt.c1);
}
void alt_bn128_G2::print() const
{
if (this->is_zero())
{
printf("O\n");
}
else
{
alt_bn128_G2 copy(*this);
copy.to_affine_coordinates();
gmp_printf("(%Nd*z + %Nd , %Nd*z + %Nd)\n",
copy.X.c1.as_bigint().data, alt_bn128_Fq::num_limbs,
copy.X.c0.as_bigint().data, alt_bn128_Fq::num_limbs,
copy.Y.c1.as_bigint().data, alt_bn128_Fq::num_limbs,
copy.Y.c0.as_bigint().data, alt_bn128_Fq::num_limbs);
}
}
void alt_bn128_G2::print_coordinates() const
{
if (this->is_zero())
{
printf("O\n");
}
else
{
gmp_printf("(%Nd*z + %Nd : %Nd*z + %Nd : %Nd*z + %Nd)\n",
this->X.c1.as_bigint().data, alt_bn128_Fq::num_limbs,
this->X.c0.as_bigint().data, alt_bn128_Fq::num_limbs,
this->Y.c1.as_bigint().data, alt_bn128_Fq::num_limbs,
this->Y.c0.as_bigint().data, alt_bn128_Fq::num_limbs,
this->Z.c1.as_bigint().data, alt_bn128_Fq::num_limbs,
this->Z.c0.as_bigint().data, alt_bn128_Fq::num_limbs);
}
}
void alt_bn128_G2::to_affine_coordinates()
{
if (this->is_zero())
{
this->X = alt_bn128_Fq2::zero();
this->Y = alt_bn128_Fq2::one();
this->Z = alt_bn128_Fq2::zero();
}
else
{
alt_bn128_Fq2 Z_inv = Z.inverse();
alt_bn128_Fq2 Z2_inv = Z_inv.squared();
alt_bn128_Fq2 Z3_inv = Z2_inv * Z_inv;
this->X = this->X * Z2_inv;
this->Y = this->Y * Z3_inv;
this->Z = alt_bn128_Fq2::one();
}
}
void alt_bn128_G2::to_special()
{
this->to_affine_coordinates();
}
bool alt_bn128_G2::is_special() const
{
return (this->is_zero() || this->Z == alt_bn128_Fq2::one());
}
bool alt_bn128_G2::is_zero() const
{
return (this->Z.is_zero());
}
bool alt_bn128_G2::operator==(const alt_bn128_G2 &other) const
{
if (this->is_zero())
{
return other.is_zero();
}
if (other.is_zero())
{
return false;
}
/* now neither is O */
// using Jacobian coordinates so:
// (X1:Y1:Z1) = (X2:Y2:Z2)
// iff
// X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3
// iff
// X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3
alt_bn128_Fq2 Z1_squared = (this->Z).squared();
alt_bn128_Fq2 Z2_squared = (other.Z).squared();
if ((this->X * Z2_squared) != (other.X * Z1_squared))
{
return false;
}
alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1_squared;
alt_bn128_Fq2 Z2_cubed = (other.Z) * Z2_squared;
if ((this->Y * Z2_cubed) != (other.Y * Z1_cubed))
{
return false;
}
return true;
}
bool alt_bn128_G2::operator!=(const alt_bn128_G2& other) const
{
return !(operator==(other));
}
alt_bn128_G2 alt_bn128_G2::operator+(const alt_bn128_G2 &other) const
{
// handle special cases having to do with O
if (this->is_zero())
{
return other;
}
if (other.is_zero())
{
return *this;
}
// no need to handle points of order 2,4
// (they cannot exist in a prime-order subgroup)
// check for doubling case
// using Jacobian coordinates so:
// (X1:Y1:Z1) = (X2:Y2:Z2)
// iff
// X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3
// iff
// X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3
alt_bn128_Fq2 Z1Z1 = (this->Z).squared();
alt_bn128_Fq2 Z2Z2 = (other.Z).squared();
alt_bn128_Fq2 U1 = this->X * Z2Z2;
alt_bn128_Fq2 U2 = other.X * Z1Z1;
alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1Z1;
alt_bn128_Fq2 Z2_cubed = (other.Z) * Z2Z2;
alt_bn128_Fq2 S1 = (this->Y) * Z2_cubed; // S1 = Y1 * Z2 * Z2Z2
alt_bn128_Fq2 S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1
if (U1 == U2 && S1 == S2)
{
// dbl case; nothing of above can be reused
return this->dbl();
}
// rest of add case
alt_bn128_Fq2 H = U2 - U1; // H = U2-U1
alt_bn128_Fq2 S2_minus_S1 = S2-S1;
alt_bn128_Fq2 I = (H+H).squared(); // I = (2 * H)^2
alt_bn128_Fq2 J = H * I; // J = H * I
alt_bn128_Fq2 r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1)
alt_bn128_Fq2 V = U1 * I; // V = U1 * I
alt_bn128_Fq2 X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V
alt_bn128_Fq2 S1_J = S1 * J;
alt_bn128_Fq2 Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J
alt_bn128_Fq2 Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
return alt_bn128_G2(X3, Y3, Z3);
}
alt_bn128_G2 alt_bn128_G2::operator-() const
{
return alt_bn128_G2(this->X, -(this->Y), this->Z);
}
alt_bn128_G2 alt_bn128_G2::operator-(const alt_bn128_G2 &other) const
{
return (*this) + (-other);
}
alt_bn128_G2 alt_bn128_G2::add(const alt_bn128_G2 &other) const
{
// handle special cases having to do with O
if (this->is_zero())
{
return other;
}
if (other.is_zero())
{
return *this;
}
// no need to handle points of order 2,4
// (they cannot exist in a prime-order subgroup)
// handle double case
if (this->operator==(other))
{
return this->dbl();
}
#ifdef PROFILE_OP_COUNTS
this->add_cnt++;
#endif
// NOTE: does not handle O and pts of order 2,4
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2
alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); // Z1Z1 = Z1^2
alt_bn128_Fq2 Z2Z2 = (other.Z).squared(); // Z2Z2 = Z2^2
alt_bn128_Fq2 U1 = (this->X) * Z2Z2; // U1 = X1 * Z2Z2
alt_bn128_Fq2 U2 = (other.X) * Z1Z1; // U2 = X2 * Z1Z1
alt_bn128_Fq2 S1 = (this->Y) * (other.Z) * Z2Z2; // S1 = Y1 * Z2 * Z2Z2
alt_bn128_Fq2 S2 = (other.Y) * (this->Z) * Z1Z1; // S2 = Y2 * Z1 * Z1Z1
alt_bn128_Fq2 H = U2 - U1; // H = U2-U1
alt_bn128_Fq2 S2_minus_S1 = S2-S1;
alt_bn128_Fq2 I = (H+H).squared(); // I = (2 * H)^2
alt_bn128_Fq2 J = H * I; // J = H * I
alt_bn128_Fq2 r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1)
alt_bn128_Fq2 V = U1 * I; // V = U1 * I
alt_bn128_Fq2 X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V
alt_bn128_Fq2 S1_J = S1 * J;
alt_bn128_Fq2 Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J
alt_bn128_Fq2 Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
return alt_bn128_G2(X3, Y3, Z3);
}
alt_bn128_G2 alt_bn128_G2::mixed_add(const alt_bn128_G2 &other) const
{
#ifdef DEBUG
assert_except(other.is_special());
#endif
// handle special cases having to do with O
if (this->is_zero())
{
return other;
}
if (other.is_zero())
{
return *this;
}
// no need to handle points of order 2,4
// (they cannot exist in a prime-order subgroup)
// check for doubling case
// using Jacobian coordinates so:
// (X1:Y1:Z1) = (X2:Y2:Z2)
// iff
// X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3
// iff
// X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3
// we know that Z2 = 1
const alt_bn128_Fq2 Z1Z1 = (this->Z).squared();
const alt_bn128_Fq2 &U1 = this->X;
const alt_bn128_Fq2 U2 = other.X * Z1Z1;
const alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1Z1;
const alt_bn128_Fq2 &S1 = (this->Y); // S1 = Y1 * Z2 * Z2Z2
const alt_bn128_Fq2 S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1
if (U1 == U2 && S1 == S2)
{
// dbl case; nothing of above can be reused
return this->dbl();
}
#ifdef PROFILE_OP_COUNTS
this->add_cnt++;
#endif
// NOTE: does not handle O and pts of order 2,4
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
alt_bn128_Fq2 H = U2-(this->X); // H = U2-X1
alt_bn128_Fq2 HH = H.squared() ; // HH = H&2
alt_bn128_Fq2 I = HH+HH; // I = 4*HH
I = I + I;
alt_bn128_Fq2 J = H*I; // J = H*I
alt_bn128_Fq2 r = S2-(this->Y); // r = 2*(S2-Y1)
r = r + r;
alt_bn128_Fq2 V = (this->X) * I ; // V = X1*I
alt_bn128_Fq2 X3 = r.squared()-J-V-V; // X3 = r^2-J-2*V
alt_bn128_Fq2 Y3 = (this->Y)*J; // Y3 = r*(V-X3)-2*Y1*J
Y3 = r*(V-X3) - Y3 - Y3;
alt_bn128_Fq2 Z3 = ((this->Z)+H).squared() - Z1Z1 - HH; // Z3 = (Z1+H)^2-Z1Z1-HH
return alt_bn128_G2(X3, Y3, Z3);
}
alt_bn128_G2 alt_bn128_G2::dbl() const
{
#ifdef PROFILE_OP_COUNTS
this->dbl_cnt++;
#endif
// handle point at infinity
if (this->is_zero())
{
return (*this);
}
// NOTE: does not handle O and pts of order 2,4
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl
alt_bn128_Fq2 A = (this->X).squared(); // A = X1^2
alt_bn128_Fq2 B = (this->Y).squared(); // B = Y1^2
alt_bn128_Fq2 C = B.squared(); // C = B^2
alt_bn128_Fq2 D = (this->X + B).squared() - A - C;
D = D+D; // D = 2 * ((X1 + B)^2 - A - C)
alt_bn128_Fq2 E = A + A + A; // E = 3 * A
alt_bn128_Fq2 F = E.squared(); // F = E^2
alt_bn128_Fq2 X3 = F - (D+D); // X3 = F - 2 D
alt_bn128_Fq2 eightC = C+C;
eightC = eightC + eightC;
eightC = eightC + eightC;
alt_bn128_Fq2 Y3 = E * (D - X3) - eightC; // Y3 = E * (D - X3) - 8 * C
alt_bn128_Fq2 Y1Z1 = (this->Y)*(this->Z);
alt_bn128_Fq2 Z3 = Y1Z1 + Y1Z1; // Z3 = 2 * Y1 * Z1
return alt_bn128_G2(X3, Y3, Z3);
}
alt_bn128_G2 alt_bn128_G2::mul_by_q() const
{
return alt_bn128_G2(alt_bn128_twist_mul_by_q_X * (this->X).Frobenius_map(1),
alt_bn128_twist_mul_by_q_Y * (this->Y).Frobenius_map(1),
(this->Z).Frobenius_map(1));
}
bool alt_bn128_G2::is_well_formed() const
{
if (this->is_zero())
{
return true;
}
else
{
/*
y^2 = x^3 + b
We are using Jacobian coordinates, so equation we need to check is actually
(y/z^3)^2 = (x/z^2)^3 + b
y^2 / z^6 = x^3 / z^6 + b
y^2 = x^3 + b z^6
*/
alt_bn128_Fq2 X2 = this->X.squared();
alt_bn128_Fq2 Y2 = this->Y.squared();
alt_bn128_Fq2 Z2 = this->Z.squared();
alt_bn128_Fq2 X3 = this->X * X2;
alt_bn128_Fq2 Z3 = this->Z * Z2;
alt_bn128_Fq2 Z6 = Z3.squared();
return (Y2 == X3 + alt_bn128_twist_coeff_b * Z6);
}
}
alt_bn128_G2 alt_bn128_G2::zero()
{
return G2_zero;
}
alt_bn128_G2 alt_bn128_G2::one()
{
return G2_one;
}
alt_bn128_G2 alt_bn128_G2::random_element()
{
return (alt_bn128_Fr::random_element().as_bigint()) * G2_one;
}
std::ostream& operator<<(std::ostream &out, const alt_bn128_G2 &g)
{
alt_bn128_G2 copy(g);
copy.to_affine_coordinates();
out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR;
#ifdef NO_PT_COMPRESSION
out << copy.X << OUTPUT_SEPARATOR << copy.Y;
#else
/* storing LSB of Y */
out << copy.X << OUTPUT_SEPARATOR << (copy.Y.c0.as_bigint().data[0] & 1);
#endif
return out;
}
std::istream& operator>>(std::istream &in, alt_bn128_G2 &g)
{
char is_zero;
alt_bn128_Fq2 tX, tY;
#ifdef NO_PT_COMPRESSION
in >> is_zero >> tX >> tY;
is_zero -= '0';
#else
in.read((char*)&is_zero, 1); // this reads is_zero;
is_zero -= '0';
consume_OUTPUT_SEPARATOR(in);
unsigned char Y_lsb;
in >> tX;
consume_OUTPUT_SEPARATOR(in);
in.read((char*)&Y_lsb, 1);
Y_lsb -= '0';
// y = +/- sqrt(x^3 + b)
if (!is_zero)
{
alt_bn128_Fq2 tX2 = tX.squared();
alt_bn128_Fq2 tY2 = tX2 * tX + alt_bn128_twist_coeff_b;
tY = tY2.sqrt();
if ((tY.c0.as_bigint().data[0] & 1) != Y_lsb)
{
tY = -tY;
}
}
#endif
// using projective coordinates
if (!is_zero)
{
g.X = tX;
g.Y = tY;
g.Z = alt_bn128_Fq2::one();
}
else
{
g = alt_bn128_G2::zero();
}
return in;
}
template<>
void batch_to_special_all_non_zeros<alt_bn128_G2>(std::vector<alt_bn128_G2> &vec)
{
std::vector<alt_bn128_Fq2> Z_vec;
Z_vec.reserve(vec.size());
for (auto &el: vec)
{
Z_vec.emplace_back(el.Z);
}
batch_invert<alt_bn128_Fq2>(Z_vec);
const alt_bn128_Fq2 one = alt_bn128_Fq2::one();
for (size_t i = 0; i < vec.size(); ++i)
{
alt_bn128_Fq2 Z2 = Z_vec[i].squared();
alt_bn128_Fq2 Z3 = Z_vec[i] * Z2;
vec[i].X = vec[i].X * Z2;
vec[i].Y = vec[i].Y * Z3;
vec[i].Z = one;
}
}
} // libsnark

96
src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.hpp

@ -1,96 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef ALT_BN128_G2_HPP_
#define ALT_BN128_G2_HPP_
#include <vector>
#include "algebra/curves/alt_bn128/alt_bn128_init.hpp"
#include "algebra/curves/curve_utils.hpp"
namespace libsnark {
class alt_bn128_G2;
std::ostream& operator<<(std::ostream &, const alt_bn128_G2&);
std::istream& operator>>(std::istream &, alt_bn128_G2&);
class alt_bn128_G2 {
public:
#ifdef PROFILE_OP_COUNTS
static int64_t add_cnt;
static int64_t dbl_cnt;
#endif
static std::vector<uint64_t> wnaf_window_table;
static std::vector<uint64_t> fixed_base_exp_window_table;
static alt_bn128_G2 G2_zero;
static alt_bn128_G2 G2_one;
typedef alt_bn128_Fq base_field;
typedef alt_bn128_Fq2 twist_field;
typedef alt_bn128_Fr scalar_field;
alt_bn128_Fq2 X, Y, Z;
// using Jacobian coordinates
alt_bn128_G2();
alt_bn128_G2(const alt_bn128_Fq2& X, const alt_bn128_Fq2& Y, const alt_bn128_Fq2& Z) : X(X), Y(Y), Z(Z) {};
static alt_bn128_Fq2 mul_by_b(const alt_bn128_Fq2 &elt);
void print() const;
void print_coordinates() const;
void to_affine_coordinates();
void to_special();
bool is_special() const;
bool is_zero() const;
bool operator==(const alt_bn128_G2 &other) const;
bool operator!=(const alt_bn128_G2 &other) const;
alt_bn128_G2 operator+(const alt_bn128_G2 &other) const;
alt_bn128_G2 operator-() const;
alt_bn128_G2 operator-(const alt_bn128_G2 &other) const;
alt_bn128_G2 add(const alt_bn128_G2 &other) const;
alt_bn128_G2 mixed_add(const alt_bn128_G2 &other) const;
alt_bn128_G2 dbl() const;
alt_bn128_G2 mul_by_q() const;
bool is_well_formed() const;
static alt_bn128_G2 zero();
static alt_bn128_G2 one();
static alt_bn128_G2 random_element();
static size_t size_in_bits() { return twist_field::size_in_bits() + 1; }
static bigint<base_field::num_limbs> base_field_char() { return base_field::field_char(); }
static bigint<scalar_field::num_limbs> order() { return scalar_field::field_char(); }
friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G2 &g);
friend std::istream& operator>>(std::istream &in, alt_bn128_G2 &g);
};
template<mp_size_t m>
alt_bn128_G2 operator*(const bigint<m> &lhs, const alt_bn128_G2 &rhs)
{
return scalar_mul<alt_bn128_G2, m>(rhs, lhs);
}
template<mp_size_t m, const bigint<m>& modulus_p>
alt_bn128_G2 operator*(const Fp_model<m,modulus_p> &lhs, const alt_bn128_G2 &rhs)
{
return scalar_mul<alt_bn128_G2, m>(rhs, lhs.as_bigint());
}
template<typename T>
void batch_to_special_all_non_zeros(std::vector<T> &vec);
template<>
void batch_to_special_all_non_zeros<alt_bn128_G2>(std::vector<alt_bn128_G2> &vec);
} // libsnark
#endif // ALT_BN128_G2_HPP_

273
src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp

@ -1,273 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "algebra/curves/alt_bn128/alt_bn128_init.hpp"
#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp"
#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp"
namespace libsnark {
bigint<alt_bn128_r_limbs> alt_bn128_modulus_r;
bigint<alt_bn128_q_limbs> alt_bn128_modulus_q;
alt_bn128_Fq alt_bn128_coeff_b;
alt_bn128_Fq2 alt_bn128_twist;
alt_bn128_Fq2 alt_bn128_twist_coeff_b;
alt_bn128_Fq alt_bn128_twist_mul_by_b_c0;
alt_bn128_Fq alt_bn128_twist_mul_by_b_c1;
alt_bn128_Fq2 alt_bn128_twist_mul_by_q_X;
alt_bn128_Fq2 alt_bn128_twist_mul_by_q_Y;
bigint<alt_bn128_q_limbs> alt_bn128_ate_loop_count;
bool alt_bn128_ate_is_loop_count_neg;
bigint<12*alt_bn128_q_limbs> alt_bn128_final_exponent;
bigint<alt_bn128_q_limbs> alt_bn128_final_exponent_z;
bool alt_bn128_final_exponent_is_z_neg;
void init_alt_bn128_params()
{
typedef bigint<alt_bn128_r_limbs> bigint_r;
typedef bigint<alt_bn128_q_limbs> bigint_q;
assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this
/* parameters for scalar field Fr */
alt_bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617");
assert(alt_bn128_Fr::modulus_is_valid());
if (sizeof(mp_limb_t) == 8)
{
alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783");
alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512");
alt_bn128_Fr::inv = 0xc2e1f593efffffff;
}
if (sizeof(mp_limb_t) == 4)
{
alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783");
alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512");
alt_bn128_Fr::inv = 0xefffffff;
}
alt_bn128_Fr::num_bits = 254;
alt_bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808");
alt_bn128_Fr::s = 28;
alt_bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111");
alt_bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055");
alt_bn128_Fr::multiplicative_generator = alt_bn128_Fr("5");
alt_bn128_Fr::root_of_unity = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904");
alt_bn128_Fr::nqr = alt_bn128_Fr("5");
alt_bn128_Fr::nqr_to_t = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904");
/* parameters for base field Fq */
alt_bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583");
assert(alt_bn128_Fq::modulus_is_valid());
if (sizeof(mp_limb_t) == 8)
{
alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209");
alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183");
alt_bn128_Fq::inv = 0x87d20782e4866389;
}
if (sizeof(mp_limb_t) == 4)
{
alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209");
alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183");
alt_bn128_Fq::inv = 0xe4866389;
}
alt_bn128_Fq::num_bits = 254;
alt_bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291");
alt_bn128_Fq::s = 1;
alt_bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291");
alt_bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145");
alt_bn128_Fq::multiplicative_generator = alt_bn128_Fq("3");
alt_bn128_Fq::root_of_unity = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582");
alt_bn128_Fq::nqr = alt_bn128_Fq("3");
alt_bn128_Fq::nqr_to_t = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582");
/* parameters for twist field Fq2 */
alt_bn128_Fq2::euler = bigint<2*alt_bn128_q_limbs>("239547588008311421220994022608339370399626158265550411218223901127035046843189118723920525909718935985594116157406550130918127817069793474323196511433944");
alt_bn128_Fq2::s = 4;
alt_bn128_Fq2::t = bigint<2*alt_bn128_q_limbs>("29943448501038927652624252826042421299953269783193801402277987640879380855398639840490065738714866998199264519675818766364765977133724184290399563929243");
alt_bn128_Fq2::t_minus_1_over_2 = bigint<2*alt_bn128_q_limbs>("14971724250519463826312126413021210649976634891596900701138993820439690427699319920245032869357433499099632259837909383182382988566862092145199781964621");
alt_bn128_Fq2::non_residue = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582");
alt_bn128_Fq2::nqr = alt_bn128_Fq2(alt_bn128_Fq("2"),alt_bn128_Fq("1"));
alt_bn128_Fq2::nqr_to_t = alt_bn128_Fq2(alt_bn128_Fq("5033503716262624267312492558379982687175200734934877598599011485707452665730"),alt_bn128_Fq("314498342015008975724433667930697407966947188435857772134235984660852259084"));
alt_bn128_Fq2::Frobenius_coeffs_c1[0] = alt_bn128_Fq("1");
alt_bn128_Fq2::Frobenius_coeffs_c1[1] = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582");
/* parameters for Fq6 */
alt_bn128_Fq6::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1"));
alt_bn128_Fq6::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0"));
alt_bn128_Fq6::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"),alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954"));
alt_bn128_Fq6::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0"));
alt_bn128_Fq6::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("3772000881919853776433695186713858239009073593817195771773381919316419345261"),alt_bn128_Fq("2236595495967245188281701248203181795121068902605861227855261137820944008926"));
alt_bn128_Fq6::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0"));
alt_bn128_Fq6::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("18429021223477853657660792034369865839114504446431234726392080002137598044644"),alt_bn128_Fq("9344045779998320333812420223237981029506012124075525679208581902008406485703"));
alt_bn128_Fq6::Frobenius_coeffs_c2[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0"));
alt_bn128_Fq6::Frobenius_coeffs_c2[1] = alt_bn128_Fq2(alt_bn128_Fq("2581911344467009335267311115468803099551665605076196740867805258568234346338"),alt_bn128_Fq("19937756971775647987995932169929341994314640652964949448313374472400716661030"));
alt_bn128_Fq6::Frobenius_coeffs_c2[2] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0"));
alt_bn128_Fq6::Frobenius_coeffs_c2[3] = alt_bn128_Fq2(alt_bn128_Fq("5324479202449903542726783395506214481928257762400643279780343368557297135718"),alt_bn128_Fq("16208900380737693084919495127334387981393726419856888799917914180988844123039"));
alt_bn128_Fq6::Frobenius_coeffs_c2[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0"));
alt_bn128_Fq6::Frobenius_coeffs_c2[5] = alt_bn128_Fq2(alt_bn128_Fq("13981852324922362344252311234282257507216387789820983642040889267519694726527"),alt_bn128_Fq("7629828391165209371577384193250820201684255241773809077146787135900891633097"));
/* parameters for Fq12 */
alt_bn128_Fq12::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1"));
alt_bn128_Fq12::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0"));
alt_bn128_Fq12::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("8376118865763821496583973867626364092589906065868298776909617916018768340080"),alt_bn128_Fq("16469823323077808223889137241176536799009286646108169935659301613961712198316"));
alt_bn128_Fq12::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556617"),alt_bn128_Fq("0"));
alt_bn128_Fq12::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("11697423496358154304825782922584725312912383441159505038794027105778954184319"),alt_bn128_Fq("303847389135065887422783454877609941456349188919719272345083954437860409601"));
alt_bn128_Fq12::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0"));
alt_bn128_Fq12::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("3321304630594332808241809054958361220322477375291206261884409189760185844239"),alt_bn128_Fq("5722266937896532885780051958958348231143373700109372999374820235121374419868"));
alt_bn128_Fq12::Frobenius_coeffs_c1[6] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"),alt_bn128_Fq("0"));
alt_bn128_Fq12::Frobenius_coeffs_c1[7] = alt_bn128_Fq2(alt_bn128_Fq("13512124006075453725662431877630910996106405091429524885779419978626457868503"),alt_bn128_Fq("5418419548761466998357268504080738289687024511189653727029736280683514010267"));
alt_bn128_Fq12::Frobenius_coeffs_c1[8] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0"));
alt_bn128_Fq12::Frobenius_coeffs_c1[9] = alt_bn128_Fq2(alt_bn128_Fq("10190819375481120917420622822672549775783927716138318623895010788866272024264"),alt_bn128_Fq("21584395482704209334823622290379665147239961968378104390343953940207365798982"));
alt_bn128_Fq12::Frobenius_coeffs_c1[10] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651967"),alt_bn128_Fq("0"));
alt_bn128_Fq12::Frobenius_coeffs_c1[11] = alt_bn128_Fq2(alt_bn128_Fq("18566938241244942414004596690298913868373833782006617400804628704885040364344"),alt_bn128_Fq("16165975933942742336466353786298926857552937457188450663314217659523851788715"));
/* choice of short Weierstrass curve and its twist */
alt_bn128_coeff_b = alt_bn128_Fq("3");
alt_bn128_twist = alt_bn128_Fq2(alt_bn128_Fq("9"), alt_bn128_Fq("1"));
alt_bn128_twist_coeff_b = alt_bn128_coeff_b * alt_bn128_twist.inverse();
alt_bn128_twist_mul_by_b_c0 = alt_bn128_coeff_b * alt_bn128_Fq2::non_residue;
alt_bn128_twist_mul_by_b_c1 = alt_bn128_coeff_b * alt_bn128_Fq2::non_residue;
alt_bn128_twist_mul_by_q_X = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"),
alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954"));
alt_bn128_twist_mul_by_q_Y = alt_bn128_Fq2(alt_bn128_Fq("2821565182194536844548159561693502659359617185244120367078079554186484126554"),
alt_bn128_Fq("3505843767911556378687030309984248845540243509899259641013678093033130930403"));
/* choice of group G1 */
alt_bn128_G1::G1_zero = alt_bn128_G1(alt_bn128_Fq::zero(),
alt_bn128_Fq::one(),
alt_bn128_Fq::zero());
alt_bn128_G1::G1_one = alt_bn128_G1(alt_bn128_Fq("1"),
alt_bn128_Fq("2"),
alt_bn128_Fq::one());
alt_bn128_G1::wnaf_window_table.push_back(11);
alt_bn128_G1::wnaf_window_table.push_back(24);
alt_bn128_G1::wnaf_window_table.push_back(60);
alt_bn128_G1::wnaf_window_table.push_back(127);
alt_bn128_G1::fixed_base_exp_window_table.resize(0);
// window 1 is unbeaten in [-inf, 4.99]
alt_bn128_G1::fixed_base_exp_window_table.push_back(1);
// window 2 is unbeaten in [4.99, 10.99]
alt_bn128_G1::fixed_base_exp_window_table.push_back(5);
// window 3 is unbeaten in [10.99, 32.29]
alt_bn128_G1::fixed_base_exp_window_table.push_back(11);
// window 4 is unbeaten in [32.29, 55.23]
alt_bn128_G1::fixed_base_exp_window_table.push_back(32);
// window 5 is unbeaten in [55.23, 162.03]
alt_bn128_G1::fixed_base_exp_window_table.push_back(55);
// window 6 is unbeaten in [162.03, 360.15]
alt_bn128_G1::fixed_base_exp_window_table.push_back(162);
// window 7 is unbeaten in [360.15, 815.44]
alt_bn128_G1::fixed_base_exp_window_table.push_back(360);
// window 8 is unbeaten in [815.44, 2373.07]
alt_bn128_G1::fixed_base_exp_window_table.push_back(815);
// window 9 is unbeaten in [2373.07, 6977.75]
alt_bn128_G1::fixed_base_exp_window_table.push_back(2373);
// window 10 is unbeaten in [6977.75, 7122.23]
alt_bn128_G1::fixed_base_exp_window_table.push_back(6978);
// window 11 is unbeaten in [7122.23, 57818.46]
alt_bn128_G1::fixed_base_exp_window_table.push_back(7122);
// window 12 is never the best
alt_bn128_G1::fixed_base_exp_window_table.push_back(0);
// window 13 is unbeaten in [57818.46, 169679.14]
alt_bn128_G1::fixed_base_exp_window_table.push_back(57818);
// window 14 is never the best
alt_bn128_G1::fixed_base_exp_window_table.push_back(0);
// window 15 is unbeaten in [169679.14, 439758.91]
alt_bn128_G1::fixed_base_exp_window_table.push_back(169679);
// window 16 is unbeaten in [439758.91, 936073.41]
alt_bn128_G1::fixed_base_exp_window_table.push_back(439759);
// window 17 is unbeaten in [936073.41, 4666554.74]
alt_bn128_G1::fixed_base_exp_window_table.push_back(936073);
// window 18 is never the best
alt_bn128_G1::fixed_base_exp_window_table.push_back(0);
// window 19 is unbeaten in [4666554.74, 7580404.42]
alt_bn128_G1::fixed_base_exp_window_table.push_back(4666555);
// window 20 is unbeaten in [7580404.42, 34552892.20]
alt_bn128_G1::fixed_base_exp_window_table.push_back(7580404);
// window 21 is never the best
alt_bn128_G1::fixed_base_exp_window_table.push_back(0);
// window 22 is unbeaten in [34552892.20, inf]
alt_bn128_G1::fixed_base_exp_window_table.push_back(34552892);
/* choice of group G2 */
alt_bn128_G2::G2_zero = alt_bn128_G2(alt_bn128_Fq2::zero(),
alt_bn128_Fq2::one(),
alt_bn128_Fq2::zero());
alt_bn128_G2::G2_one = alt_bn128_G2(alt_bn128_Fq2(alt_bn128_Fq("10857046999023057135944570762232829481370756359578518086990519993285655852781"),
alt_bn128_Fq("11559732032986387107991004021392285783925812861821192530917403151452391805634")),
alt_bn128_Fq2(alt_bn128_Fq("8495653923123431417604973247489272438418190587263600148770280649306958101930"),
alt_bn128_Fq("4082367875863433681332203403145435568316851327593401208105741076214120093531")),
alt_bn128_Fq2::one());
alt_bn128_G2::wnaf_window_table.push_back(5);
alt_bn128_G2::wnaf_window_table.push_back(15);
alt_bn128_G2::wnaf_window_table.push_back(39);
alt_bn128_G2::wnaf_window_table.push_back(109);
alt_bn128_G2::fixed_base_exp_window_table.resize(0);
// window 1 is unbeaten in [-inf, 5.10]
alt_bn128_G2::fixed_base_exp_window_table.push_back(1);
// window 2 is unbeaten in [5.10, 10.43]
alt_bn128_G2::fixed_base_exp_window_table.push_back(5);
// window 3 is unbeaten in [10.43, 25.28]
alt_bn128_G2::fixed_base_exp_window_table.push_back(10);
// window 4 is unbeaten in [25.28, 59.00]
alt_bn128_G2::fixed_base_exp_window_table.push_back(25);
// window 5 is unbeaten in [59.00, 154.03]
alt_bn128_G2::fixed_base_exp_window_table.push_back(59);
// window 6 is unbeaten in [154.03, 334.25]
alt_bn128_G2::fixed_base_exp_window_table.push_back(154);
// window 7 is unbeaten in [334.25, 742.58]
alt_bn128_G2::fixed_base_exp_window_table.push_back(334);
// window 8 is unbeaten in [742.58, 2034.40]
alt_bn128_G2::fixed_base_exp_window_table.push_back(743);
// window 9 is unbeaten in [2034.40, 4987.56]
alt_bn128_G2::fixed_base_exp_window_table.push_back(2034);
// window 10 is unbeaten in [4987.56, 8888.27]
alt_bn128_G2::fixed_base_exp_window_table.push_back(4988);
// window 11 is unbeaten in [8888.27, 26271.13]
alt_bn128_G2::fixed_base_exp_window_table.push_back(8888);
// window 12 is unbeaten in [26271.13, 39768.20]
alt_bn128_G2::fixed_base_exp_window_table.push_back(26271);
// window 13 is unbeaten in [39768.20, 106275.75]
alt_bn128_G2::fixed_base_exp_window_table.push_back(39768);
// window 14 is unbeaten in [106275.75, 141703.40]
alt_bn128_G2::fixed_base_exp_window_table.push_back(106276);
// window 15 is unbeaten in [141703.40, 462422.97]
alt_bn128_G2::fixed_base_exp_window_table.push_back(141703);
// window 16 is unbeaten in [462422.97, 926871.84]
alt_bn128_G2::fixed_base_exp_window_table.push_back(462423);
// window 17 is unbeaten in [926871.84, 4873049.17]
alt_bn128_G2::fixed_base_exp_window_table.push_back(926872);
// window 18 is never the best
alt_bn128_G2::fixed_base_exp_window_table.push_back(0);
// window 19 is unbeaten in [4873049.17, 5706707.88]
alt_bn128_G2::fixed_base_exp_window_table.push_back(4873049);
// window 20 is unbeaten in [5706707.88, 31673814.95]
alt_bn128_G2::fixed_base_exp_window_table.push_back(5706708);
// window 21 is never the best
alt_bn128_G2::fixed_base_exp_window_table.push_back(0);
// window 22 is unbeaten in [31673814.95, inf]
alt_bn128_G2::fixed_base_exp_window_table.push_back(31673815);
/* pairing parameters */
alt_bn128_ate_loop_count = bigint_q("29793968203157093288");
alt_bn128_ate_is_loop_count_neg = false;
alt_bn128_final_exponent = bigint<12*alt_bn128_q_limbs>("552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480");
alt_bn128_final_exponent_z = bigint_q("4965661367192848881");
alt_bn128_final_exponent_is_z_neg = false;
}
} // libsnark

57
src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.hpp

@ -1,57 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef ALT_BN128_INIT_HPP_
#define ALT_BN128_INIT_HPP_
#include "algebra/curves/public_params.hpp"
#include "algebra/fields/fp.hpp"
#include "algebra/fields/fp2.hpp"
#include "algebra/fields/fp6_3over2.hpp"
#include "algebra/fields/fp12_2over3over2.hpp"
namespace libsnark {
const mp_size_t alt_bn128_r_bitcount = 254;
const mp_size_t alt_bn128_q_bitcount = 254;
const mp_size_t alt_bn128_r_limbs = (alt_bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS;
const mp_size_t alt_bn128_q_limbs = (alt_bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS;
extern bigint<alt_bn128_r_limbs> alt_bn128_modulus_r;
extern bigint<alt_bn128_q_limbs> alt_bn128_modulus_q;
typedef Fp_model<alt_bn128_r_limbs, alt_bn128_modulus_r> alt_bn128_Fr;
typedef Fp_model<alt_bn128_q_limbs, alt_bn128_modulus_q> alt_bn128_Fq;
typedef Fp2_model<alt_bn128_q_limbs, alt_bn128_modulus_q> alt_bn128_Fq2;
typedef Fp6_3over2_model<alt_bn128_q_limbs, alt_bn128_modulus_q> alt_bn128_Fq6;
typedef Fp12_2over3over2_model<alt_bn128_q_limbs, alt_bn128_modulus_q> alt_bn128_Fq12;
typedef alt_bn128_Fq12 alt_bn128_GT;
// parameters for Barreto--Naehrig curve E/Fq : y^2 = x^3 + b
extern alt_bn128_Fq alt_bn128_coeff_b;
// parameters for twisted Barreto--Naehrig curve E'/Fq2 : y^2 = x^3 + b/xi
extern alt_bn128_Fq2 alt_bn128_twist;
extern alt_bn128_Fq2 alt_bn128_twist_coeff_b;
extern alt_bn128_Fq alt_bn128_twist_mul_by_b_c0;
extern alt_bn128_Fq alt_bn128_twist_mul_by_b_c1;
extern alt_bn128_Fq2 alt_bn128_twist_mul_by_q_X;
extern alt_bn128_Fq2 alt_bn128_twist_mul_by_q_Y;
// parameters for pairing
extern bigint<alt_bn128_q_limbs> alt_bn128_ate_loop_count;
extern bool alt_bn128_ate_is_loop_count_neg;
extern bigint<12*alt_bn128_q_limbs> alt_bn128_final_exponent;
extern bigint<alt_bn128_q_limbs> alt_bn128_final_exponent_z;
extern bool alt_bn128_final_exponent_is_z_neg;
void init_alt_bn128_params();
class alt_bn128_G1;
class alt_bn128_G2;
} // libsnark
#endif // ALT_BN128_INIT_HPP_

547
src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp

@ -1,547 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp"
#include "algebra/curves/alt_bn128/alt_bn128_init.hpp"
#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp"
#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp"
#include <cassert>
#include "common/profiling.hpp"
#include "common/assert_except.hpp"
namespace libsnark {
bool alt_bn128_ate_G1_precomp::operator==(const alt_bn128_ate_G1_precomp &other) const
{
return (this->PX == other.PX &&
this->PY == other.PY);
}
std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G1_precomp &prec_P)
{
out << prec_P.PX << OUTPUT_SEPARATOR << prec_P.PY;
return out;
}
std::istream& operator>>(std::istream &in, alt_bn128_ate_G1_precomp &prec_P)
{
in >> prec_P.PX;
consume_OUTPUT_SEPARATOR(in);
in >> prec_P.PY;
return in;
}
bool alt_bn128_ate_ell_coeffs::operator==(const alt_bn128_ate_ell_coeffs &other) const
{
return (this->ell_0 == other.ell_0 &&
this->ell_VW == other.ell_VW &&
this->ell_VV == other.ell_VV);
}
std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_ell_coeffs &c)
{
out << c.ell_0 << OUTPUT_SEPARATOR << c.ell_VW << OUTPUT_SEPARATOR << c.ell_VV;
return out;
}
std::istream& operator>>(std::istream &in, alt_bn128_ate_ell_coeffs &c)
{
in >> c.ell_0;
consume_OUTPUT_SEPARATOR(in);
in >> c.ell_VW;
consume_OUTPUT_SEPARATOR(in);
in >> c.ell_VV;
return in;
}
bool alt_bn128_ate_G2_precomp::operator==(const alt_bn128_ate_G2_precomp &other) const
{
return (this->QX == other.QX &&
this->QY == other.QY &&
this->coeffs == other.coeffs);
}
std::ostream& operator<<(std::ostream& out, const alt_bn128_ate_G2_precomp &prec_Q)
{
out << prec_Q.QX << OUTPUT_SEPARATOR << prec_Q.QY << "\n";
out << prec_Q.coeffs.size() << "\n";
for (const alt_bn128_ate_ell_coeffs &c : prec_Q.coeffs)
{
out << c << OUTPUT_NEWLINE;
}
return out;
}
std::istream& operator>>(std::istream& in, alt_bn128_ate_G2_precomp &prec_Q)
{
in >> prec_Q.QX;
consume_OUTPUT_SEPARATOR(in);
in >> prec_Q.QY;
consume_newline(in);
prec_Q.coeffs.clear();
size_t s;
in >> s;
consume_newline(in);
prec_Q.coeffs.reserve(s);
for (size_t i = 0; i < s; ++i)
{
alt_bn128_ate_ell_coeffs c;
in >> c;
consume_OUTPUT_NEWLINE(in);
prec_Q.coeffs.emplace_back(c);
}
return in;
}
/* final exponentiations */
alt_bn128_Fq12 alt_bn128_final_exponentiation_first_chunk(const alt_bn128_Fq12 &elt)
{
enter_block("Call to alt_bn128_final_exponentiation_first_chunk");
/*
Computes result = elt^((q^6-1)*(q^2+1)).
Follows, e.g., Beuchat et al page 9, by computing result as follows:
elt^((q^6-1)*(q^2+1)) = (conj(elt) * elt^(-1))^(q^2+1)
More precisely:
A = conj(elt)
B = elt.inverse()
C = A * B
D = C.Frobenius_map(2)
result = D * C
*/
const alt_bn128_Fq12 A = alt_bn128_Fq12(elt.c0,-elt.c1);
const alt_bn128_Fq12 B = elt.inverse();
const alt_bn128_Fq12 C = A * B;
const alt_bn128_Fq12 D = C.Frobenius_map(2);
const alt_bn128_Fq12 result = D * C;
leave_block("Call to alt_bn128_final_exponentiation_first_chunk");
return result;
}
alt_bn128_Fq12 alt_bn128_exp_by_neg_z(const alt_bn128_Fq12 &elt)
{
enter_block("Call to alt_bn128_exp_by_neg_z");
alt_bn128_Fq12 result = elt.cyclotomic_exp(alt_bn128_final_exponent_z);
if (!alt_bn128_final_exponent_is_z_neg)
{
result = result.unitary_inverse();
}
leave_block("Call to alt_bn128_exp_by_neg_z");
return result;
}
alt_bn128_Fq12 alt_bn128_final_exponentiation_last_chunk(const alt_bn128_Fq12 &elt)
{
enter_block("Call to alt_bn128_final_exponentiation_last_chunk");
/*
Follows Laura Fuentes-Castaneda et al. "Faster hashing to G2"
by computing:
result = elt^(q^3 * (12*z^3 + 6z^2 + 4z - 1) +
q^2 * (12*z^3 + 6z^2 + 6z) +
q * (12*z^3 + 6z^2 + 4z) +
1 * (12*z^3 + 12z^2 + 6z + 1))
which equals
result = elt^( 2z * ( 6z^2 + 3z + 1 ) * (q^4 - q^2 + 1)/r ).
Using the following addition chain:
A = exp_by_neg_z(elt) // = elt^(-z)
B = A^2 // = elt^(-2*z)
C = B^2 // = elt^(-4*z)
D = C * B // = elt^(-6*z)
E = exp_by_neg_z(D) // = elt^(6*z^2)
F = E^2 // = elt^(12*z^2)
G = epx_by_neg_z(F) // = elt^(-12*z^3)
H = conj(D) // = elt^(6*z)
I = conj(G) // = elt^(12*z^3)
J = I * E // = elt^(12*z^3 + 6*z^2)
K = J * H // = elt^(12*z^3 + 6*z^2 + 6*z)
L = K * B // = elt^(12*z^3 + 6*z^2 + 4*z)
M = K * E // = elt^(12*z^3 + 12*z^2 + 6*z)
N = M * elt // = elt^(12*z^3 + 12*z^2 + 6*z + 1)
O = L.Frobenius_map(1) // = elt^(q*(12*z^3 + 6*z^2 + 4*z))
P = O * N // = elt^(q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1))
Q = K.Frobenius_map(2) // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z))
R = Q * P // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1))
S = conj(elt) // = elt^(-1)
T = S * L // = elt^(12*z^3 + 6*z^2 + 4*z - 1)
U = T.Frobenius_map(3) // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1))
V = U * R // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1) + q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1))
result = V
*/
const alt_bn128_Fq12 A = alt_bn128_exp_by_neg_z(elt);
const alt_bn128_Fq12 B = A.cyclotomic_squared();
const alt_bn128_Fq12 C = B.cyclotomic_squared();
const alt_bn128_Fq12 D = C * B;
const alt_bn128_Fq12 E = alt_bn128_exp_by_neg_z(D);
const alt_bn128_Fq12 F = E.cyclotomic_squared();
const alt_bn128_Fq12 G = alt_bn128_exp_by_neg_z(F);
const alt_bn128_Fq12 H = D.unitary_inverse();
const alt_bn128_Fq12 I = G.unitary_inverse();
const alt_bn128_Fq12 J = I * E;
const alt_bn128_Fq12 K = J * H;
const alt_bn128_Fq12 L = K * B;
const alt_bn128_Fq12 M = K * E;
const alt_bn128_Fq12 N = M * elt;
const alt_bn128_Fq12 O = L.Frobenius_map(1);
const alt_bn128_Fq12 P = O * N;
const alt_bn128_Fq12 Q = K.Frobenius_map(2);
const alt_bn128_Fq12 R = Q * P;
const alt_bn128_Fq12 S = elt.unitary_inverse();
const alt_bn128_Fq12 T = S * L;
const alt_bn128_Fq12 U = T.Frobenius_map(3);
const alt_bn128_Fq12 V = U * R;
const alt_bn128_Fq12 result = V;
leave_block("Call to alt_bn128_final_exponentiation_last_chunk");
return result;
}
alt_bn128_GT alt_bn128_final_exponentiation(const alt_bn128_Fq12 &elt)
{
enter_block("Call to alt_bn128_final_exponentiation");
/* OLD naive version:
alt_bn128_GT result = elt^alt_bn128_final_exponent;
*/
alt_bn128_Fq12 A = alt_bn128_final_exponentiation_first_chunk(elt);
alt_bn128_GT result = alt_bn128_final_exponentiation_last_chunk(A);
leave_block("Call to alt_bn128_final_exponentiation");
return result;
}
/* ate pairing */
void doubling_step_for_flipped_miller_loop(const alt_bn128_Fq two_inv,
alt_bn128_G2 &current,
alt_bn128_ate_ell_coeffs &c)
{
const alt_bn128_Fq2 X = current.X, Y = current.Y, Z = current.Z;
const alt_bn128_Fq2 A = two_inv * (X * Y); // A = X1 * Y1 / 2
const alt_bn128_Fq2 B = Y.squared(); // B = Y1^2
const alt_bn128_Fq2 C = Z.squared(); // C = Z1^2
const alt_bn128_Fq2 D = C+C+C; // D = 3 * C
const alt_bn128_Fq2 E = alt_bn128_twist_coeff_b * D; // E = twist_b * D
const alt_bn128_Fq2 F = E+E+E; // F = 3 * E
const alt_bn128_Fq2 G = two_inv * (B+F); // G = (B+F)/2
const alt_bn128_Fq2 H = (Y+Z).squared() - (B+C); // H = (Y1+Z1)^2-(B+C)
const alt_bn128_Fq2 I = E-B; // I = E-B
const alt_bn128_Fq2 J = X.squared(); // J = X1^2
const alt_bn128_Fq2 E_squared = E.squared(); // E_squared = E^2
current.X = A * (B-F); // X3 = A * (B-F)
current.Y = G.squared() - (E_squared+E_squared+E_squared); // Y3 = G^2 - 3*E^2
current.Z = B * H; // Z3 = B * H
c.ell_0 = alt_bn128_twist * I; // ell_0 = xi * I
c.ell_VW = -H; // ell_VW = - H (later: * yP)
c.ell_VV = J+J+J; // ell_VV = 3*J (later: * xP)
}
void mixed_addition_step_for_flipped_miller_loop(const alt_bn128_G2 base,
alt_bn128_G2 &current,
alt_bn128_ate_ell_coeffs &c)
{
const alt_bn128_Fq2 X1 = current.X, Y1 = current.Y, Z1 = current.Z;
const alt_bn128_Fq2 &x2 = base.X, &y2 = base.Y;
const alt_bn128_Fq2 D = X1 - x2 * Z1; // D = X1 - X2*Z1
const alt_bn128_Fq2 E = Y1 - y2 * Z1; // E = Y1 - Y2*Z1
const alt_bn128_Fq2 F = D.squared(); // F = D^2
const alt_bn128_Fq2 G = E.squared(); // G = E^2
const alt_bn128_Fq2 H = D*F; // H = D*F
const alt_bn128_Fq2 I = X1 * F; // I = X1 * F
const alt_bn128_Fq2 J = H + Z1*G - (I+I); // J = H + Z1*G - (I+I)
current.X = D * J; // X3 = D*J
current.Y = E * (I-J)-(H * Y1); // Y3 = E*(I-J)-(H*Y1)
current.Z = Z1 * H; // Z3 = Z1*H
c.ell_0 = alt_bn128_twist * (E * x2 - D * y2); // ell_0 = xi * (E * X2 - D * Y2)
c.ell_VV = - E; // ell_VV = - E (later: * xP)
c.ell_VW = D; // ell_VW = D (later: * yP )
}
alt_bn128_ate_G1_precomp alt_bn128_ate_precompute_G1(const alt_bn128_G1& P)
{
enter_block("Call to alt_bn128_ate_precompute_G1");
alt_bn128_G1 Pcopy = P;
Pcopy.to_affine_coordinates();
alt_bn128_ate_G1_precomp result;
result.PX = Pcopy.X;
result.PY = Pcopy.Y;
leave_block("Call to alt_bn128_ate_precompute_G1");
return result;
}
alt_bn128_ate_G2_precomp alt_bn128_ate_precompute_G2(const alt_bn128_G2& Q)
{
enter_block("Call to alt_bn128_ate_precompute_G2");
alt_bn128_G2 Qcopy(Q);
Qcopy.to_affine_coordinates();
alt_bn128_Fq two_inv = (alt_bn128_Fq("2").inverse()); // could add to global params if needed
alt_bn128_ate_G2_precomp result;
result.QX = Qcopy.X;
result.QY = Qcopy.Y;
alt_bn128_G2 R;
R.X = Qcopy.X;
R.Y = Qcopy.Y;
R.Z = alt_bn128_Fq2::one();
const bigint<alt_bn128_Fr::num_limbs> &loop_count = alt_bn128_ate_loop_count;
bool found_one = false;
alt_bn128_ate_ell_coeffs c;
for (int64_t i = loop_count.max_bits(); i >= 0; --i)
{
const bool bit = loop_count.test_bit(i);
if (!found_one)
{
/* this skips the MSB itself */
found_one |= bit;
continue;
}
doubling_step_for_flipped_miller_loop(two_inv, R, c);
result.coeffs.push_back(c);
if (bit)
{
mixed_addition_step_for_flipped_miller_loop(Qcopy, R, c);
result.coeffs.push_back(c);
}
}
alt_bn128_G2 Q1 = Qcopy.mul_by_q();
assert_except(Q1.Z == alt_bn128_Fq2::one());
alt_bn128_G2 Q2 = Q1.mul_by_q();
assert_except(Q2.Z == alt_bn128_Fq2::one());
if (alt_bn128_ate_is_loop_count_neg)
{
R.Y = - R.Y;
}
Q2.Y = - Q2.Y;
mixed_addition_step_for_flipped_miller_loop(Q1, R, c);
result.coeffs.push_back(c);
mixed_addition_step_for_flipped_miller_loop(Q2, R, c);
result.coeffs.push_back(c);
leave_block("Call to alt_bn128_ate_precompute_G2");
return result;
}
alt_bn128_Fq12 alt_bn128_ate_miller_loop(const alt_bn128_ate_G1_precomp &prec_P,
const alt_bn128_ate_G2_precomp &prec_Q)
{
enter_block("Call to alt_bn128_ate_miller_loop");
alt_bn128_Fq12 f = alt_bn128_Fq12::one();
bool found_one = false;
size_t idx = 0;
const bigint<alt_bn128_Fr::num_limbs> &loop_count = alt_bn128_ate_loop_count;
alt_bn128_ate_ell_coeffs c;
for (int64_t i = loop_count.max_bits(); i >= 0; --i)
{
const bool bit = loop_count.test_bit(i);
if (!found_one)
{
/* this skips the MSB itself */
found_one |= bit;
continue;
}
/* code below gets executed for all bits (EXCEPT the MSB itself) of
alt_bn128_param_p (skipping leading zeros) in MSB to LSB
order */
c = prec_Q.coeffs[idx++];
f = f.squared();
f = f.mul_by_024(c.ell_0, prec_P.PY * c.ell_VW, prec_P.PX * c.ell_VV);
if (bit)
{
c = prec_Q.coeffs[idx++];
f = f.mul_by_024(c.ell_0, prec_P.PY * c.ell_VW, prec_P.PX * c.ell_VV);
}
}
if (alt_bn128_ate_is_loop_count_neg)
{
f = f.inverse();
}
c = prec_Q.coeffs[idx++];
f = f.mul_by_024(c.ell_0,prec_P.PY * c.ell_VW,prec_P.PX * c.ell_VV);
c = prec_Q.coeffs[idx++];
f = f.mul_by_024(c.ell_0,prec_P.PY * c.ell_VW,prec_P.PX * c.ell_VV);
leave_block("Call to alt_bn128_ate_miller_loop");
return f;
}
alt_bn128_Fq12 alt_bn128_ate_double_miller_loop(const alt_bn128_ate_G1_precomp &prec_P1,
const alt_bn128_ate_G2_precomp &prec_Q1,
const alt_bn128_ate_G1_precomp &prec_P2,
const alt_bn128_ate_G2_precomp &prec_Q2)
{
enter_block("Call to alt_bn128_ate_double_miller_loop");
alt_bn128_Fq12 f = alt_bn128_Fq12::one();
bool found_one = false;
size_t idx = 0;
const bigint<alt_bn128_Fr::num_limbs> &loop_count = alt_bn128_ate_loop_count;
for (int64_t i = loop_count.max_bits(); i >= 0; --i)
{
const bool bit = loop_count.test_bit(i);
if (!found_one)
{
/* this skips the MSB itself */
found_one |= bit;
continue;
}
/* code below gets executed for all bits (EXCEPT the MSB itself) of
alt_bn128_param_p (skipping leading zeros) in MSB to LSB
order */
alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx];
alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx];
++idx;
f = f.squared();
f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV);
f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV);
if (bit)
{
alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx];
alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx];
++idx;
f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV);
f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV);
}
}
if (alt_bn128_ate_is_loop_count_neg)
{
f = f.inverse();
}
alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx];
alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx];
++idx;
f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV);
f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV);
c1 = prec_Q1.coeffs[idx];
c2 = prec_Q2.coeffs[idx];
++idx;
f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV);
f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV);
leave_block("Call to alt_bn128_ate_double_miller_loop");
return f;
}
alt_bn128_Fq12 alt_bn128_ate_pairing(const alt_bn128_G1& P, const alt_bn128_G2 &Q)
{
enter_block("Call to alt_bn128_ate_pairing");
alt_bn128_ate_G1_precomp prec_P = alt_bn128_ate_precompute_G1(P);
alt_bn128_ate_G2_precomp prec_Q = alt_bn128_ate_precompute_G2(Q);
alt_bn128_Fq12 result = alt_bn128_ate_miller_loop(prec_P, prec_Q);
leave_block("Call to alt_bn128_ate_pairing");
return result;
}
alt_bn128_GT alt_bn128_ate_reduced_pairing(const alt_bn128_G1 &P, const alt_bn128_G2 &Q)
{
enter_block("Call to alt_bn128_ate_reduced_pairing");
const alt_bn128_Fq12 f = alt_bn128_ate_pairing(P, Q);
const alt_bn128_GT result = alt_bn128_final_exponentiation(f);
leave_block("Call to alt_bn128_ate_reduced_pairing");
return result;
}
/* choice of pairing */
alt_bn128_G1_precomp alt_bn128_precompute_G1(const alt_bn128_G1& P)
{
return alt_bn128_ate_precompute_G1(P);
}
alt_bn128_G2_precomp alt_bn128_precompute_G2(const alt_bn128_G2& Q)
{
return alt_bn128_ate_precompute_G2(Q);
}
alt_bn128_Fq12 alt_bn128_miller_loop(const alt_bn128_G1_precomp &prec_P,
const alt_bn128_G2_precomp &prec_Q)
{
return alt_bn128_ate_miller_loop(prec_P, prec_Q);
}
alt_bn128_Fq12 alt_bn128_double_miller_loop(const alt_bn128_G1_precomp &prec_P1,
const alt_bn128_G2_precomp &prec_Q1,
const alt_bn128_G1_precomp &prec_P2,
const alt_bn128_G2_precomp &prec_Q2)
{
return alt_bn128_ate_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2);
}
alt_bn128_Fq12 alt_bn128_pairing(const alt_bn128_G1& P,
const alt_bn128_G2 &Q)
{
return alt_bn128_ate_pairing(P, Q);
}
alt_bn128_GT alt_bn128_reduced_pairing(const alt_bn128_G1 &P,
const alt_bn128_G2 &Q)
{
return alt_bn128_ate_reduced_pairing(P, Q);
}
} // libsnark

92
src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.hpp

@ -1,92 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef ALT_BN128_PAIRING_HPP_
#define ALT_BN128_PAIRING_HPP_
#include <vector>
#include "algebra/curves/alt_bn128/alt_bn128_init.hpp"
namespace libsnark {
/* final exponentiation */
alt_bn128_GT alt_bn128_final_exponentiation(const alt_bn128_Fq12 &elt);
/* ate pairing */
struct alt_bn128_ate_G1_precomp {
alt_bn128_Fq PX;
alt_bn128_Fq PY;
bool operator==(const alt_bn128_ate_G1_precomp &other) const;
friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G1_precomp &prec_P);
friend std::istream& operator>>(std::istream &in, alt_bn128_ate_G1_precomp &prec_P);
};
struct alt_bn128_ate_ell_coeffs {
alt_bn128_Fq2 ell_0;
alt_bn128_Fq2 ell_VW;
alt_bn128_Fq2 ell_VV;
bool operator==(const alt_bn128_ate_ell_coeffs &other) const;
friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_ell_coeffs &dc);
friend std::istream& operator>>(std::istream &in, alt_bn128_ate_ell_coeffs &dc);
};
struct alt_bn128_ate_G2_precomp {
alt_bn128_Fq2 QX;
alt_bn128_Fq2 QY;
std::vector<alt_bn128_ate_ell_coeffs> coeffs;
bool operator==(const alt_bn128_ate_G2_precomp &other) const;
friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G2_precomp &prec_Q);
friend std::istream& operator>>(std::istream &in, alt_bn128_ate_G2_precomp &prec_Q);
};
alt_bn128_ate_G1_precomp alt_bn128_ate_precompute_G1(const alt_bn128_G1& P);
alt_bn128_ate_G2_precomp alt_bn128_ate_precompute_G2(const alt_bn128_G2& Q);
alt_bn128_Fq12 alt_bn128_ate_miller_loop(const alt_bn128_ate_G1_precomp &prec_P,
const alt_bn128_ate_G2_precomp &prec_Q);
alt_bn128_Fq12 alt_bn128_ate_double_miller_loop(const alt_bn128_ate_G1_precomp &prec_P1,
const alt_bn128_ate_G2_precomp &prec_Q1,
const alt_bn128_ate_G1_precomp &prec_P2,
const alt_bn128_ate_G2_precomp &prec_Q2);
alt_bn128_Fq12 alt_bn128_ate_pairing(const alt_bn128_G1& P,
const alt_bn128_G2 &Q);
alt_bn128_GT alt_bn128_ate_reduced_pairing(const alt_bn128_G1 &P,
const alt_bn128_G2 &Q);
/* choice of pairing */
typedef alt_bn128_ate_G1_precomp alt_bn128_G1_precomp;
typedef alt_bn128_ate_G2_precomp alt_bn128_G2_precomp;
alt_bn128_G1_precomp alt_bn128_precompute_G1(const alt_bn128_G1& P);
alt_bn128_G2_precomp alt_bn128_precompute_G2(const alt_bn128_G2& Q);
alt_bn128_Fq12 alt_bn128_miller_loop(const alt_bn128_G1_precomp &prec_P,
const alt_bn128_G2_precomp &prec_Q);
alt_bn128_Fq12 alt_bn128_double_miller_loop(const alt_bn128_G1_precomp &prec_P1,
const alt_bn128_G2_precomp &prec_Q1,
const alt_bn128_G1_precomp &prec_P2,
const alt_bn128_G2_precomp &prec_Q2);
alt_bn128_Fq12 alt_bn128_pairing(const alt_bn128_G1& P,
const alt_bn128_G2 &Q);
alt_bn128_GT alt_bn128_reduced_pairing(const alt_bn128_G1 &P,
const alt_bn128_G2 &Q);
alt_bn128_GT alt_bn128_affine_reduced_pairing(const alt_bn128_G1 &P,
const alt_bn128_G2 &Q);
} // libsnark
#endif // ALT_BN128_PAIRING_HPP_

58
src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp

@ -1,58 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp"
namespace libsnark {
void alt_bn128_pp::init_public_params()
{
init_alt_bn128_params();
}
alt_bn128_GT alt_bn128_pp::final_exponentiation(const alt_bn128_Fq12 &elt)
{
return alt_bn128_final_exponentiation(elt);
}
alt_bn128_G1_precomp alt_bn128_pp::precompute_G1(const alt_bn128_G1 &P)
{
return alt_bn128_precompute_G1(P);
}
alt_bn128_G2_precomp alt_bn128_pp::precompute_G2(const alt_bn128_G2 &Q)
{
return alt_bn128_precompute_G2(Q);
}
alt_bn128_Fq12 alt_bn128_pp::miller_loop(const alt_bn128_G1_precomp &prec_P,
const alt_bn128_G2_precomp &prec_Q)
{
return alt_bn128_miller_loop(prec_P, prec_Q);
}
alt_bn128_Fq12 alt_bn128_pp::double_miller_loop(const alt_bn128_G1_precomp &prec_P1,
const alt_bn128_G2_precomp &prec_Q1,
const alt_bn128_G1_precomp &prec_P2,
const alt_bn128_G2_precomp &prec_Q2)
{
return alt_bn128_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2);
}
alt_bn128_Fq12 alt_bn128_pp::pairing(const alt_bn128_G1 &P,
const alt_bn128_G2 &Q)
{
return alt_bn128_pairing(P, Q);
}
alt_bn128_Fq12 alt_bn128_pp::reduced_pairing(const alt_bn128_G1 &P,
const alt_bn128_G2 &Q)
{
return alt_bn128_reduced_pairing(P, Q);
}
} // libsnark

50
src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.hpp

@ -1,50 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef ALT_BN128_PP_HPP_
#define ALT_BN128_PP_HPP_
#include "algebra/curves/public_params.hpp"
#include "algebra/curves/alt_bn128/alt_bn128_init.hpp"
#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp"
#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp"
#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp"
namespace libsnark {
class alt_bn128_pp {
public:
typedef alt_bn128_Fr Fp_type;
typedef alt_bn128_G1 G1_type;
typedef alt_bn128_G2 G2_type;
typedef alt_bn128_G1_precomp G1_precomp_type;
typedef alt_bn128_G2_precomp G2_precomp_type;
typedef alt_bn128_Fq Fq_type;
typedef alt_bn128_Fq2 Fqe_type;
typedef alt_bn128_Fq12 Fqk_type;
typedef alt_bn128_GT GT_type;
static const bool has_affine_pairing = false;
static void init_public_params();
static alt_bn128_GT final_exponentiation(const alt_bn128_Fq12 &elt);
static alt_bn128_G1_precomp precompute_G1(const alt_bn128_G1 &P);
static alt_bn128_G2_precomp precompute_G2(const alt_bn128_G2 &Q);
static alt_bn128_Fq12 miller_loop(const alt_bn128_G1_precomp &prec_P,
const alt_bn128_G2_precomp &prec_Q);
static alt_bn128_Fq12 double_miller_loop(const alt_bn128_G1_precomp &prec_P1,
const alt_bn128_G2_precomp &prec_Q1,
const alt_bn128_G1_precomp &prec_P2,
const alt_bn128_G2_precomp &prec_Q2);
static alt_bn128_Fq12 pairing(const alt_bn128_G1 &P,
const alt_bn128_G2 &Q);
static alt_bn128_Fq12 reduced_pairing(const alt_bn128_G1 &P,
const alt_bn128_G2 &Q);
};
} // libsnark
#endif // ALT_BN128_PP_HPP_

22
src/snark/libsnark/algebra/curves/curve_utils.hpp

@ -1,22 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef CURVE_UTILS_HPP_
#define CURVE_UTILS_HPP_
#include <cstdint>
#include "algebra/fields/bigint.hpp"
namespace libsnark {
template<typename GroupT, mp_size_t m>
GroupT scalar_mul(const GroupT &base, const bigint<m> &scalar);
} // libsnark
#include "algebra/curves/curve_utils.tcc"
#endif // CURVE_UTILS_HPP_

37
src/snark/libsnark/algebra/curves/curve_utils.tcc

@ -1,37 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef CURVE_UTILS_TCC_
#define CURVE_UTILS_TCC_
namespace libsnark {
template<typename GroupT, mp_size_t m>
GroupT scalar_mul(const GroupT &base, const bigint<m> &scalar)
{
GroupT result = GroupT::zero();
bool found_one = false;
for (int64_t i = scalar.max_bits() - 1; i >= 0; --i)
{
if (found_one)
{
result = result.dbl();
}
if (scalar.test_bit(i))
{
found_one = true;
result = result + base;
}
}
return result;
}
} // libsnark
#endif // CURVE_UTILS_TCC_

103
src/snark/libsnark/algebra/curves/public_params.hpp

@ -1,103 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef PUBLIC_PARAMS_HPP_
#define PUBLIC_PARAMS_HPP_
#include <vector>
namespace libsnark {
/*
for every curve the user should define corresponding
public_params with the following typedefs:
Fp_type
G1_type
G2_type
G1_precomp_type
G2_precomp_type
affine_ate_G1_precomp_type
affine_ate_G2_precomp_type
Fq_type
Fqe_type
Fqk_type
GT_type
one should also define the following static methods:
void init_public_params();
GT<EC_ppT> final_exponentiation(const Fqk<EC_ppT> &elt);
G1_precomp<EC_ppT> precompute_G1(const G1<EC_ppT> &P);
G2_precomp<EC_ppT> precompute_G2(const G2<EC_ppT> &Q);
Fqk<EC_ppT> miller_loop(const G1_precomp<EC_ppT> &prec_P,
const G2_precomp<EC_ppT> &prec_Q);
affine_ate_G1_precomp<EC_ppT> affine_ate_precompute_G1(const G1<EC_ppT> &P);
affine_ate_G2_precomp<EC_ppT> affine_ate_precompute_G2(const G2<EC_ppT> &Q);
Fqk<EC_ppT> affine_ate_miller_loop(const affine_ate_G1_precomp<EC_ppT> &prec_P,
const affine_ate_G2_precomp<EC_ppT> &prec_Q);
Fqk<EC_ppT> affine_ate_e_over_e_miller_loop(const affine_ate_G1_precomp<EC_ppT> &prec_P1,
const affine_ate_G2_precomp<EC_ppT> &prec_Q1,
const affine_ate_G1_precomp<EC_ppT> &prec_P2,
const affine_ate_G2_precomp<EC_ppT> &prec_Q2);
Fqk<EC_ppT> affine_ate_e_times_e_over_e_miller_loop(const affine_ate_G1_precomp<EC_ppT> &prec_P1,
const affine_ate_G2_precomp<EC_ppT> &prec_Q1,
const affine_ate_G1_precomp<EC_ppT> &prec_P2,
const affine_ate_G2_precomp<EC_ppT> &prec_Q2,
const affine_ate_G1_precomp<EC_ppT> &prec_P3,
const affine_ate_G2_precomp<EC_ppT> &prec_Q3);
Fqk<EC_ppT> double_miller_loop(const G1_precomp<EC_ppT> &prec_P1,
const G2_precomp<EC_ppT> &prec_Q1,
const G1_precomp<EC_ppT> &prec_P2,
const G2_precomp<EC_ppT> &prec_Q2);
Fqk<EC_ppT> pairing(const G1<EC_ppT> &P,
const G2<EC_ppT> &Q);
GT<EC_ppT> reduced_pairing(const G1<EC_ppT> &P,
const G2<EC_ppT> &Q);
GT<EC_ppT> affine_reduced_pairing(const G1<EC_ppT> &P,
const G2<EC_ppT> &Q);
*/
template<typename EC_ppT>
using Fr = typename EC_ppT::Fp_type;
template<typename EC_ppT>
using G1 = typename EC_ppT::G1_type;
template<typename EC_ppT>
using G2 = typename EC_ppT::G2_type;
template<typename EC_ppT>
using G1_precomp = typename EC_ppT::G1_precomp_type;
template<typename EC_ppT>
using G2_precomp = typename EC_ppT::G2_precomp_type;
template<typename EC_ppT>
using affine_ate_G1_precomp = typename EC_ppT::affine_ate_G1_precomp_type;
template<typename EC_ppT>
using affine_ate_G2_precomp = typename EC_ppT::affine_ate_G2_precomp_type;
template<typename EC_ppT>
using Fq = typename EC_ppT::Fq_type;
template<typename EC_ppT>
using Fqe = typename EC_ppT::Fqe_type;
template<typename EC_ppT>
using Fqk = typename EC_ppT::Fqk_type;
template<typename EC_ppT>
using GT = typename EC_ppT::GT_type;
template<typename EC_ppT>
using Fr_vector = std::vector<Fr<EC_ppT> >;
template<typename EC_ppT>
using G1_vector = std::vector<G1<EC_ppT> >;
template<typename EC_ppT>
using G2_vector = std::vector<G2<EC_ppT> >;
} // libsnark
#endif // PUBLIC_PARAMS_HPP_

139
src/snark/libsnark/algebra/curves/tests/test_bilinearity.cpp

@ -1,139 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include <iostream>
#include "common/profiling.hpp"
//#include "algebra/curves/edwards/edwards_pp.hpp"
#ifdef CURVE_BN128
#include "algebra/curves/bn128/bn128_pp.hpp"
#endif
#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp"
//#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp"
//#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp"
#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp"
#include "algebra/curves/alt_bn128/alt_bn128_pairing.cpp"
using namespace libsnark;
template<typename ppT>
void pairing_test()
{
GT<ppT> GT_one = GT<ppT>::one();
printf("Running bilinearity tests:\n");
G1<ppT> P = (Fr<ppT>::random_element()) * G1<ppT>::one();
//G1<ppT> P = Fr<ppT>("2") * G1<ppT>::one();
G2<ppT> Q = (Fr<ppT>::random_element()) * G2<ppT>::one();
//G2<ppT> Q = Fr<ppT>("3") * G2<ppT>::one();
printf("P:\n");
P.print();
P.print_coordinates();
printf("Q:\n");
Q.print();
Q.print_coordinates();
printf("\n\n");
Fr<ppT> s = Fr<ppT>::random_element();
//Fr<ppT> s = Fr<ppT>("2");
G1<ppT> sP = s * P;
G2<ppT> sQ = s * Q;
printf("Pairing bilinearity tests (three must match):\n");
GT<ppT> ans1 = ppT::reduced_pairing(sP, Q);
GT<ppT> ans2 = ppT::reduced_pairing(P, sQ);
GT<ppT> ans3 = ppT::reduced_pairing(P, Q)^s;
ans1.print();
ans2.print();
ans3.print();
assert(ans1 == ans2);
assert(ans2 == ans3);
assert(ans1 != GT_one);
assert((ans1^Fr<ppT>::field_char()) == GT_one);
printf("\n\n");
}
template<typename ppT>
void double_miller_loop_test()
{
const G1<ppT> P1 = (Fr<ppT>::random_element()) * G1<ppT>::one();
const G1<ppT> P2 = (Fr<ppT>::random_element()) * G1<ppT>::one();
const G2<ppT> Q1 = (Fr<ppT>::random_element()) * G2<ppT>::one();
const G2<ppT> Q2 = (Fr<ppT>::random_element()) * G2<ppT>::one();
const G1_precomp<ppT> prec_P1 = ppT::precompute_G1(P1);
const G1_precomp<ppT> prec_P2 = ppT::precompute_G1(P2);
const G2_precomp<ppT> prec_Q1 = ppT::precompute_G2(Q1);
const G2_precomp<ppT> prec_Q2 = ppT::precompute_G2(Q2);
const Fqk<ppT> ans_1 = ppT::miller_loop(prec_P1, prec_Q1);
const Fqk<ppT> ans_2 = ppT::miller_loop(prec_P2, prec_Q2);
const Fqk<ppT> ans_12 = ppT::double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2);
assert(ans_1 * ans_2 == ans_12);
}
template<typename ppT>
void affine_pairing_test()
{
GT<ppT> GT_one = GT<ppT>::one();
printf("Running bilinearity tests:\n");
G1<ppT> P = (Fr<ppT>::random_element()) * G1<ppT>::one();
G2<ppT> Q = (Fr<ppT>::random_element()) * G2<ppT>::one();
printf("P:\n");
P.print();
printf("Q:\n");
Q.print();
printf("\n\n");
Fr<ppT> s = Fr<ppT>::random_element();
G1<ppT> sP = s * P;
G2<ppT> sQ = s * Q;
printf("Pairing bilinearity tests (three must match):\n");
GT<ppT> ans1 = ppT::affine_reduced_pairing(sP, Q);
GT<ppT> ans2 = ppT::affine_reduced_pairing(P, sQ);
GT<ppT> ans3 = ppT::affine_reduced_pairing(P, Q)^s;
ans1.print();
ans2.print();
ans3.print();
assert(ans1 == ans2);
assert(ans2 == ans3);
assert(ans1 != GT_one);
assert((ans1^Fr<ppT>::field_char()) == GT_one);
printf("\n\n");
}
int main(void)
{
start_profiling();
edwards_pp::init_public_params();
pairing_test<edwards_pp>();
double_miller_loop_test<edwards_pp>();
mnt6_pp::init_public_params();
pairing_test<mnt6_pp>();
double_miller_loop_test<mnt6_pp>();
affine_pairing_test<mnt6_pp>();
mnt4_pp::init_public_params();
pairing_test<mnt4_pp>();
double_miller_loop_test<mnt4_pp>();
affine_pairing_test<mnt4_pp>();
alt_bn128_pp::init_public_params();
pairing_test<alt_bn128_pp>();
double_miller_loop_test<alt_bn128_pp>();
#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled
bn128_pp::init_public_params();
pairing_test<bn128_pp>();
double_miller_loop_test<bn128_pp>();
#endif
}

176
src/snark/libsnark/algebra/curves/tests/test_groups.cpp

@ -1,176 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "common/profiling.hpp"
//#include "algebra/curves/edwards/edwards_pp.hpp"
//#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp"
//#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp"
#ifdef CURVE_BN128
#include "algebra/curves/bn128/bn128_pp.hpp"
#endif
#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp"
#include <sstream>
using namespace libsnark;
template<typename GroupT>
void test_mixed_add()
{
GroupT base, el, result;
base = GroupT::zero();
el = GroupT::zero();
el.to_special();
result = base.mixed_add(el);
assert(result == base + el);
base = GroupT::zero();
el = GroupT::random_element();
el.to_special();
result = base.mixed_add(el);
assert(result == base + el);
base = GroupT::random_element();
el = GroupT::zero();
el.to_special();
result = base.mixed_add(el);
assert(result == base + el);
base = GroupT::random_element();
el = GroupT::random_element();
el.to_special();
result = base.mixed_add(el);
assert(result == base + el);
base = GroupT::random_element();
el = base;
el.to_special();
result = base.mixed_add(el);
assert(result == base.dbl());
}
template<typename GroupT>
void test_group()
{
bigint<1> rand1 = bigint<1>("76749407");
bigint<1> rand2 = bigint<1>("44410867");
bigint<1> randsum = bigint<1>("121160274");
GroupT zero = GroupT::zero();
assert(zero == zero);
GroupT one = GroupT::one();
assert(one == one);
GroupT two = bigint<1>(2l) * GroupT::one();
assert(two == two);
GroupT five = bigint<1>(5l) * GroupT::one();
GroupT three = bigint<1>(3l) * GroupT::one();
GroupT four = bigint<1>(4l) * GroupT::one();
assert(two+five == three+four);
GroupT a = GroupT::random_element();
GroupT b = GroupT::random_element();
assert(one != zero);
assert(a != zero);
assert(a != one);
assert(b != zero);
assert(b != one);
assert(a.dbl() == a + a);
assert(b.dbl() == b + b);
assert(one.add(two) == three);
assert(two.add(one) == three);
assert(a + b == b + a);
assert(a - a == zero);
assert(a - b == a + (-b));
assert(a - b == (-b) + a);
// handle special cases
assert(zero + (-a) == -a);
assert(zero - a == -a);
assert(a - zero == a);
assert(a + zero == a);
assert(zero + a == a);
assert((a + b).dbl() == (a + b) + (b + a));
assert(bigint<1>("2") * (a + b) == (a + b) + (b + a));
assert((rand1 * a) + (rand2 * a) == (randsum * a));
assert(GroupT::order() * a == zero);
assert(GroupT::order() * one == zero);
assert((GroupT::order() * a) - a != zero);
assert((GroupT::order() * one) - one != zero);
test_mixed_add<GroupT>();
}
template<typename GroupT>
void test_mul_by_q()
{
GroupT a = GroupT::random_element();
assert((GroupT::base_field_char()*a) == a.mul_by_q());
}
template<typename GroupT>
void test_output()
{
GroupT g = GroupT::zero();
for (size_t i = 0; i < 1000; ++i)
{
std::stringstream ss;
ss << g;
GroupT gg;
ss >> gg;
assert(g == gg);
/* use a random point in next iteration */
g = GroupT::random_element();
}
}
int main(void)
{
/*
edwards_pp::init_public_params();
test_group<G1<edwards_pp> >();
test_output<G1<edwards_pp> >();
test_group<G2<edwards_pp> >();
test_output<G2<edwards_pp> >();
test_mul_by_q<G2<edwards_pp> >();
mnt4_pp::init_public_params();
test_group<G1<mnt4_pp> >();
test_output<G1<mnt4_pp> >();
test_group<G2<mnt4_pp> >();
test_output<G2<mnt4_pp> >();
test_mul_by_q<G2<mnt4_pp> >();
mnt6_pp::init_public_params();
test_group<G1<mnt6_pp> >();
test_output<G1<mnt6_pp> >();
test_group<G2<mnt6_pp> >();
test_output<G2<mnt6_pp> >();
test_mul_by_q<G2<mnt6_pp> >();
*/
alt_bn128_pp::init_public_params();
test_group<G1<alt_bn128_pp> >();
test_output<G1<alt_bn128_pp> >();
test_group<G2<alt_bn128_pp> >();
test_output<G2<alt_bn128_pp> >();
test_mul_by_q<G2<alt_bn128_pp> >();
#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled
bn128_pp::init_public_params();
test_group<G1<bn128_pp> >();
test_output<G1<bn128_pp> >();
test_group<G2<bn128_pp> >();
test_output<G2<bn128_pp> >();
#endif
}

45
src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.hpp

@ -1,45 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for the "basic radix-2" evaluation domain.
Roughly, the domain has size m = 2^k and consists of the m-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 BASIC_RADIX2_DOMAIN_HPP_
#define BASIC_RADIX2_DOMAIN_HPP_
#include "algebra/evaluation_domain/evaluation_domain.hpp"
namespace libsnark {
template<typename FieldT>
class basic_radix2_domain : public evaluation_domain<FieldT> {
public:
FieldT omega;
basic_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/basic_radix2_domain.tcc"
#endif // BASIC_RADIX2_DOMAIN_HPP_

113
src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.tcc

@ -1,113 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for the "basic radix-2" evaluation domain.
See basic_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 BASIC_RADIX2_DOMAIN_TCC_
#define BASIC_RADIX2_DOMAIN_TCC_
#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp"
#include "common/assert_except.hpp"
namespace libsnark {
template<typename FieldT>
basic_radix2_domain<FieldT>::basic_radix2_domain(const size_t m) : evaluation_domain<FieldT>(m)
{
assert_except(m > 1);
const size_t logm = log2(m);
assert_except(logm <= (FieldT::s));
omega = get_root_of_unity<FieldT>(m);
}
template<typename FieldT>
void basic_radix2_domain<FieldT>::FFT(std::vector<FieldT> &a)
{
enter_block("Execute FFT");
assert_except(a.size() == this->m);
_basic_radix2_FFT(a, omega);
leave_block("Execute FFT");
}
template<typename FieldT>
void basic_radix2_domain<FieldT>::iFFT(std::vector<FieldT> &a)
{
enter_block("Execute inverse FFT");
assert_except(a.size() == this->m);
_basic_radix2_FFT(a, omega.inverse());
const FieldT sconst = FieldT(a.size()).inverse();
for (size_t i = 0; i < a.size(); ++i)
{
a[i] *= sconst;
}
leave_block("Execute inverse FFT");
}
template<typename FieldT>
void basic_radix2_domain<FieldT>::cosetFFT(std::vector<FieldT> &a, const FieldT &g)
{
enter_block("Execute coset FFT");
_multiply_by_coset(a, g);
FFT(a);
leave_block("Execute coset FFT");
}
template<typename FieldT>
void basic_radix2_domain<FieldT>::icosetFFT(std::vector<FieldT> &a, const FieldT &g)
{
enter_block("Execute inverse coset IFFT");
iFFT(a);
_multiply_by_coset(a, g.inverse());
leave_block("Execute inverse coset IFFT");
}
template<typename FieldT>
std::vector<FieldT> basic_radix2_domain<FieldT>::lagrange_coeffs(const FieldT &t)
{
return _basic_radix2_lagrange_coeffs(this->m, t);
}
template<typename FieldT>
FieldT basic_radix2_domain<FieldT>::get_element(const size_t idx)
{
return omega^idx;
}
template<typename FieldT>
FieldT basic_radix2_domain<FieldT>::compute_Z(const FieldT &t)
{
return (t^this->m) - FieldT::one();
}
template<typename FieldT>
void basic_radix2_domain<FieldT>::add_poly_Z(const FieldT &coeff, std::vector<FieldT> &H)
{
assert_except(H.size() == this->m+1);
H[this->m] += coeff;
H[0] -= coeff;
}
template<typename FieldT>
void basic_radix2_domain<FieldT>::divide_by_Z_on_coset(std::vector<FieldT> &P)
{
const FieldT coset = FieldT::multiplicative_generator;
const FieldT Z_inverse_at_coset = this->compute_Z(coset).inverse();
for (size_t i = 0; i < this->m; ++i)
{
P[i] *= Z_inverse_at_coset;
}
}
} // libsnark
#endif // BASIC_RADIX2_DOMAIN_TCC_

48
src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp

@ -1,48 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for auxiliary functions for the "basic radix-2" evaluation domain.
These functions compute the radix-2 FFT (in single- or multi-thread mode) and,
also compute Lagrange coefficients.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef BASIC_RADIX2_DOMAIN_AUX_HPP_
#define BASIC_RADIX2_DOMAIN_AUX_HPP_
namespace libsnark {
/**
* Compute the radix-2 FFT of the vector a over the set S={omega^{0},...,omega^{m-1}}.
*/
template<typename FieldT>
void _basic_radix2_FFT(std::vector<FieldT> &a, const FieldT &omega);
/**
* A multi-thread version of _basic_radix2_FFT.
*/
template<typename FieldT>
void _parallel_basic_radix2_FFT(std::vector<FieldT> &a, const FieldT &omega);
/**
* Translate the vector a to a coset defined by g.
*/
template<typename FieldT>
void _multiply_by_coset(std::vector<FieldT> &a, const FieldT &g);
/**
* Compute the m Lagrange coefficients, relative to the set S={omega^{0},...,omega^{m-1}}, at the field element t.
*/
template<typename FieldT>
std::vector<FieldT> _basic_radix2_lagrange_coeffs(const size_t m, const FieldT &t);
} // libsnark
#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc"
#endif // BASIC_RADIX2_DOMAIN_AUX_HPP_

243
src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc

@ -1,243 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for auxiliary functions for the "basic radix-2" evaluation domain.
See basic_radix2_domain_aux.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef BASIC_RADIX2_DOMAIN_AUX_TCC_
#define BASIC_RADIX2_DOMAIN_AUX_TCC_
#include <cassert>
#ifdef MULTICORE
#include <omp.h>
#endif
#include "algebra/fields/field_utils.hpp"
#include "common/profiling.hpp"
#include "common/utils.hpp"
#include "common/assert_except.hpp"
namespace libsnark {
#ifdef MULTICORE
#define _basic_radix2_FFT _basic_parallel_radix2_FFT
#else
#define _basic_radix2_FFT _basic_serial_radix2_FFT
#endif
/*
Below we make use of pseudocode from [CLRS 2n Ed, pp. 864].
Also, note that it's the caller's responsibility to multiply by 1/N.
*/
template<typename FieldT>
void _basic_serial_radix2_FFT(std::vector<FieldT> &a, const FieldT &omega)
{
const size_t n = a.size(), logn = log2(n);
assert_except(n == (1u << logn));
/* swapping in place (from Storer's book) */
for (size_t k = 0; k < n; ++k)
{
const size_t rk = bitreverse(k, logn);
if (k < rk)
std::swap(a[k], a[rk]);
}
size_t m = 1; // invariant: m = 2^{s-1}
for (size_t s = 1; s <= logn; ++s)
{
// w_m is 2^s-th root of unity now
const FieldT w_m = omega^(n/(2*m));
asm volatile ("/* pre-inner */");
for (size_t k = 0; k < n; k += 2*m)
{
FieldT w = FieldT::one();
for (size_t j = 0; j < m; ++j)
{
const FieldT t = w * a[k+j+m];
a[k+j+m] = a[k+j] - t;
a[k+j] += t;
w *= w_m;
}
}
asm volatile ("/* post-inner */");
m *= 2;
}
}
template<typename FieldT>
void _basic_parallel_radix2_FFT_inner(std::vector<FieldT> &a, const FieldT &omega, const size_t log_cpus)
{
const size_t num_cpus = UINT64_C(1)<<log_cpus;
const size_t m = a.size();
const size_t log_m = log2(m);
assert(m == UINT64_C(1)<<log_m);
if (log_m < log_cpus)
{
_basic_serial_radix2_FFT(a, omega);
return;
}
enter_block("Shuffle inputs");
std::vector<std::vector<FieldT> > tmp(num_cpus);
for (size_t j = 0; j < num_cpus; ++j)
{
tmp[j].resize(UINT64_C(1)<<(log_m-log_cpus), FieldT::zero());
}
#ifdef MULTICORE
#pragma omp parallel for
#endif
for (size_t j = 0; j < num_cpus; ++j)
{
const FieldT omega_j = omega^j;
const FieldT omega_step = omega^(j<<(log_m - log_cpus));
FieldT elt = FieldT::one();
for (size_t i = 0; i < UINT64_C(1)<<(log_m - log_cpus); ++i)
{
for (size_t s = 0; s < num_cpus; ++s)
{
// invariant: elt is omega^(j*idx)
const size_t idx = (i + (s<<(log_m - log_cpus))) % (1u << log_m);
tmp[j][i] += a[idx] * elt;
elt *= omega_step;
}
elt *= omega_j;
}
}
leave_block("Shuffle inputs");
enter_block("Execute sub-FFTs");
const FieldT omega_num_cpus = omega^num_cpus;
#ifdef MULTICORE
#pragma omp parallel for
#endif
for (size_t j = 0; j < num_cpus; ++j)
{
_basic_serial_radix2_FFT(tmp[j], omega_num_cpus);
}
leave_block("Execute sub-FFTs");
enter_block("Re-shuffle outputs");
#ifdef MULTICORE
#pragma omp parallel for
#endif
for (size_t i = 0; i < num_cpus; ++i)
{
for (size_t j = 0; j < UINT64_C(1)<<(log_m - log_cpus); ++j)
{
// now: i = idx >> (log_m - log_cpus) and j = idx % (1u << (log_m - log_cpus)), for idx = ((i<<(log_m-log_cpus))+j) % (1u << log_m)
a[(j<<log_cpus) + i] = tmp[i][j];
}
}
leave_block("Re-shuffle outputs");
}
template<typename FieldT>
void _basic_parallel_radix2_FFT(std::vector<FieldT> &a, const FieldT &omega)
{
#ifdef MULTICORE
const size_t num_cpus = omp_get_max_threads();
#else
const size_t num_cpus = 1;
#endif
const size_t log_cpus = ((num_cpus & (num_cpus - 1)) == 0 ? log2(num_cpus) : log2(num_cpus) - 1);
#ifdef DEBUG
print_indent(); printf("* Invoking parallel FFT on 2^%zu CPUs (omp_get_max_threads = %zu)\n", log_cpus, num_cpus);
#endif
if (log_cpus == 0)
{
_basic_serial_radix2_FFT(a, omega);
}
else
{
_basic_parallel_radix2_FFT_inner(a, omega, log_cpus);
}
}
template<typename FieldT>
void _multiply_by_coset(std::vector<FieldT> &a, const FieldT &g)
{
//enter_block("Multiply by coset");
FieldT u = g;
for (size_t i = 1; i < a.size(); ++i)
{
a[i] *= u;
u *= g;
}
//leave_block("Multiply by coset");
}
template<typename FieldT>
std::vector<FieldT> _basic_radix2_lagrange_coeffs(const size_t m, const FieldT &t)
{
if (m == 1)
{
return std::vector<FieldT>(1, FieldT::one());
}
assert_except(m == (1u << log2(m)));
const FieldT omega = get_root_of_unity<FieldT>(m);
std::vector<FieldT> u(m, FieldT::zero());
/*
If t equals one of the roots of unity in S={omega^{0},...,omega^{m-1}}
then output 1 at the right place, and 0 elsewhere
*/
if ((t^m) == (FieldT::one()))
{
FieldT omega_i = FieldT::one();
for (size_t i = 0; i < m; ++i)
{
if (omega_i == t) // i.e., t equals omega^i
{
u[i] = FieldT::one();
return u;
}
omega_i *= omega;
}
}
/*
Otherwise, if t does not equal any of the roots of unity in S,
then compute each L_{i,S}(t) as Z_{S}(t) * v_i / (t-\omega^i)
where:
- Z_{S}(t) = \prod_{j} (t-\omega^j) = (t^m-1), and
- v_{i} = 1 / \prod_{j \neq i} (\omega^i-\omega^j).
Below we use the fact that v_{0} = 1/m and v_{i+1} = \omega * v_{i}.
*/
const FieldT Z = (t^m)-FieldT::one();
FieldT l = Z * FieldT(m).inverse();
FieldT r = FieldT::one();
for (size_t i = 0; i < m; ++i)
{
u[i] = l * (t - r).inverse();
l *= omega;
r *= omega;
}
return u;
}
} // libsnark
#endif // BASIC_RADIX2_DOMAIN_AUX_TCC_

125
src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.hpp

@ -1,125 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for evaluation domains.
Roughly, given a desired size m for the domain, the constructor selects
a choice of domain S with size ~m that has been selected so to optimize
- computations of Lagrange polynomials, and
- FFT/iFFT computations.
An evaluation domain also provides other other functions, e.g., accessing
individual elements in S or evaluating its vanishing polynomial.
The descriptions below make use of the definition of a *Lagrange polynomial*,
which we recall. Given a field F, a subset S=(a_i)_i of F, and an index idx
in {0,...,|S-1|}, the idx-th Lagrange polynomial (wrt to subset S) is defined to be
\f[ L_{idx,S}(z) := prod_{k \neq idx} (z - a_k) / prod_{k \neq idx} (a_{idx} - a_k) \f]
Note that, by construction:
\f[ \forall j \neq idx: L_{idx,S}(a_{idx}) = 1 \text{ and } L_{idx,S}(a_j) = 0 \f]
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef EVALUATION_DOMAIN_HPP_
#define EVALUATION_DOMAIN_HPP_
#include <memory>
namespace libsnark {
/**
* An evaluation domain.
*/
template<typename FieldT>
class evaluation_domain {
public:
const size_t m;
/**
* Construct an evaluation domain S of size m, if possible.
*
* (See the function get_evaluation_domain below.)
*/
evaluation_domain(const size_t m) : m(m) {};
/**
* Get the idx-th element in S.
*/
virtual FieldT get_element(const size_t idx) = 0;
/**
* Compute the FFT, over the domain S, of the vector a.
*/
virtual void FFT(std::vector<FieldT> &a) = 0;
/**
* Compute the inverse FFT, over the domain S, of the vector a.
*/
virtual void iFFT(std::vector<FieldT> &a) = 0;
/**
* Compute the FFT, over the domain g*S, of the vector a.
*/
virtual void cosetFFT(std::vector<FieldT> &a, const FieldT &g) = 0;
/**
* Compute the inverse FFT, over the domain g*S, of the vector a.
*/
virtual void icosetFFT(std::vector<FieldT> &a, const FieldT &g) = 0;
/**
* Evaluate all Lagrange polynomials.
*
* The inputs are:
* - an integer m
* - an element t
* The output is a vector (b_{0},...,b_{m-1})
* where b_{i} is the evaluation of L_{i,S}(z) at z = t.
*/
virtual std::vector<FieldT> lagrange_coeffs(const FieldT &t) = 0;
/**
* Evaluate the vanishing polynomial of S at the field element t.
*/
virtual FieldT compute_Z(const FieldT &t) = 0;
/**
* Add the coefficients of the vanishing polynomial of S to the coefficients of the polynomial H.
*/
virtual void add_poly_Z(const FieldT &coeff, std::vector<FieldT> &H) = 0;
/**
* Multiply by the evaluation, on a coset of S, of the inverse of the vanishing polynomial of S.
*/
virtual void divide_by_Z_on_coset(std::vector<FieldT> &P) = 0;
};
/**
* Return an evaluation domain object in which the domain S has size |S| >= min_size.
* The function chooses from different supported domains, depending on min_size.
*/
template<typename FieldT>
std::shared_ptr<evaluation_domain<FieldT> > get_evaluation_domain(const size_t min_size);
/**
* Naive evaluation of a *single* Lagrange polynomial, used for testing purposes.
*
* The inputs are:
* - an integer m
* - a domain S = (a_{0},...,a_{m-1}) of size m
* - a field element element t
* - an index idx in {0,...,m-1}
* The output is the polynomial L_{idx,S}(z) evaluated at z = t.
*/
template<typename FieldT>
FieldT lagrange_eval(const size_t m, const std::vector<FieldT> &domain, const FieldT &t, const size_t idx);
} // libsnark
#include "algebra/evaluation_domain/evaluation_domain.tcc"
#endif // EVALUATION_DOMAIN_HPP_

118
src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.tcc

@ -1,118 +0,0 @@
/** @file
*****************************************************************************
Imeplementation of interfaces for evaluation domains.
See evaluation_domain.hpp .
We currently implement, and select among, three types of domains:
- "basic radix-2": the domain has size m = 2^k and consists of the m-th roots of unity
- "extended radix-2": the domain has size m = 2^{k+1} and consists of "the m-th roots of unity" union "a coset"
- "step radix-2": 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 EVALUATION_DOMAIN_TCC_
#define EVALUATION_DOMAIN_TCC_
#include <cassert>
#include "algebra/fields/field_utils.hpp"
#include "algebra/evaluation_domain/domains/basic_radix2_domain.hpp"
#include "common/assert_except.hpp"
namespace libsnark {
template<typename FieldT>
std::shared_ptr<evaluation_domain<FieldT> > get_evaluation_domain(const size_t min_size)
{
assert_except(min_size > 1);
const size_t log_min_size = log2(min_size);
assert_except(log_min_size <= (FieldT::s+1));
std::shared_ptr<evaluation_domain<FieldT> > result;
if (min_size == (1u << log_min_size))
{
if (log_min_size == FieldT::s+1)
{
if (!inhibit_profiling_info)
{
print_indent(); printf("* Selected domain: extended_radix2\n");
}
assert_except(0);
}
else
{
if (!inhibit_profiling_info)
{
print_indent(); printf("* Selected domain: basic_radix2\n");
}
result.reset(new basic_radix2_domain<FieldT>(min_size));
}
}
else
{
const size_t big = UINT64_C(1)<<(log2(min_size)-1);
const size_t small = min_size - big;
const size_t rounded_small = (UINT64_C(1)<<log2(small));
if (big == rounded_small)
{
if (log2(big + rounded_small) < FieldT::s+1)
{
if (!inhibit_profiling_info)
{
print_indent(); printf("* Selected domain: basic_radix2\n");
}
result.reset(new basic_radix2_domain<FieldT>(big + rounded_small));
}
else
{
if (!inhibit_profiling_info)
{
print_indent(); printf("* Selected domain: extended_radix2\n");
}
assert_except(0);
}
}
else
{
if (!inhibit_profiling_info)
{
print_indent(); printf("* Selected domain: step_radix2\n");
}
assert_except(0);
}
}
return result;
}
template<typename FieldT>
FieldT lagrange_eval(const size_t m, const std::vector<FieldT> &domain, const FieldT &t, const size_t idx)
{
assert_except(m == domain.size());
assert_except(idx < m);
FieldT num = FieldT::one();
FieldT denom = FieldT::one();
for (size_t k = 0; k < m; ++k)
{
if (k == idx)
{
continue;
}
num *= t - domain[k];
denom *= domain[idx] - domain[k];
}
return num * denom.inverse();
}
} // libsnark
#endif // EVALUATION_DOMAIN_TCC_

31
src/snark/libsnark/algebra/exponentiation/exponentiation.hpp

@ -1,31 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for (square-and-multiply) exponentiation.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef EXPONENTIATION_HPP_
#define EXPONENTIATION_HPP_
#include <cstdint>
#include "algebra/fields/bigint.hpp"
namespace libsnark {
template<typename FieldT, mp_size_t m>
FieldT power(const FieldT &base, const bigint<m> &exponent);
template<typename FieldT>
FieldT power(const FieldT &base, const uint64_t exponent);
} // libsnark
#include "algebra/exponentiation/exponentiation.tcc"
#endif // EXPONENTIATION_HPP_

53
src/snark/libsnark/algebra/exponentiation/exponentiation.tcc

@ -1,53 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for (square-and-multiply) exponentiation.
See exponentiation.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef EXPONENTIATION_TCC_
#define EXPONENTIATION_TCC_
#include "common/utils.hpp"
namespace libsnark {
template<typename FieldT, mp_size_t m>
FieldT power(const FieldT &base, const bigint<m> &exponent)
{
FieldT result = FieldT::one();
bool found_one = false;
for (int64_t i = exponent.max_bits() - 1; i >= 0; --i)
{
if (found_one)
{
result = result * result;
}
if (exponent.test_bit(i))
{
found_one = true;
result = result * base;
}
}
return result;
}
template<typename FieldT>
FieldT power(const FieldT &base, const uint64_t exponent)
{
return power<FieldT>(base, bigint<1>(exponent));
}
} // libsnark
#endif // EXPONENTIATION_TCC_

70
src/snark/libsnark/algebra/fields/bigint.hpp

@ -1,70 +0,0 @@
/** @file
*****************************************************************************
Declaration of bigint wrapper class around GMP's MPZ long integers.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef BIGINT_HPP_
#define BIGINT_HPP_
#include <cstddef>
#include <iostream>
#include <gmp.h>
#include "common/serialization.hpp"
namespace libsnark {
template<mp_size_t n> class bigint;
template<mp_size_t n> std::ostream& operator<<(std::ostream &, const bigint<n>&);
template<mp_size_t n> std::istream& operator>>(std::istream &, bigint<n>&);
/**
* Wrapper class around GMP's MPZ long integers. It supports arithmetic operations,
* serialization and randomization. Serialization is fragile, see common/serialization.hpp.
*/
template<mp_size_t n>
class bigint {
public:
static const mp_size_t N = n;
mp_limb_t data[n] = {0};
bigint() = default;
bigint(const uint64_t x); /// Initalize from a small integer
bigint(const char* s); /// Initialize from a string containing an integer in decimal notation
bigint(const mpz_t r); /// Initialize from MPZ element
void print() const;
void print_hex() const;
bool operator==(const bigint<n>& other) const;
bool operator!=(const bigint<n>& other) const;
void clear();
bool is_zero() const;
size_t max_bits() const { return n * GMP_NUMB_BITS; }
size_t num_bits() const;
uint64_t as_uint64() const; /* return the last limb of the integer */
void to_mpz(mpz_t r) const;
bool test_bit(const std::size_t bitno) const;
template<mp_size_t m> inline void operator+=(const bigint<m>& other);
template<mp_size_t m> inline bigint<n+m> operator*(const bigint<m>& other) const;
template<mp_size_t d> static inline void div_qr(bigint<n-d+1>& quotient, bigint<d>& remainder,
const bigint<n>& dividend, const bigint<d>& divisor);
template<mp_size_t m> inline bigint<m> shorten(const bigint<m>& q, const char *msg) const;
inline void limit(const bigint<n>& q, const char *msg) const;
bool operator>(const bigint<n>& other) const;
bigint& randomize();
friend std::ostream& operator<< <n>(std::ostream &out, const bigint<n> &b);
friend std::istream& operator>> <n>(std::istream &in, bigint<n> &b);
};
} // libsnark
#include "algebra/fields/bigint.tcc"
#endif

280
src/snark/libsnark/algebra/fields/bigint.tcc

@ -1,280 +0,0 @@
/** @file
*****************************************************************************
Implementation of bigint wrapper class around GMP's MPZ long integers.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef BIGINT_TCC_
#define BIGINT_TCC_
#include <cassert>
#include <climits>
#include <cstring>
#include "sodium.h"
#include "common/assert_except.hpp"
namespace libsnark {
template<mp_size_t n>
bigint<n>::bigint(const uint64_t x) /// Initialize from a small integer
{
static_assert(UINT64_MAX <= GMP_NUMB_MAX, "uint64_t does not fit in a GMP limb");
this->data[0] = x;
}
template<mp_size_t n>
bigint<n>::bigint(const char* s) /// Initialize from a string containing an integer in decimal notation
{
size_t l = strlen(s);
unsigned char* s_copy = new unsigned char[l];
for (size_t i = 0; i < l; ++i)
{
assert_except(s[i] >= '0' && s[i] <= '9');
s_copy[i] = s[i] - '0';
}
mp_size_t limbs_written = mpn_set_str(this->data, s_copy, l, 10);
assert_except(limbs_written <= n);
delete[] s_copy;
}
template<mp_size_t n>
bigint<n>::bigint(const mpz_t r) /// Initialize from MPZ element
{
mpz_t k;
mpz_init_set(k, r);
for (size_t i = 0; i < n; ++i)
{
data[i] = mpz_get_ui(k);
mpz_fdiv_q_2exp(k, k, GMP_NUMB_BITS);
}
assert_except(mpz_sgn(k) == 0);
mpz_clear(k);
}
template<mp_size_t n>
void bigint<n>::print() const
{
gmp_printf("%Nd\n", this->data, n);
}
template<mp_size_t n>
void bigint<n>::print_hex() const
{
gmp_printf("%Nx\n", this->data, n);
}
template<mp_size_t n>
bool bigint<n>::operator==(const bigint<n>& other) const
{
return (mpn_cmp(this->data, other.data, n) == 0);
}
template<mp_size_t n>
bool bigint<n>::operator!=(const bigint<n>& other) const
{
return !(operator==(other));
}
template<mp_size_t n>
void bigint<n>::clear()
{
mpn_zero(this->data, n);
}
template<mp_size_t n>
bool bigint<n>::is_zero() const
{
for (mp_size_t i = 0; i < n; ++i)
{
if (this->data[i])
{
return false;
}
}
return true;
}
template<mp_size_t n>
size_t bigint<n>::num_bits() const
{
/*
for (int64_t i = max_bits(); i >= 0; --i)
{
if (this->test_bit(i))
{
return i+1;
}
}
return 0;
*/
for (int64_t i = n-1; i >= 0; --i)
{
mp_limb_t x = this->data[i];
if (x == 0)
{
continue;
}
else
{
static_assert(GMP_NUMB_MAX <= ULLONG_MAX, "coercing limb to unsigned long long might truncate");
return ((i+1) * GMP_NUMB_BITS) - __builtin_clzll(x);
}
}
return 0;
}
template<mp_size_t n>
uint64_t bigint<n>::as_uint64() const
{
return this->data[0];
}
template<mp_size_t n>
void bigint<n>::to_mpz(mpz_t r) const
{
mpz_set_ui(r, 0);
for (int i = n-1; i >= 0; --i)
{
mpz_mul_2exp(r, r, GMP_NUMB_BITS);
mpz_add_ui(r, r, this->data[i]);
}
}
template<mp_size_t n>
bool bigint<n>::test_bit(const std::size_t bitno) const
{
if (bitno >= n * GMP_NUMB_BITS)
{
return false;
}
else
{
const std::size_t part = bitno/GMP_NUMB_BITS;
const std::size_t bit = bitno - (GMP_NUMB_BITS*part);
const mp_limb_t one = 1;
return (this->data[part] & (one<<bit));
}
}
template<mp_size_t n> template<mp_size_t m>
inline void bigint<n>::operator+=(const bigint<m>& other)
{
static_assert(n >= m, "first arg must not be smaller than second arg for bigint in-place add");
mpn_add(data, data, n, other.data, m);
}
template<mp_size_t n> template<mp_size_t m>
inline bigint<n+m> bigint<n>::operator*(const bigint<m>& other) const
{
static_assert(n >= m, "first arg must not be smaller than second arg for bigint mul");
bigint<n+m> res;
mpn_mul(res.data, data, n, other.data, m);
return res;
}
template<mp_size_t n> template<mp_size_t d>
inline void bigint<n>::div_qr(bigint<n-d+1>& quotient, bigint<d>& remainder,
const bigint<n>& dividend, const bigint<d>& divisor)
{
static_assert(n >= d, "dividend must not be smaller than divisor for bigint::div_qr");
assert_except(divisor.data[d-1] != 0);
mpn_tdiv_qr(quotient.data, remainder.data, 0, dividend.data, n, divisor.data, d);
}
// Return a copy shortened to m limbs provided it is less than limit, throwing std::domain_error if not in range.
template<mp_size_t n> template<mp_size_t m>
inline bigint<m> bigint<n>::shorten(const bigint<m>& q, const char *msg) const
{
static_assert(m <= n, "number of limbs must not increase for bigint::shorten");
for (mp_size_t i = m; i < n; i++) { // high-order limbs
if (data[i] != 0) {
throw std::domain_error(msg);
}
}
bigint<m> res;
mpn_copyi(res.data, data, m);
res.limit(q, msg);
return res;
}
template<mp_size_t n>
inline void bigint<n>::limit(const bigint<n>& q, const char *msg) const
{
if (!(q > *this)) {
throw std::domain_error(msg);
}
}
template<mp_size_t n>
inline bool bigint<n>::operator>(const bigint<n>& other) const
{
return mpn_cmp(this->data, other.data, n) > 0;
}
template<mp_size_t n>
bigint<n>& bigint<n>::randomize()
{
assert_except(GMP_NUMB_BITS == sizeof(mp_limb_t) * 8);
randombytes_buf(this->data, sizeof(mp_limb_t) * n);
return (*this);
}
template<mp_size_t n>
std::ostream& operator<<(std::ostream &out, const bigint<n> &b)
{
#ifdef BINARY_OUTPUT
out.write((char*)b.data, sizeof(b.data[0]) * n);
#else
mpz_t t;
mpz_init(t);
b.to_mpz(t);
out << t;
mpz_clear(t);
#endif
return out;
}
template<mp_size_t n>
std::istream& operator>>(std::istream &in, bigint<n> &b)
{
#ifdef BINARY_OUTPUT
in.read((char*)b.data, sizeof(b.data[0]) * n);
#else
std::string s;
in >> s;
size_t l = s.size();
unsigned char* s_copy = new unsigned char[l];
for (size_t i = 0; i < l; ++i)
{
assert_except(s[i] >= '0' && s[i] <= '9');
s_copy[i] = s[i] - '0';
}
mp_size_t limbs_written = mpn_set_str(b.data, s_copy, l, 10);
assert_except(limbs_written <= n);
delete[] s_copy;
#endif
return in;
}
} // libsnark
#endif // BIGINT_TCC_

51
src/snark/libsnark/algebra/fields/field_utils.hpp

@ -1,51 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef FIELD_UTILS_HPP_
#define FIELD_UTILS_HPP_
#include <cstdint>
#include "common/utils.hpp"
#include "algebra/fields/bigint.hpp"
namespace libsnark {
// returns root of unity of order n (for n a power of 2), if one exists
template<typename FieldT>
FieldT get_root_of_unity(const uint64_t n);
template<typename FieldT>
std::vector<FieldT> pack_int_vector_into_field_element_vector(const std::vector<uint64_t> &v, const uint64_t w);
template<typename FieldT>
std::vector<FieldT> pack_bit_vector_into_field_element_vector(const bit_vector &v, const uint64_t chunk_bits);
template<typename FieldT>
std::vector<FieldT> pack_bit_vector_into_field_element_vector(const bit_vector &v);
template<typename FieldT>
std::vector<FieldT> convert_bit_vector_to_field_element_vector(const bit_vector &v);
template<typename FieldT>
bit_vector convert_field_element_vector_to_bit_vector(const std::vector<FieldT> &v);
template<typename FieldT>
bit_vector convert_field_element_to_bit_vector(const FieldT &el);
template<typename FieldT>
bit_vector convert_field_element_to_bit_vector(const FieldT &el, const uint64_t bitcount);
template<typename FieldT>
FieldT convert_bit_vector_to_field_element(const bit_vector &v);
template<typename FieldT>
void batch_invert(std::vector<FieldT> &vec);
} // libsnark
#include "algebra/fields/field_utils.tcc"
#endif // FIELD_UTILS_HPP_

184
src/snark/libsnark/algebra/fields/field_utils.tcc

@ -1,184 +0,0 @@
/** @file
*****************************************************************************
Implementation of misc. math and serialization utility functions
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef FIELD_UTILS_TCC_
#define FIELD_UTILS_TCC_
#include "common/utils.hpp"
#include "common/assert_except.hpp"
namespace libsnark {
template<typename FieldT>
FieldT coset_shift()
{
return FieldT::multiplicative_generator.squared();
}
template<typename FieldT>
FieldT get_root_of_unity(const uint64_t n)
{
const uint64_t logn = log2(n);
assert_except(n == (1u << logn));
assert_except(logn <= FieldT::s);
FieldT omega = FieldT::root_of_unity;
for (uint64_t i = FieldT::s; i > logn; --i)
{
omega *= omega;
}
return omega;
}
template<typename FieldT>
std::vector<FieldT> pack_int_vector_into_field_element_vector(const std::vector<uint64_t> &v, const uint64_t w)
{
const uint64_t chunk_bits = FieldT::capacity();
const uint64_t repacked_size = div_ceil(v.size() * w, chunk_bits);
std::vector<FieldT> result(repacked_size);
for (uint64_t i = 0; i < repacked_size; ++i)
{
bigint<FieldT::num_limbs> b;
for (uint64_t j = 0; j < chunk_bits; ++j)
{
const uint64_t word_index = (i * chunk_bits + j) / w;
const uint64_t pos_in_word = (i * chunk_bits + j) % w;
const uint64_t word_or_0 = (word_index < v.size() ? v[word_index] : 0);
const uint64_t bit = (word_or_0 >> pos_in_word) & 1;
b.data[j / GMP_NUMB_BITS] |= bit << (j % GMP_NUMB_BITS);
}
result[i] = FieldT(b);
}
return result;
}
template<typename FieldT>
std::vector<FieldT> pack_bit_vector_into_field_element_vector(const bit_vector &v, const uint64_t chunk_bits)
{
assert_except(chunk_bits <= FieldT::capacity());
const uint64_t repacked_size = div_ceil(v.size(), chunk_bits);
std::vector<FieldT> result(repacked_size);
for (size_t i = 0; i < repacked_size; ++i)
{
bigint<FieldT::num_limbs> b;
for (size_t j = 0; j < chunk_bits; ++j)
{
b.data[j / GMP_NUMB_BITS] |= ((i * chunk_bits + j) < v.size() && v[i * chunk_bits + j] ? 1ll : 0ll) << (j % GMP_NUMB_BITS);
}
result[i] = FieldT(b);
}
return result;
}
template<typename FieldT>
std::vector<FieldT> pack_bit_vector_into_field_element_vector(const bit_vector &v)
{
return pack_bit_vector_into_field_element_vector<FieldT>(v, FieldT::capacity());
}
template<typename FieldT>
std::vector<FieldT> convert_bit_vector_to_field_element_vector(const bit_vector &v)
{
std::vector<FieldT> result;
result.reserve(v.size());
for (const bool b : v)
{
result.emplace_back(b ? FieldT::one() : FieldT::zero());
}
return result;
}
template<typename FieldT>
bit_vector convert_field_element_vector_to_bit_vector(const std::vector<FieldT> &v)
{
bit_vector result;
for (const FieldT &el : v)
{
const bit_vector el_bits = convert_field_element_to_bit_vector<FieldT>(el);
result.insert(result.end(), el_bits.begin(), el_bits.end());
}
return result;
}
template<typename FieldT>
bit_vector convert_field_element_to_bit_vector(const FieldT &el)
{
bit_vector result;
bigint<FieldT::num_limbs> b = el.as_bigint();
for (size_t i = 0; i < FieldT::size_in_bits(); ++i)
{
result.push_back(b.test_bit(i));
}
return result;
}
template<typename FieldT>
bit_vector convert_field_element_to_bit_vector(const FieldT &el, const uint64_t bitcount)
{
bit_vector result = convert_field_element_to_bit_vector(el);
result.resize(bitcount);
return result;
}
template<typename FieldT>
FieldT convert_bit_vector_to_field_element(const bit_vector &v)
{
assert_except(v.size() <= FieldT::size_in_bits());
FieldT res = FieldT::zero();
FieldT c = FieldT::one();
for (bool b : v)
{
res += b ? c : FieldT::zero();
c += c;
}
return res;
}
template<typename FieldT>
void batch_invert(std::vector<FieldT> &vec)
{
std::vector<FieldT> prod;
prod.reserve(vec.size());
FieldT acc = FieldT::one();
for (auto el : vec)
{
assert_except(!el.is_zero());
prod.emplace_back(acc);
acc = acc * el;
}
FieldT acc_inverse = acc.inverse();
for (int64_t i = vec.size()-1; i >= 0; --i)
{
const FieldT old_el = vec[i];
vec[i] = acc_inverse * prod[i];
acc_inverse = acc_inverse * old_el;
}
}
} // libsnark
#endif // FIELD_UTILS_TCC_

182
src/snark/libsnark/algebra/fields/fp.hpp

@ -1,182 +0,0 @@
/** @file
*****************************************************************************
Declaration of arithmetic in the finite field F[p], for prime p of fixed length.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef FP_HPP_
#define FP_HPP_
#include "algebra/fields/bigint.hpp"
#include "algebra/exponentiation/exponentiation.hpp"
namespace libsnark {
template<mp_size_t n, const bigint<n>& modulus>
class Fp_model;
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream &, const Fp_model<n, modulus>&);
template<mp_size_t n, const bigint<n>& modulus>
std::istream& operator>>(std::istream &, Fp_model<n, modulus> &);
/**
* Arithmetic in the finite field F[p], for prime p of fixed length.
*
* This class implements Fp-arithmetic, for a large prime p, using a fixed number
* of words. It is optimized for tight memory consumption, so the modulus p is
* passed as a template parameter, to avoid per-element overheads.
*
* The implementation is mostly a wrapper around GMP's MPN (constant-size integers).
* But for the integer sizes of interest for libsnark (3 to 5 limbs of 64 bits each),
* we implement performance-critical routines, like addition and multiplication,
* using hand-optimzied assembly code.
*/
template<mp_size_t n, const bigint<n>& modulus>
class Fp_model {
public:
bigint<n> mont_repr;
public:
static const mp_size_t num_limbs = n;
static const constexpr bigint<n>& mod = modulus;
#ifdef PROFILE_OP_COUNTS
static int64_t add_cnt;
static int64_t sub_cnt;
static int64_t mul_cnt;
static int64_t sqr_cnt;
static int64_t inv_cnt;
#endif
static uint64_t num_bits;
static bigint<n> euler; // (modulus-1)/2
static uint64_t s; // modulus = 2^s * t + 1
static bigint<n> t; // with t odd
static bigint<n> t_minus_1_over_2; // (t-1)/2
static Fp_model<n, modulus> nqr; // a quadratic nonresidue
static Fp_model<n, modulus> nqr_to_t; // nqr^t
static Fp_model<n, modulus> multiplicative_generator; // generator of Fp^*
static Fp_model<n, modulus> root_of_unity; // generator^((modulus-1)/2^s)
static mp_limb_t inv; // modulus^(-1) mod W, where W = 2^(word size)
static bigint<n> Rsquared; // R^2, where R = W^k, where k = ??
static bigint<n> Rcubed; // R^3
static bool modulus_is_valid() { return modulus.data[n-1] != 0; } // mpn inverse assumes that highest limb is non-zero
Fp_model() {};
Fp_model(const bigint<n> &b);
Fp_model(const int64_t x, const bool is_unsigned=false);
void set_uint64(const uint64_t x);
void mul_reduce(const bigint<n> &other);
void clear();
/* Return the standard (not Montgomery) representation of the
Field element's requivalence class. I.e. Fp(2).as_bigint()
would return bigint(2) */
bigint<n> as_bigint() const;
/* Return the last limb of the standard representation of the
field element. E.g. on 64-bit architectures Fp(123).as_uint64()
and Fp(2^64+123).as_uint64() would both return 123. */
uint64_t as_uint64() const;
bool operator==(const Fp_model& other) const;
bool operator!=(const Fp_model& other) const;
bool is_zero() const;
void print() const;
Fp_model& operator+=(const Fp_model& other);
Fp_model& operator-=(const Fp_model& other);
Fp_model& operator*=(const Fp_model& other);
Fp_model& operator^=(const uint64_t pow);
template<mp_size_t m>
Fp_model& operator^=(const bigint<m> &pow);
Fp_model operator+(const Fp_model& other) const;
Fp_model operator-(const Fp_model& other) const;
Fp_model operator*(const Fp_model& other) const;
Fp_model operator-() const;
Fp_model squared() const;
Fp_model& invert();
Fp_model inverse() const;
Fp_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate)
Fp_model operator^(const uint64_t pow) const;
template<mp_size_t m>
Fp_model operator^(const bigint<m> &pow) const;
static uint64_t size_in_bits() { return num_bits; }
static uint64_t capacity() { return num_bits - 1; }
static bigint<n> field_char() { return modulus; }
static Fp_model<n, modulus> zero();
static Fp_model<n, modulus> one();
static Fp_model<n, modulus> random_element();
friend std::ostream& operator<< <n,modulus>(std::ostream &out, const Fp_model<n, modulus> &p);
friend std::istream& operator>> <n,modulus>(std::istream &in, Fp_model<n, modulus> &p);
};
#ifdef PROFILE_OP_COUNTS
template<mp_size_t n, const bigint<n>& modulus>
int64_t Fp_model<n, modulus>::add_cnt = 0;
template<mp_size_t n, const bigint<n>& modulus>
int64_t Fp_model<n, modulus>::sub_cnt = 0;
template<mp_size_t n, const bigint<n>& modulus>
int64_t Fp_model<n, modulus>::mul_cnt = 0;
template<mp_size_t n, const bigint<n>& modulus>
int64_t Fp_model<n, modulus>::sqr_cnt = 0;
template<mp_size_t n, const bigint<n>& modulus>
int64_t Fp_model<n, modulus>::inv_cnt = 0;
#endif
template<mp_size_t n, const bigint<n>& modulus>
uint64_t Fp_model<n, modulus>::num_bits;
template<mp_size_t n, const bigint<n>& modulus>
bigint<n> Fp_model<n, modulus>::euler;
template<mp_size_t n, const bigint<n>& modulus>
uint64_t Fp_model<n, modulus>::s;
template<mp_size_t n, const bigint<n>& modulus>
bigint<n> Fp_model<n, modulus>::t;
template<mp_size_t n, const bigint<n>& modulus>
bigint<n> Fp_model<n, modulus>::t_minus_1_over_2;
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n, modulus> Fp_model<n, modulus>::nqr;
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n, modulus> Fp_model<n, modulus>::nqr_to_t;
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n, modulus> Fp_model<n, modulus>::multiplicative_generator;
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n, modulus> Fp_model<n, modulus>::root_of_unity;
template<mp_size_t n, const bigint<n>& modulus>
mp_limb_t Fp_model<n, modulus>::inv;
template<mp_size_t n, const bigint<n>& modulus>
bigint<n> Fp_model<n, modulus>::Rsquared;
template<mp_size_t n, const bigint<n>& modulus>
bigint<n> Fp_model<n, modulus>::Rcubed;
} // libsnark
#include "algebra/fields/fp.tcc"
#endif // FP_HPP_

790
src/snark/libsnark/algebra/fields/fp.tcc

@ -1,790 +0,0 @@
/** @file
*****************************************************************************
Implementation of arithmetic in the finite field F[p], for prime p of fixed length.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef FP_TCC_
#define FP_TCC_
#include <cassert>
#include <cstdlib>
#include <cmath>
#include "algebra/fields/fp_aux.tcc"
#include "algebra/fields/field_utils.hpp"
#include "common/assert_except.hpp"
namespace libsnark {
template<mp_size_t n, const bigint<n>& modulus>
void Fp_model<n,modulus>::mul_reduce(const bigint<n> &other)
{
/* stupid pre-processor tricks; beware */
#if defined(__x86_64__) && defined(USE_ASM)
if (n == 3)
{ // Use asm-optimized Comba multiplication and reduction
mp_limb_t res[2*n];
mp_limb_t c0, c1, c2;
COMBA_3_BY_3_MUL(c0, c1, c2, res, this->mont_repr.data, other.data);
mp_limb_t k;
mp_limb_t tmp1, tmp2, tmp3;
REDUCE_6_LIMB_PRODUCT(k, tmp1, tmp2, tmp3, inv, res, modulus.data);
/* subtract t > mod */
__asm__
("/* check for overflow */ \n\t"
MONT_CMP(16)
MONT_CMP(8)
MONT_CMP(0)
"/* subtract mod if overflow */ \n\t"
"subtract%=: \n\t"
MONT_FIRSTSUB
MONT_NEXTSUB(8)
MONT_NEXTSUB(16)
"done%=: \n\t"
:
: [tmp] "r" (res+n), [M] "r" (modulus.data)
: "cc", "memory", "%rax");
mpn_copyi(this->mont_repr.data, res+n, n);
}
else if (n == 4)
{ // use asm-optimized "CIOS method"
mp_limb_t tmp[n+1];
mp_limb_t T0=0, T1=1, cy=2, u=3; // TODO: fix this
__asm__ (MONT_PRECOMPUTE
MONT_FIRSTITER(1)
MONT_FIRSTITER(2)
MONT_FIRSTITER(3)
MONT_FINALIZE(3)
MONT_ITERFIRST(1)
MONT_ITERITER(1, 1)
MONT_ITERITER(1, 2)
MONT_ITERITER(1, 3)
MONT_FINALIZE(3)
MONT_ITERFIRST(2)
MONT_ITERITER(2, 1)
MONT_ITERITER(2, 2)
MONT_ITERITER(2, 3)
MONT_FINALIZE(3)
MONT_ITERFIRST(3)
MONT_ITERITER(3, 1)
MONT_ITERITER(3, 2)
MONT_ITERITER(3, 3)
MONT_FINALIZE(3)
"/* check for overflow */ \n\t"
MONT_CMP(24)
MONT_CMP(16)
MONT_CMP(8)
MONT_CMP(0)
"/* subtract mod if overflow */ \n\t"
"subtract%=: \n\t"
MONT_FIRSTSUB
MONT_NEXTSUB(8)
MONT_NEXTSUB(16)
MONT_NEXTSUB(24)
"done%=: \n\t"
:
: [tmp] "r" (tmp), [A] "r" (this->mont_repr.data), [B] "r" (other.data), [inv] "r" (inv), [M] "r" (modulus.data),
[T0] "r" (T0), [T1] "r" (T1), [cy] "r" (cy), [u] "r" (u)
: "cc", "memory", "%rax", "%rdx"
);
mpn_copyi(this->mont_repr.data, tmp, n);
}
else if (n == 5)
{ // use asm-optimized "CIOS method"
mp_limb_t tmp[n+1];
mp_limb_t T0=0, T1=1, cy=2, u=3; // TODO: fix this
__asm__ (MONT_PRECOMPUTE
MONT_FIRSTITER(1)
MONT_FIRSTITER(2)
MONT_FIRSTITER(3)
MONT_FIRSTITER(4)
MONT_FINALIZE(4)
MONT_ITERFIRST(1)
MONT_ITERITER(1, 1)
MONT_ITERITER(1, 2)
MONT_ITERITER(1, 3)
MONT_ITERITER(1, 4)
MONT_FINALIZE(4)
MONT_ITERFIRST(2)
MONT_ITERITER(2, 1)
MONT_ITERITER(2, 2)
MONT_ITERITER(2, 3)
MONT_ITERITER(2, 4)
MONT_FINALIZE(4)
MONT_ITERFIRST(3)
MONT_ITERITER(3, 1)
MONT_ITERITER(3, 2)
MONT_ITERITER(3, 3)
MONT_ITERITER(3, 4)
MONT_FINALIZE(4)
MONT_ITERFIRST(4)
MONT_ITERITER(4, 1)
MONT_ITERITER(4, 2)
MONT_ITERITER(4, 3)
MONT_ITERITER(4, 4)
MONT_FINALIZE(4)
"/* check for overflow */ \n\t"
MONT_CMP(32)
MONT_CMP(24)
MONT_CMP(16)
MONT_CMP(8)
MONT_CMP(0)
"/* subtract mod if overflow */ \n\t"
"subtract%=: \n\t"
MONT_FIRSTSUB
MONT_NEXTSUB(8)
MONT_NEXTSUB(16)
MONT_NEXTSUB(24)
MONT_NEXTSUB(32)
"done%=: \n\t"
:
: [tmp] "r" (tmp), [A] "r" (this->mont_repr.data), [B] "r" (other.data), [inv] "r" (inv), [M] "r" (modulus.data),
[T0] "r" (T0), [T1] "r" (T1), [cy] "r" (cy), [u] "r" (u)
: "cc", "memory", "%rax", "%rdx"
);
mpn_copyi(this->mont_repr.data, tmp, n);
}
else
#endif
{
mp_limb_t res[2*n];
mpn_mul_n(res, this->mont_repr.data, other.data, n);
/*
The Montgomery reduction here is based on Algorithm 14.32 in
Handbook of Applied Cryptography
<http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
*/
for (size_t i = 0; i < n; ++i)
{
mp_limb_t k = inv * res[i];
/* calculate res = res + k * mod * b^i */
mp_limb_t carryout = mpn_addmul_1(res+i, modulus.data, n, k);
carryout = mpn_add_1(res+n+i, res+n+i, n-i, carryout);
assert_except(carryout == 0);
}
if (mpn_cmp(res+n, modulus.data, n) >= 0)
{
const mp_limb_t borrow = mpn_sub(res+n, res+n, n, modulus.data, n);
assert_except(borrow == 0);
}
mpn_copyi(this->mont_repr.data, res+n, n);
}
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus>::Fp_model(const bigint<n> &b)
{
mpn_copyi(this->mont_repr.data, Rsquared.data, n);
mul_reduce(b);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus>::Fp_model(const int64_t x, const bool is_unsigned)
{
if (is_unsigned || x >= 0)
{
this->mont_repr.data[0] = x;
}
else
{
const mp_limb_t borrow = mpn_sub_1(this->mont_repr.data, modulus.data, n, -x);
assert_except(borrow == 0);
}
mul_reduce(Rsquared);
}
template<mp_size_t n, const bigint<n>& modulus>
void Fp_model<n,modulus>::set_uint64(const uint64_t x)
{
this->mont_repr.clear();
this->mont_repr.data[0] = x;
mul_reduce(Rsquared);
}
template<mp_size_t n, const bigint<n>& modulus>
void Fp_model<n,modulus>::clear()
{
this->mont_repr.clear();
}
template<mp_size_t n, const bigint<n>& modulus>
bigint<n> Fp_model<n,modulus>::as_bigint() const
{
bigint<n> one;
one.clear();
one.data[0] = 1;
Fp_model<n, modulus> res(*this);
res.mul_reduce(one);
return (res.mont_repr);
}
template<mp_size_t n, const bigint<n>& modulus>
uint64_t Fp_model<n,modulus>::as_uint64() const
{
return this->as_bigint().as_uint64();
}
template<mp_size_t n, const bigint<n>& modulus>
bool Fp_model<n,modulus>::operator==(const Fp_model& other) const
{
return (this->mont_repr == other.mont_repr);
}
template<mp_size_t n, const bigint<n>& modulus>
bool Fp_model<n,modulus>::operator!=(const Fp_model& other) const
{
return (this->mont_repr != other.mont_repr);
}
template<mp_size_t n, const bigint<n>& modulus>
bool Fp_model<n,modulus>::is_zero() const
{
return (this->mont_repr.is_zero()); // zero maps to zero
}
template<mp_size_t n, const bigint<n>& modulus>
void Fp_model<n,modulus>::print() const
{
Fp_model<n,modulus> tmp;
tmp.mont_repr.data[0] = 1;
tmp.mul_reduce(this->mont_repr);
tmp.mont_repr.print();
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus> Fp_model<n,modulus>::zero()
{
Fp_model<n,modulus> res;
res.mont_repr.clear();
return res;
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus> Fp_model<n,modulus>::one()
{
Fp_model<n,modulus> res;
res.mont_repr.data[0] = 1;
res.mul_reduce(Rsquared);
return res;
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus>& Fp_model<n,modulus>::operator+=(const Fp_model<n,modulus>& other)
{
#ifdef PROFILE_OP_COUNTS
this->add_cnt++;
#endif
#if defined(__x86_64__) && defined(USE_ASM)
if (n == 3)
{
__asm__
("/* perform bignum addition */ \n\t"
ADD_FIRSTADD
ADD_NEXTADD(8)
ADD_NEXTADD(16)
"/* if overflow: subtract */ \n\t"
"/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t"
"jc subtract%= \n\t"
"/* check for overflow */ \n\t"
ADD_CMP(16)
ADD_CMP(8)
ADD_CMP(0)
"/* subtract mod if overflow */ \n\t"
"subtract%=: \n\t"
ADD_FIRSTSUB
ADD_NEXTSUB(8)
ADD_NEXTSUB(16)
"done%=: \n\t"
:
: [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data)
: "cc", "memory", "%rax");
}
else if (n == 4)
{
__asm__
("/* perform bignum addition */ \n\t"
ADD_FIRSTADD
ADD_NEXTADD(8)
ADD_NEXTADD(16)
ADD_NEXTADD(24)
"/* if overflow: subtract */ \n\t"
"/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t"
"jc subtract%= \n\t"
"/* check for overflow */ \n\t"
ADD_CMP(24)
ADD_CMP(16)
ADD_CMP(8)
ADD_CMP(0)
"/* subtract mod if overflow */ \n\t"
"subtract%=: \n\t"
ADD_FIRSTSUB
ADD_NEXTSUB(8)
ADD_NEXTSUB(16)
ADD_NEXTSUB(24)
"done%=: \n\t"
:
: [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data)
: "cc", "memory", "%rax");
}
else if (n == 5)
{
__asm__
("/* perform bignum addition */ \n\t"
ADD_FIRSTADD
ADD_NEXTADD(8)
ADD_NEXTADD(16)
ADD_NEXTADD(24)
ADD_NEXTADD(32)
"/* if overflow: subtract */ \n\t"
"/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t"
"jc subtract%= \n\t"
"/* check for overflow */ \n\t"
ADD_CMP(32)
ADD_CMP(24)
ADD_CMP(16)
ADD_CMP(8)
ADD_CMP(0)
"/* subtract mod if overflow */ \n\t"
"subtract%=: \n\t"
ADD_FIRSTSUB
ADD_NEXTSUB(8)
ADD_NEXTSUB(16)
ADD_NEXTSUB(24)
ADD_NEXTSUB(32)
"done%=: \n\t"
:
: [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data)
: "cc", "memory", "%rax");
}
else
#endif
{
mp_limb_t scratch[n+1];
const mp_limb_t carry = mpn_add_n(scratch, this->mont_repr.data, other.mont_repr.data, n);
scratch[n] = carry;
if (carry || mpn_cmp(scratch, modulus.data, n) >= 0)
{
const mp_limb_t borrow = mpn_sub(scratch, scratch, n+1, modulus.data, n);
assert_except(borrow == 0);
}
mpn_copyi(this->mont_repr.data, scratch, n);
}
return *this;
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus>& Fp_model<n,modulus>::operator-=(const Fp_model<n,modulus>& other)
{
#ifdef PROFILE_OP_COUNTS
this->sub_cnt++;
#endif
#if defined(__x86_64__) && defined(USE_ASM)
if (n == 3)
{
__asm__
(SUB_FIRSTSUB
SUB_NEXTSUB(8)
SUB_NEXTSUB(16)
"jnc done%=\n\t"
SUB_FIRSTADD
SUB_NEXTADD(8)
SUB_NEXTADD(16)
"done%=:\n\t"
:
: [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data)
: "cc", "memory", "%rax");
}
else if (n == 4)
{
__asm__
(SUB_FIRSTSUB
SUB_NEXTSUB(8)
SUB_NEXTSUB(16)
SUB_NEXTSUB(24)
"jnc done%=\n\t"
SUB_FIRSTADD
SUB_NEXTADD(8)
SUB_NEXTADD(16)
SUB_NEXTADD(24)
"done%=:\n\t"
:
: [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data)
: "cc", "memory", "%rax");
}
else if (n == 5)
{
__asm__
(SUB_FIRSTSUB
SUB_NEXTSUB(8)
SUB_NEXTSUB(16)
SUB_NEXTSUB(24)
SUB_NEXTSUB(32)
"jnc done%=\n\t"
SUB_FIRSTADD
SUB_NEXTADD(8)
SUB_NEXTADD(16)
SUB_NEXTADD(24)
SUB_NEXTADD(32)
"done%=:\n\t"
:
: [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data)
: "cc", "memory", "%rax");
}
else
#endif
{
mp_limb_t scratch[n+1];
if (mpn_cmp(this->mont_repr.data, other.mont_repr.data, n) < 0)
{
const mp_limb_t carry = mpn_add_n(scratch, this->mont_repr.data, modulus.data, n);
scratch[n] = carry;
}
else
{
mpn_copyi(scratch, this->mont_repr.data, n);
scratch[n] = 0;
}
const mp_limb_t borrow = mpn_sub(scratch, scratch, n+1, other.mont_repr.data, n);
assert_except(borrow == 0);
mpn_copyi(this->mont_repr.data, scratch, n);
}
return *this;
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus>& Fp_model<n,modulus>::operator*=(const Fp_model<n,modulus>& other)
{
#ifdef PROFILE_OP_COUNTS
this->mul_cnt++;
#endif
mul_reduce(other.mont_repr);
return *this;
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus>& Fp_model<n,modulus>::operator^=(const uint64_t pow)
{
(*this) = power<Fp_model<n, modulus> >(*this, pow);
return (*this);
}
template<mp_size_t n, const bigint<n>& modulus>
template<mp_size_t m>
Fp_model<n,modulus>& Fp_model<n,modulus>::operator^=(const bigint<m> &pow)
{
(*this) = power<Fp_model<n, modulus>, m>(*this, pow);
return (*this);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus> Fp_model<n,modulus>::operator+(const Fp_model<n,modulus>& other) const
{
Fp_model<n, modulus> r(*this);
return (r += other);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus> Fp_model<n,modulus>::operator-(const Fp_model<n,modulus>& other) const
{
Fp_model<n, modulus> r(*this);
return (r -= other);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus> Fp_model<n,modulus>::operator*(const Fp_model<n,modulus>& other) const
{
Fp_model<n, modulus> r(*this);
return (r *= other);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus> Fp_model<n,modulus>::operator^(const uint64_t pow) const
{
Fp_model<n, modulus> r(*this);
return (r ^= pow);
}
template<mp_size_t n, const bigint<n>& modulus>
template<mp_size_t m>
Fp_model<n,modulus> Fp_model<n,modulus>::operator^(const bigint<m> &pow) const
{
Fp_model<n, modulus> r(*this);
return (r ^= pow);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus> Fp_model<n,modulus>::operator-() const
{
#ifdef PROFILE_OP_COUNTS
this->sub_cnt++;
#endif
if (this->is_zero())
{
return (*this);
}
else
{
Fp_model<n, modulus> r;
mpn_sub_n(r.mont_repr.data, modulus.data, this->mont_repr.data, n);
return r;
}
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus> Fp_model<n,modulus>::squared() const
{
#ifdef PROFILE_OP_COUNTS
this->sqr_cnt++;
this->mul_cnt--; // zero out the upcoming mul
#endif
/* stupid pre-processor tricks; beware */
#if defined(__x86_64__) && defined(USE_ASM)
if (n == 3)
{ // use asm-optimized Comba squaring
mp_limb_t res[2*n];
mp_limb_t c0, c1, c2;
COMBA_3_BY_3_SQR(c0, c1, c2, res, this->mont_repr.data);
mp_limb_t k;
mp_limb_t tmp1, tmp2, tmp3;
REDUCE_6_LIMB_PRODUCT(k, tmp1, tmp2, tmp3, inv, res, modulus.data);
/* subtract t > mod */
__asm__ volatile
("/* check for overflow */ \n\t"
MONT_CMP(16)
MONT_CMP(8)
MONT_CMP(0)
"/* subtract mod if overflow */ \n\t"
"subtract%=: \n\t"
MONT_FIRSTSUB
MONT_NEXTSUB(8)
MONT_NEXTSUB(16)
"done%=: \n\t"
:
: [tmp] "r" (res+n), [M] "r" (modulus.data)
: "cc", "memory", "%rax");
Fp_model<n, modulus> r;
mpn_copyi(r.mont_repr.data, res+n, n);
return r;
}
else
#endif
{
Fp_model<n, modulus> r(*this);
return (r *= r);
}
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus>& Fp_model<n,modulus>::invert()
{
#ifdef PROFILE_OP_COUNTS
this->inv_cnt++;
#endif
assert_except(!this->is_zero());
bigint<n> g; /* gp should have room for vn = n limbs */
mp_limb_t s[n+1]; /* sp should have room for vn+1 limbs */
mp_size_t sn;
bigint<n> v = modulus; // both source operands are destroyed by mpn_gcdext
/* computes gcd(u, v) = g = u*s + v*t, so s*u will be 1 (mod v) */
const mp_size_t gn = mpn_gcdext(g.data, s, &sn, this->mont_repr.data, n, v.data, n);
assert_except(gn == 1 && g.data[0] == 1); /* inverse exists */
mp_limb_t q; /* division result fits into q, as sn <= n+1 */
/* sn < 0 indicates negative sn; will fix up later */
if (std::abs(sn) >= n)
{
/* if sn could require modulus reduction, do it here */
mpn_tdiv_qr(&q, this->mont_repr.data, 0, s, std::abs(sn), modulus.data, n);
}
else
{
/* otherwise just copy it over */
mpn_zero(this->mont_repr.data, n);
mpn_copyi(this->mont_repr.data, s, std::abs(sn));
}
/* fix up the negative sn */
if (sn < 0)
{
const mp_limb_t borrow = mpn_sub_n(this->mont_repr.data, modulus.data, this->mont_repr.data, n);
assert_except(borrow == 0);
}
mul_reduce(Rcubed);
return *this;
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus> Fp_model<n,modulus>::inverse() const
{
Fp_model<n, modulus> r(*this);
return (r.invert());
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n, modulus> Fp_model<n,modulus>::random_element() /// returns random element of Fp_model
{
/* note that as Montgomery representation is a bijection then
selecting a random element of {xR} is the same as selecting a
random element of {x} */
Fp_model<n, modulus> r;
do
{
r.mont_repr.randomize();
/* clear all bits higher than MSB of modulus */
uint64_t bitno = GMP_NUMB_BITS * n - 1;
while (modulus.test_bit(bitno) == false)
{
const uint64_t part = bitno/GMP_NUMB_BITS;
const uint64_t bit = bitno - (GMP_NUMB_BITS*part);
r.mont_repr.data[part] &= ~(UINT64_C(1)<<bit);
bitno--;
}
}
/* if r.data is still >= modulus -- repeat (rejection sampling) */
while (mpn_cmp(r.mont_repr.data, modulus.data, n) >= 0);
return r;
}
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n,modulus> Fp_model<n,modulus>::sqrt() const
{
if (is_zero()) {
return *this;
}
Fp_model<n,modulus> one = Fp_model<n,modulus>::one();
uint64_t v = Fp_model<n,modulus>::s;
Fp_model<n,modulus> z = Fp_model<n,modulus>::nqr_to_t;
Fp_model<n,modulus> w = (*this)^Fp_model<n,modulus>::t_minus_1_over_2;
Fp_model<n,modulus> x = (*this) * w;
Fp_model<n,modulus> b = x * w; // b = (*this)^t
// check if square with euler's criterion
Fp_model<n,modulus> check = b;
for (size_t i = 0; i < v-1; ++i)
{
check = check.squared();
}
if (check != one)
{
assert_except(0);
}
// compute square root with Tonelli--Shanks
// (does not terminate if not a square!)
while (b != one)
{
uint64_t m = 0;
Fp_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>
std::ostream& operator<<(std::ostream &out, const Fp_model<n, modulus> &p)
{
#ifndef MONTGOMERY_OUTPUT
Fp_model<n,modulus> tmp;
tmp.mont_repr.data[0] = 1;
tmp.mul_reduce(p.mont_repr);
out << tmp.mont_repr;
#else
out << p.mont_repr;
#endif
return out;
}
template<mp_size_t n, const bigint<n>& modulus>
std::istream& operator>>(std::istream &in, Fp_model<n, modulus> &p)
{
#ifndef MONTGOMERY_OUTPUT
in >> p.mont_repr;
p.mul_reduce(Fp_model<n, modulus>::Rsquared);
#else
in >> p.mont_repr;
#endif
return in;
}
} // libsnark
#endif // FP_TCC_

116
src/snark/libsnark/algebra/fields/fp12_2over3over2.hpp

@ -1,116 +0,0 @@
/** @file
*****************************************************************************
Declaration of arithmetic in the finite field F[((p^2)^3)^2].
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef FP12_2OVER3OVER2_HPP_
#define FP12_2OVER3OVER2_HPP_
#include "algebra/fields/fp.hpp"
#include "algebra/fields/fp2.hpp"
#include "algebra/fields/fp6_3over2.hpp"
#include <vector>
namespace libsnark {
template<mp_size_t n, const bigint<n>& modulus>
class Fp12_2over3over2_model;
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream &, const Fp12_2over3over2_model<n, modulus> &);
template<mp_size_t n, const bigint<n>& modulus>
std::istream& operator>>(std::istream &, Fp12_2over3over2_model<n, modulus> &);
/**
* Arithmetic in the finite field F[((p^2)^3)^2].
*
* Let p := modulus. This interface provides arithmetic for the extension field
* Fp12 = Fp6[W]/(W^2-V) where Fp6 = Fp2[V]/(V^3-non_residue) and non_residue is in Fp2
*
* ASSUMPTION: p = 1 (mod 6)
*/
template<mp_size_t n, const bigint<n>& modulus>
class Fp12_2over3over2_model {
public:
typedef Fp_model<n, modulus> my_Fp;
typedef Fp2_model<n, modulus> my_Fp2;
typedef Fp6_3over2_model<n, modulus> my_Fp6;
static Fp2_model<n, modulus> non_residue;
static Fp2_model<n, modulus> Frobenius_coeffs_c1[12]; // non_residue^((modulus^i-1)/6) for i=0,...,11
my_Fp6 c0, c1;
Fp12_2over3over2_model() {};
Fp12_2over3over2_model(const my_Fp6& c0, const my_Fp6& c1) : c0(c0), c1(c1) {};
void clear() { c0.clear(); c1.clear(); }
void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); }
static Fp12_2over3over2_model<n, modulus> zero();
static Fp12_2over3over2_model<n, modulus> one();
static Fp12_2over3over2_model<n, modulus> random_element();
bool is_zero() const { return c0.is_zero() && c1.is_zero(); }
bool operator==(const Fp12_2over3over2_model &other) const;
bool operator!=(const Fp12_2over3over2_model &other) const;
Fp12_2over3over2_model operator+(const Fp12_2over3over2_model &other) const;
Fp12_2over3over2_model operator-(const Fp12_2over3over2_model &other) const;
Fp12_2over3over2_model operator*(const Fp12_2over3over2_model &other) const;
Fp12_2over3over2_model operator-() const;
Fp12_2over3over2_model squared() const; // default is squared_complex
Fp12_2over3over2_model squared_karatsuba() const;
Fp12_2over3over2_model squared_complex() const;
Fp12_2over3over2_model inverse() const;
Fp12_2over3over2_model Frobenius_map(uint64_t power) const;
Fp12_2over3over2_model unitary_inverse() const;
Fp12_2over3over2_model cyclotomic_squared() const;
Fp12_2over3over2_model mul_by_024(const my_Fp2 &ell_0, const my_Fp2 &ell_VW, const my_Fp2 &ell_VV) const;
static my_Fp6 mul_by_non_residue(const my_Fp6 &elt);
template<mp_size_t m>
Fp12_2over3over2_model cyclotomic_exp(const bigint<m> &exponent) const;
static bigint<n> base_field_char() { return modulus; }
static uint64_t extension_degree() { return 12; }
friend std::ostream& operator<< <n, modulus>(std::ostream &out, const Fp12_2over3over2_model<n, modulus> &el);
friend std::istream& operator>> <n, modulus>(std::istream &in, Fp12_2over3over2_model<n, modulus> &el);
};
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream& out, const std::vector<Fp12_2over3over2_model<n, modulus> > &v);
template<mp_size_t n, const bigint<n>& modulus>
std::istream& operator>>(std::istream& in, std::vector<Fp12_2over3over2_model<n, modulus> > &v);
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n, modulus> operator*(const Fp_model<n, modulus> &lhs, const Fp12_2over3over2_model<n, modulus> &rhs);
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n, modulus> operator*(const Fp2_model<n, modulus> &lhs, const Fp12_2over3over2_model<n, modulus> &rhs);
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n, modulus> operator*(const Fp6_3over2_model<n, modulus> &lhs, const Fp12_2over3over2_model<n, modulus> &rhs);
template<mp_size_t n, const bigint<n>& modulus, mp_size_t m>
Fp12_2over3over2_model<n, modulus> operator^(const Fp12_2over3over2_model<n, modulus> &self, const bigint<m> &exponent);
template<mp_size_t n, const bigint<n>& modulus, mp_size_t m, const bigint<m>& exp_modulus>
Fp12_2over3over2_model<n, modulus> operator^(const Fp12_2over3over2_model<n, modulus> &self, const Fp_model<m, exp_modulus> &exponent);
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::non_residue;
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n, modulus> Fp12_2over3over2_model<n, modulus>::Frobenius_coeffs_c1[12];
} // libsnark
#include "algebra/fields/fp12_2over3over2.tcc"
#endif // FP12_2OVER3OVER2_HPP_

412
src/snark/libsnark/algebra/fields/fp12_2over3over2.tcc

@ -1,412 +0,0 @@
/** @file
*****************************************************************************
Implementation of arithmetic in the finite field F[((p^2)^3)^2].
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef FP12_2OVER3OVER2_TCC_
#define FP12_2OVER3OVER2_TCC_
namespace libsnark {
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n, modulus> Fp12_2over3over2_model<n,modulus>::mul_by_non_residue(const Fp6_3over2_model<n, modulus> &elt)
{
return Fp6_3over2_model<n, modulus>(non_residue * elt.c2, elt.c0, elt.c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::zero()
{
return Fp12_2over3over2_model<n, modulus>(my_Fp6::zero(), my_Fp6::zero());
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::one()
{
return Fp12_2over3over2_model<n, modulus>(my_Fp6::one(), my_Fp6::zero());
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::random_element()
{
Fp12_2over3over2_model<n, modulus> r;
r.c0 = my_Fp6::random_element();
r.c1 = my_Fp6::random_element();
return r;
}
template<mp_size_t n, const bigint<n>& modulus>
bool Fp12_2over3over2_model<n,modulus>::operator==(const Fp12_2over3over2_model<n,modulus> &other) const
{
return (this->c0 == other.c0 && this->c1 == other.c1);
}
template<mp_size_t n, const bigint<n>& modulus>
bool Fp12_2over3over2_model<n,modulus>::operator!=(const Fp12_2over3over2_model<n,modulus> &other) const
{
return !(operator==(other));
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::operator+(const Fp12_2over3over2_model<n,modulus> &other) const
{
return Fp12_2over3over2_model<n,modulus>(this->c0 + other.c0,
this->c1 + other.c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::operator-(const Fp12_2over3over2_model<n,modulus> &other) const
{
return Fp12_2over3over2_model<n,modulus>(this->c0 - other.c0,
this->c1 - other.c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n, modulus> operator*(const Fp_model<n, modulus> &lhs, const Fp12_2over3over2_model<n, modulus> &rhs)
{
return Fp12_2over3over2_model<n,modulus>(lhs*rhs.c0,
lhs*rhs.c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n, modulus> operator*(const Fp2_model<n, modulus> &lhs, const Fp12_2over3over2_model<n, modulus> &rhs)
{
return Fp12_2over3over2_model<n,modulus>(lhs*rhs.c0,
lhs*rhs.c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n, modulus> operator*(const Fp6_3over2_model<n, modulus> &lhs, const Fp12_2over3over2_model<n, modulus> &rhs)
{
return Fp12_2over3over2_model<n,modulus>(lhs*rhs.c0,
lhs*rhs.c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::operator*(const Fp12_2over3over2_model<n,modulus> &other) const
{
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */
const my_Fp6 &A = other.c0, &B = other.c1,
&a = this->c0, &b = this->c1;
const my_Fp6 aA = a * A;
const my_Fp6 bB = b * B;
return Fp12_2over3over2_model<n,modulus>(aA + Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(bB),
(a + b)*(A+B) - aA - bB);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::operator-() const
{
return Fp12_2over3over2_model<n,modulus>(-this->c0,
-this->c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::squared() const
{
return squared_complex();
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::squared_karatsuba() const
{
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */
const my_Fp6 &a = this->c0, &b = this->c1;
const my_Fp6 asq = a.squared();
const my_Fp6 bsq = b.squared();
return Fp12_2over3over2_model<n,modulus>(asq + Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(bsq),
(a + b).squared() - asq - bsq);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::squared_complex() const
{
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */
const my_Fp6 &a = this->c0, &b = this->c1;
const my_Fp6 ab = a * b;
return Fp12_2over3over2_model<n,modulus>((a + b) * (a + Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(b)) - ab - Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(ab),
ab + ab);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::inverse() const
{
/* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */
const my_Fp6 &a = this->c0, &b = this->c1;
const my_Fp6 t0 = a.squared();
const my_Fp6 t1 = b.squared();
const my_Fp6 t2 = t0 - Fp12_2over3over2_model<n, modulus>::mul_by_non_residue(t1);
const my_Fp6 t3 = t2.inverse();
const my_Fp6 c0 = a * t3;
const my_Fp6 c1 = - (b * t3);
return Fp12_2over3over2_model<n,modulus>(c0, c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::Frobenius_map(uint64_t power) const
{
return Fp12_2over3over2_model<n,modulus>(c0.Frobenius_map(power),
Frobenius_coeffs_c1[power % 12] * c1.Frobenius_map(power));
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::unitary_inverse() const
{
return Fp12_2over3over2_model<n,modulus>(this->c0,
-this->c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::cyclotomic_squared() const
{
/* OLD: naive implementation
return (*this).squared();
*/
my_Fp2 z0 = this->c0.c0;
my_Fp2 z4 = this->c0.c1;
my_Fp2 z3 = this->c0.c2;
my_Fp2 z2 = this->c1.c0;
my_Fp2 z1 = this->c1.c1;
my_Fp2 z5 = this->c1.c2;
my_Fp2 t0, t1, t2, t3, t4, t5, tmp;
// t0 + t1*y = (z0 + z1*y)^2 = a^2
tmp = z0 * z1;
t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp - my_Fp6::non_residue * tmp;
t1 = tmp + tmp;
// t2 + t3*y = (z2 + z3*y)^2 = b^2
tmp = z2 * z3;
t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp - my_Fp6::non_residue * tmp;
t3 = tmp + tmp;
// t4 + t5*y = (z4 + z5*y)^2 = c^2
tmp = z4 * z5;
t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp - my_Fp6::non_residue * tmp;
t5 = tmp + tmp;
// for A
// z0 = 3 * t0 - 2 * z0
z0 = t0 - z0;
z0 = z0 + z0;
z0 = z0 + t0;
// z1 = 3 * t1 + 2 * z1
z1 = t1 + z1;
z1 = z1 + z1;
z1 = z1 + t1;
// for B
// z2 = 3 * (xi * t5) + 2 * z2
tmp = my_Fp6::non_residue * t5;
z2 = tmp + z2;
z2 = z2 + z2;
z2 = z2 + tmp;
// z3 = 3 * t4 - 2 * z3
z3 = t4 - z3;
z3 = z3 + z3;
z3 = z3 + t4;
// for C
// z4 = 3 * t2 - 2 * z4
z4 = t2 - z4;
z4 = z4 + z4;
z4 = z4 + t2;
// z5 = 3 * t3 + 2 * z5
z5 = t3 + z5;
z5 = z5 + z5;
z5 = z5 + t3;
return Fp12_2over3over2_model<n,modulus>(my_Fp6(z0,z4,z3),my_Fp6(z2,z1,z5));
}
template<mp_size_t n, const bigint<n>& modulus>
Fp12_2over3over2_model<n,modulus> Fp12_2over3over2_model<n,modulus>::mul_by_024(const Fp2_model<n, modulus> &ell_0,
const Fp2_model<n, modulus> &ell_VW,
const Fp2_model<n, modulus> &ell_VV) const
{
/* OLD: naive implementation
Fp12_2over3over2_model<n,modulus> a(my_Fp6(ell_0, my_Fp2::zero(), ell_VV),
my_Fp6(my_Fp2::zero(), ell_VW, my_Fp2::zero()));
return (*this) * a;
*/
my_Fp2 z0 = this->c0.c0;
my_Fp2 z1 = this->c0.c1;
my_Fp2 z2 = this->c0.c2;
my_Fp2 z3 = this->c1.c0;
my_Fp2 z4 = this->c1.c1;
my_Fp2 z5 = this->c1.c2;
my_Fp2 x0 = ell_0;
my_Fp2 x2 = ell_VV;
my_Fp2 x4 = ell_VW;
my_Fp2 t0, t1, t2, s0, T3, T4, D0, D2, D4, S1;
D0 = z0 * x0;
D2 = z2 * x2;
D4 = z4 * x4;
t2 = z0 + z4;
t1 = z0 + z2;
s0 = z1 + z3 + z5;
// For z.a_.a_ = z0.
S1 = z1 * x2;
T3 = S1 + D4;
T4 = my_Fp6::non_residue * T3 + D0;
z0 = T4;
// For z.a_.b_ = z1
T3 = z5 * x4;
S1 = S1 + T3;
T3 = T3 + D2;
T4 = my_Fp6::non_residue * T3;
T3 = z1 * x0;
S1 = S1 + T3;
T4 = T4 + T3;
z1 = T4;
// For z.a_.c_ = z2
t0 = x0 + x2;
T3 = t1 * t0 - D0 - D2;
T4 = z3 * x4;
S1 = S1 + T4;
T3 = T3 + T4;
// For z.b_.a_ = z3 (z3 needs z2)
t0 = z2 + z4;
z2 = T3;
t1 = x2 + x4;
T3 = t0 * t1 - D2 - D4;
T4 = my_Fp6::non_residue * T3;
T3 = z3 * x0;
S1 = S1 + T3;
T4 = T4 + T3;
z3 = T4;
// For z.b_.b_ = z4
T3 = z5 * x2;
S1 = S1 + T3;
T4 = my_Fp6::non_residue * T3;
t0 = x0 + x4;
T3 = t2 * t0 - D0 - D4;
T4 = T4 + T3;
z4 = T4;
// For z.b_.c_ = z5.
t0 = x0 + x2 + x4;
T3 = s0 * t0 - S1;
z5 = T3;
return Fp12_2over3over2_model<n,modulus>(my_Fp6(z0,z1,z2),my_Fp6(z3,z4,z5));
}
template<mp_size_t n, const bigint<n>& modulus, mp_size_t m>
Fp12_2over3over2_model<n, modulus> operator^(const Fp12_2over3over2_model<n, modulus> &self, const bigint<m> &exponent)
{
return power<Fp12_2over3over2_model<n, modulus> >(self, exponent);
}
template<mp_size_t n, const bigint<n>& modulus, mp_size_t m, const bigint<m>& exp_modulus>
Fp12_2over3over2_model<n, modulus> operator^(const Fp12_2over3over2_model<n, modulus> &self, const Fp_model<m, exp_modulus> &exponent)
{
return self^(exponent.as_bigint());
}
template<mp_size_t n, const bigint<n>& modulus>
template<mp_size_t m>
Fp12_2over3over2_model<n, modulus> Fp12_2over3over2_model<n,modulus>::cyclotomic_exp(const bigint<m> &exponent) const
{
Fp12_2over3over2_model<n,modulus> res = Fp12_2over3over2_model<n,modulus>::one();
bool found_one = false;
for (int64_t i = m-1; i >= 0; --i)
{
for (int64_t j = GMP_NUMB_BITS - 1; j >= 0; --j)
{
if (found_one)
{
res = res.cyclotomic_squared();
}
if (exponent.data[i] & (((mp_limb_t) 1)<<j))
{
found_one = true;
res = res * (*this);
}
}
}
return res;
}
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream &out, const Fp12_2over3over2_model<n, modulus> &el)
{
out << el.c0 << OUTPUT_SEPARATOR << el.c1;
return out;
}
template<mp_size_t n, const bigint<n>& modulus>
std::istream& operator>>(std::istream &in, Fp12_2over3over2_model<n, modulus> &el)
{
in >> el.c0 >> el.c1;
return in;
}
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream& out, const std::vector<Fp12_2over3over2_model<n, modulus> > &v)
{
out << v.size() << "\n";
for (const Fp12_2over3over2_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<Fp12_2over3over2_model<n, modulus> > &v)
{
v.clear();
uint64_t s;
in >> s;
char b;
in.read(&b, 1);
v.reserve(s);
for (size_t i = 0; i < s; ++i)
{
Fp12_2over3over2_model<n, modulus> el;
in >> el;
v.emplace_back(el);
}
return in;
}
} // libsnark
#endif // FP12_2OVER3OVER2_TCC_

120
src/snark/libsnark/algebra/fields/fp2.hpp

@ -1,120 +0,0 @@
/** @file
*****************************************************************************
Implementation of arithmetic in the finite field F[p^2].
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef FP2_HPP_
#define FP2_HPP_
#include "algebra/fields/fp.hpp"
#include <vector>
namespace libsnark {
template<mp_size_t n, const bigint<n>& modulus>
class Fp2_model;
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream &, const Fp2_model<n, modulus> &);
template<mp_size_t n, const bigint<n>& modulus>
std::istream& operator>>(std::istream &, Fp2_model<n, modulus> &);
/**
* Arithmetic in the field F[p^3].
*
* Let p := modulus. This interface provides arithmetic for the extension field
* Fp2 = Fp[U]/(U^2-non_residue), where non_residue is in Fp.
*
* ASSUMPTION: p = 1 (mod 6)
*/
template<mp_size_t n, const bigint<n>& modulus>
class Fp2_model {
public:
typedef Fp_model<n, modulus> my_Fp;
static bigint<2*n> euler; // (modulus^2-1)/2
static uint64_t s; // modulus^2 = 2^s * t + 1
static bigint<2*n> t; // with t odd
static bigint<2*n> t_minus_1_over_2; // (t-1)/2
static my_Fp non_residue; // X^4-non_residue irreducible over Fp; used for constructing Fp2 = Fp[X] / (X^2 - non_residue)
static Fp2_model<n, modulus> nqr; // a quadratic nonresidue in Fp2
static Fp2_model<n, modulus> nqr_to_t; // nqr^t
static my_Fp Frobenius_coeffs_c1[2]; // non_residue^((modulus^i-1)/2) for i=0,1
my_Fp c0, c1;
Fp2_model() {};
Fp2_model(const my_Fp& c0, const my_Fp& c1) : c0(c0), c1(c1) {};
void clear() { c0.clear(); c1.clear(); }
void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); }
static Fp2_model<n, modulus> zero();
static Fp2_model<n, modulus> one();
static Fp2_model<n, modulus> random_element();
bool is_zero() const { return c0.is_zero() && c1.is_zero(); }
bool operator==(const Fp2_model &other) const;
bool operator!=(const Fp2_model &other) const;
Fp2_model operator+(const Fp2_model &other) const;
Fp2_model operator-(const Fp2_model &other) const;
Fp2_model operator*(const Fp2_model &other) const;
Fp2_model operator-() const;
Fp2_model squared() const; // default is squared_complex
Fp2_model inverse() const;
Fp2_model Frobenius_map(uint64_t power) const;
Fp2_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate)
Fp2_model squared_karatsuba() const;
Fp2_model squared_complex() const;
template<mp_size_t m>
Fp2_model operator^(const bigint<m> &other) const;
static uint64_t size_in_bits() { return 2*my_Fp::size_in_bits(); }
static bigint<n> base_field_char() { return modulus; }
friend std::ostream& operator<< <n, modulus>(std::ostream &out, const Fp2_model<n, modulus> &el);
friend std::istream& operator>> <n, modulus>(std::istream &in, Fp2_model<n, modulus> &el);
};
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream& out, const std::vector<Fp2_model<n, modulus> > &v);
template<mp_size_t n, const bigint<n>& modulus>
std::istream& operator>>(std::istream& in, std::vector<Fp2_model<n, modulus> > &v);
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n, modulus> operator*(const Fp_model<n, modulus> &lhs, const Fp2_model<n, modulus> &rhs);
template<mp_size_t n, const bigint<n>& modulus>
bigint<2*n> Fp2_model<n, modulus>::euler;
template<mp_size_t n, const bigint<n>& modulus>
uint64_t Fp2_model<n, modulus>::s;
template<mp_size_t n, const bigint<n>& modulus>
bigint<2*n> Fp2_model<n, modulus>::t;
template<mp_size_t n, const bigint<n>& modulus>
bigint<2*n> Fp2_model<n, modulus>::t_minus_1_over_2;
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n, modulus> Fp2_model<n, modulus>::non_residue;
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n, modulus> Fp2_model<n, modulus>::nqr;
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n, modulus> Fp2_model<n, modulus>::nqr_to_t;
template<mp_size_t n, const bigint<n>& modulus>
Fp_model<n, modulus> Fp2_model<n, modulus>::Frobenius_coeffs_c1[2];
} // libsnark
#include "algebra/fields/fp2.tcc"
#endif // FP2_HPP_

261
src/snark/libsnark/algebra/fields/fp2.tcc

@ -1,261 +0,0 @@
/** @file
*****************************************************************************
Implementation of arithmetic in the finite field F[p^2].
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef FP2_TCC_
#define FP2_TCC_
#include "algebra/fields/field_utils.hpp"
namespace libsnark {
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::zero()
{
return Fp2_model<n, modulus>(my_Fp::zero(), my_Fp::zero());
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::one()
{
return Fp2_model<n, modulus>(my_Fp::one(), my_Fp::zero());
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::random_element()
{
Fp2_model<n, modulus> r;
r.c0 = my_Fp::random_element();
r.c1 = my_Fp::random_element();
return r;
}
template<mp_size_t n, const bigint<n>& modulus>
bool Fp2_model<n,modulus>::operator==(const Fp2_model<n,modulus> &other) const
{
return (this->c0 == other.c0 && this->c1 == other.c1);
}
template<mp_size_t n, const bigint<n>& modulus>
bool Fp2_model<n,modulus>::operator!=(const Fp2_model<n,modulus> &other) const
{
return !(operator==(other));
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::operator+(const Fp2_model<n,modulus> &other) const
{
return Fp2_model<n,modulus>(this->c0 + other.c0,
this->c1 + other.c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::operator-(const Fp2_model<n,modulus> &other) const
{
return Fp2_model<n,modulus>(this->c0 - other.c0,
this->c1 - other.c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n, modulus> operator*(const Fp_model<n, modulus> &lhs, const Fp2_model<n, modulus> &rhs)
{
return Fp2_model<n,modulus>(lhs*rhs.c0,
lhs*rhs.c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::operator*(const Fp2_model<n,modulus> &other) const
{
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */
const my_Fp
&A = other.c0, &B = other.c1,
&a = this->c0, &b = this->c1;
const my_Fp aA = a * A;
const my_Fp bB = b * B;
return Fp2_model<n,modulus>(aA + non_residue * bB,
(a + b)*(A+B) - aA - bB);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::operator-() const
{
return Fp2_model<n,modulus>(-this->c0,
-this->c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::squared() const
{
return squared_complex();
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::squared_karatsuba() const
{
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */
const my_Fp &a = this->c0, &b = this->c1;
const my_Fp asq = a.squared();
const my_Fp bsq = b.squared();
return Fp2_model<n,modulus>(asq + non_residue * bsq,
(a + b).squared() - asq - bsq);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::squared_complex() const
{
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */
const my_Fp &a = this->c0, &b = this->c1;
const my_Fp ab = a * b;
return Fp2_model<n,modulus>((a + b) * (a + non_residue * b) - ab - non_residue * ab,
ab + ab);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::inverse() const
{
const my_Fp &a = this->c0, &b = this->c1;
/* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */
const my_Fp t0 = a.squared();
const my_Fp t1 = b.squared();
const my_Fp t2 = t0 - non_residue * t1;
const my_Fp t3 = t2.inverse();
const my_Fp c0 = a * t3;
const my_Fp c1 = - (b * t3);
return Fp2_model<n,modulus>(c0, c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::Frobenius_map(uint64_t power) const
{
return Fp2_model<n,modulus>(c0,
Frobenius_coeffs_c1[power % 2] * c1);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n,modulus> Fp2_model<n,modulus>::sqrt() const
{
if (is_zero()) {
return *this;
}
Fp2_model<n,modulus> one = Fp2_model<n,modulus>::one();
unsigned long long v = Fp2_model<n,modulus>::s;
Fp2_model<n,modulus> z = Fp2_model<n,modulus>::nqr_to_t;
Fp2_model<n,modulus> w = (*this)^Fp2_model<n,modulus>::t_minus_1_over_2;
Fp2_model<n,modulus> x = (*this) * w;
Fp2_model<n,modulus> b = x * w; // b = (*this)^t
// check if square with euler's criterion
Fp2_model<n,modulus> check = b;
for (size_t i = 0; i < v-1; ++i)
{
check = check.squared();
}
if (check != one)
{
assert_except(0);
}
// compute square root with Tonelli--Shanks
// (does not terminate if not a square!)
while (b != one)
{
unsigned long long m = 0;
Fp2_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>
Fp2_model<n,modulus> Fp2_model<n,modulus>::operator^(const bigint<m> &pow) const
{
return power<Fp2_model<n, modulus>, m>(*this, pow);
}
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream &out, const Fp2_model<n, modulus> &el)
{
out << el.c0 << OUTPUT_SEPARATOR << el.c1;
return out;
}
template<mp_size_t n, const bigint<n>& modulus>
std::istream& operator>>(std::istream &in, Fp2_model<n, modulus> &el)
{
in >> el.c0 >> el.c1;
return in;
}
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream& out, const std::vector<Fp2_model<n, modulus> > &v)
{
out << v.size() << "\n";
for (const Fp2_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<Fp2_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)
{
Fp2_model<n, modulus> el;
in >> el;
v.emplace_back(el);
}
return in;
}
} // libsnark
#endif // FP2_TCC_

104
src/snark/libsnark/algebra/fields/fp6_3over2.hpp

@ -1,104 +0,0 @@
/** @file
*****************************************************************************
Declaration of arithmetic in the finite field F[(p^2)^3]
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef FP6_3OVER2_HPP_
#define FP6_3OVER2_HPP_
#include "algebra/fields/fp.hpp"
#include "algebra/fields/fp2.hpp"
#include <vector>
namespace libsnark {
template<mp_size_t n, const bigint<n>& modulus>
class Fp6_3over2_model;
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream &, const Fp6_3over2_model<n, modulus> &);
template<mp_size_t n, const bigint<n>& modulus>
std::istream& operator>>(std::istream &, Fp6_3over2_model<n, modulus> &);
/**
* Arithmetic in the finite field F[(p^2)^3].
*
* Let p := modulus. This interface provides arithmetic for the extension field
* Fp6 = Fp2[V]/(V^3-non_residue) where non_residue is in Fp.
*
* ASSUMPTION: p = 1 (mod 6)
*/
template<mp_size_t n, const bigint<n>& modulus>
class Fp6_3over2_model {
public:
typedef Fp_model<n, modulus> my_Fp;
typedef Fp2_model<n, modulus> my_Fp2;
static my_Fp2 non_residue;
static my_Fp2 Frobenius_coeffs_c1[6]; // non_residue^((modulus^i-1)/3) for i=0,1,2,3,4,5
static my_Fp2 Frobenius_coeffs_c2[6]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2,3,4,5
my_Fp2 c0, c1, c2;
Fp6_3over2_model() {};
Fp6_3over2_model(const my_Fp2& c0, const my_Fp2& c1, const my_Fp2& 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 Fp6_3over2_model<n, modulus> zero();
static Fp6_3over2_model<n, modulus> one();
static Fp6_3over2_model<n, modulus> random_element();
bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); }
bool operator==(const Fp6_3over2_model &other) const;
bool operator!=(const Fp6_3over2_model &other) const;
Fp6_3over2_model operator+(const Fp6_3over2_model &other) const;
Fp6_3over2_model operator-(const Fp6_3over2_model &other) const;
Fp6_3over2_model operator*(const Fp6_3over2_model &other) const;
Fp6_3over2_model operator-() const;
Fp6_3over2_model squared() const;
Fp6_3over2_model inverse() const;
Fp6_3over2_model Frobenius_map(uint64_t power) const;
static my_Fp2 mul_by_non_residue(const my_Fp2 &elt);
template<mp_size_t m>
Fp6_3over2_model operator^(const bigint<m> &other) const;
static bigint<n> base_field_char() { return modulus; }
static uint64_t extension_degree() { return 6; }
friend std::ostream& operator<< <n, modulus>(std::ostream &out, const Fp6_3over2_model<n, modulus> &el);
friend std::istream& operator>> <n, modulus>(std::istream &in, Fp6_3over2_model<n, modulus> &el);
};
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream& out, const std::vector<Fp6_3over2_model<n, modulus> > &v);
template<mp_size_t n, const bigint<n>& modulus>
std::istream& operator>>(std::istream& in, std::vector<Fp6_3over2_model<n, modulus> > &v);
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n, modulus> operator*(const Fp_model<n, modulus> &lhs, const Fp6_3over2_model<n, modulus> &rhs);
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n, modulus> operator*(const Fp2_model<n, modulus> &lhs, const Fp6_3over2_model<n, modulus> &rhs);
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n, modulus> Fp6_3over2_model<n, modulus>::non_residue;
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n, modulus> Fp6_3over2_model<n, modulus>::Frobenius_coeffs_c1[6];
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n, modulus> Fp6_3over2_model<n, modulus>::Frobenius_coeffs_c2[6];
} // libsnark
#include "algebra/fields/fp6_3over2.tcc"
#endif // FP6_3OVER2_HPP_

216
src/snark/libsnark/algebra/fields/fp6_3over2.tcc

@ -1,216 +0,0 @@
/** @file
*****************************************************************************
Implementation of arithmetic in the finite field F[(p^2)^3].
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef FP6_3OVER2_TCC_
#define FP6_3OVER2_TCC_
#include "algebra/fields/field_utils.hpp"
namespace libsnark {
template<mp_size_t n, const bigint<n>& modulus>
Fp2_model<n, modulus> Fp6_3over2_model<n,modulus>::mul_by_non_residue(const Fp2_model<n, modulus> &elt)
{
return Fp2_model<n, modulus>(non_residue * elt);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::zero()
{
return Fp6_3over2_model<n, modulus>(my_Fp2::zero(), my_Fp2::zero(), my_Fp2::zero());
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::one()
{
return Fp6_3over2_model<n, modulus>(my_Fp2::one(), my_Fp2::zero(), my_Fp2::zero());
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::random_element()
{
Fp6_3over2_model<n, modulus> r;
r.c0 = my_Fp2::random_element();
r.c1 = my_Fp2::random_element();
r.c2 = my_Fp2::random_element();
return r;
}
template<mp_size_t n, const bigint<n>& modulus>
bool Fp6_3over2_model<n,modulus>::operator==(const Fp6_3over2_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 Fp6_3over2_model<n,modulus>::operator!=(const Fp6_3over2_model<n,modulus> &other) const
{
return !(operator==(other));
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::operator+(const Fp6_3over2_model<n,modulus> &other) const
{
return Fp6_3over2_model<n,modulus>(this->c0 + other.c0,
this->c1 + other.c1,
this->c2 + other.c2);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::operator-(const Fp6_3over2_model<n,modulus> &other) const
{
return Fp6_3over2_model<n,modulus>(this->c0 - other.c0,
this->c1 - other.c1,
this->c2 - other.c2);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n, modulus> operator*(const Fp_model<n, modulus> &lhs, const Fp6_3over2_model<n, modulus> &rhs)
{
return Fp6_3over2_model<n,modulus>(lhs*rhs.c0,
lhs*rhs.c1,
lhs*rhs.c2);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n, modulus> operator*(const Fp2_model<n, modulus> &lhs, const Fp6_3over2_model<n, modulus> &rhs)
{
return Fp6_3over2_model<n,modulus>(lhs*rhs.c0,
lhs*rhs.c1,
lhs*rhs.c2);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::operator*(const Fp6_3over2_model<n,modulus> &other) const
{
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */
const my_Fp2 &A = other.c0, &B = other.c1, &C = other.c2,
&a = this->c0, &b = this->c1, &c = this->c2;
const my_Fp2 aA = a*A;
const my_Fp2 bB = b*B;
const my_Fp2 cC = c*C;
return Fp6_3over2_model<n,modulus>(aA + Fp6_3over2_model<n,modulus>::mul_by_non_residue((b+c)*(B+C)-bB-cC),
(a+b)*(A+B)-aA-bB+Fp6_3over2_model<n,modulus>::mul_by_non_residue(cC),
(a+c)*(A+C)-aA+bB-cC);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::operator-() const
{
return Fp6_3over2_model<n,modulus>(-this->c0,
-this->c1,
-this->c2);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::squared() const
{
/* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */
const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2;
const my_Fp2 s0 = a.squared();
const my_Fp2 ab = a*b;
const my_Fp2 s1 = ab + ab;
const my_Fp2 s2 = (a - b + c).squared();
const my_Fp2 bc = b*c;
const my_Fp2 s3 = bc + bc;
const my_Fp2 s4 = c.squared();
return Fp6_3over2_model<n,modulus>(s0 + Fp6_3over2_model<n,modulus>::mul_by_non_residue(s3),
s1 + Fp6_3over2_model<n,modulus>::mul_by_non_residue(s4),
s1 + s2 + s3 - s0 - s4);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::inverse() const
{
/* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */
const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2;
const my_Fp2 t0 = a.squared();
const my_Fp2 t1 = b.squared();
const my_Fp2 t2 = c.squared();
const my_Fp2 t3 = a*b;
const my_Fp2 t4 = a*c;
const my_Fp2 t5 = b*c;
const my_Fp2 c0 = t0 - Fp6_3over2_model<n,modulus>::mul_by_non_residue(t5);
const my_Fp2 c1 = Fp6_3over2_model<n,modulus>::mul_by_non_residue(t2) - t3;
const my_Fp2 c2 = t1 - t4; // typo in paper referenced above. should be "-" as per Scott, but is "*"
const my_Fp2 t6 = (a * c0 + Fp6_3over2_model<n,modulus>::mul_by_non_residue((c * c1 + b * c2))).inverse();
return Fp6_3over2_model<n,modulus>(t6 * c0, t6 * c1, t6 * c2);
}
template<mp_size_t n, const bigint<n>& modulus>
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::Frobenius_map(uint64_t power) const
{
return Fp6_3over2_model<n,modulus>(c0.Frobenius_map(power),
Frobenius_coeffs_c1[power % 6] * c1.Frobenius_map(power),
Frobenius_coeffs_c2[power % 6] * c2.Frobenius_map(power));
}
template<mp_size_t n, const bigint<n>& modulus>
template<mp_size_t m>
Fp6_3over2_model<n,modulus> Fp6_3over2_model<n,modulus>::operator^(const bigint<m> &pow) const
{
return power<Fp6_3over2_model<n, modulus>, m>(*this, pow);
}
template<mp_size_t n, const bigint<n>& modulus>
std::ostream& operator<<(std::ostream &out, const Fp6_3over2_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, Fp6_3over2_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<Fp6_3over2_model<n, modulus> > &v)
{
out << v.size() << "\n";
for (const Fp6_3over2_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<Fp6_3over2_model<n, modulus> > &v)
{
v.clear();
uint64_t s;
in >> s;
char b;
in.read(&b, 1);
v.reserve(s);
for (size_t i = 0; i < s; ++i)
{
Fp6_3over2_model<n, modulus> el;
in >> el;
v.emplace_back(el);
}
return in;
}
} // libsnark
#endif // FP6_3_OVER_2_TCC_

389
src/snark/libsnark/algebra/fields/fp_aux.tcc

@ -1,389 +0,0 @@
/** @file
*****************************************************************************
Assembly code snippets for F[p] finite field arithmetic, used by fp.tcc .
Specific to x86-64, and used only if USE_ASM is defined.
On other architectures or without USE_ASM, fp.tcc uses a portable
C++ implementation instead.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef FP_AUX_TCC_
#define FP_AUX_TCC_
namespace libsnark {
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
/* addq is faster than adcq, even if preceded by clc */
#define ADD_FIRSTADD \
"movq (%[B]), %%rax \n\t" \
"addq %%rax, (%[A]) \n\t"
#define ADD_NEXTADD(ofs) \
"movq " STR(ofs) "(%[B]), %%rax \n\t" \
"adcq %%rax, " STR(ofs) "(%[A]) \n\t"
#define ADD_CMP(ofs) \
"movq " STR(ofs) "(%[mod]), %%rax \n\t" \
"cmpq %%rax, " STR(ofs) "(%[A]) \n\t" \
"jb done%= \n\t" \
"ja subtract%= \n\t"
#define ADD_FIRSTSUB \
"movq (%[mod]), %%rax \n\t" \
"subq %%rax, (%[A]) \n\t"
#define ADD_FIRSTSUB \
"movq (%[mod]), %%rax \n\t" \
"subq %%rax, (%[A]) \n\t"
#define ADD_NEXTSUB(ofs) \
"movq " STR(ofs) "(%[mod]), %%rax \n\t" \
"sbbq %%rax, " STR(ofs) "(%[A]) \n\t"
#define SUB_FIRSTSUB \
"movq (%[B]), %%rax\n\t" \
"subq %%rax, (%[A])\n\t"
#define SUB_NEXTSUB(ofs) \
"movq " STR(ofs) "(%[B]), %%rax\n\t" \
"sbbq %%rax, " STR(ofs) "(%[A])\n\t"
#define SUB_FIRSTADD \
"movq (%[mod]), %%rax\n\t" \
"addq %%rax, (%[A])\n\t"
#define SUB_NEXTADD(ofs) \
"movq " STR(ofs) "(%[mod]), %%rax\n\t" \
"adcq %%rax, " STR(ofs) "(%[A])\n\t"
#define MONT_CMP(ofs) \
"movq " STR(ofs) "(%[M]), %%rax \n\t" \
"cmpq %%rax, " STR(ofs) "(%[tmp]) \n\t" \
"jb done%= \n\t" \
"ja subtract%= \n\t"
#define MONT_FIRSTSUB \
"movq (%[M]), %%rax \n\t" \
"subq %%rax, (%[tmp]) \n\t"
#define MONT_NEXTSUB(ofs) \
"movq " STR(ofs) "(%[M]), %%rax \n\t" \
"sbbq %%rax, " STR(ofs) "(%[tmp]) \n\t"
/*
The x86-64 Montgomery multiplication here is similar
to Algorithm 2 (CIOS method) in http://eprint.iacr.org/2012/140.pdf
and the PowerPC pseudocode of gmp-ecm library (c) Paul Zimmermann and Alexander Kruppa
(see comments on top of powerpc64/mulredc.m4).
*/
#define MONT_PRECOMPUTE \
"xorq %[cy], %[cy] \n\t" \
"movq 0(%[A]), %%rax \n\t" \
"mulq 0(%[B]) \n\t" \
"movq %%rax, %[T0] \n\t" \
"movq %%rdx, %[T1] # T1:T0 <- A[0] * B[0] \n\t" \
"mulq %[inv] \n\t" \
"movq %%rax, %[u] # u <- T0 * inv \n\t" \
"mulq 0(%[M]) \n\t" \
"addq %[T0], %%rax \n\t" \
"adcq %%rdx, %[T1] \n\t" \
"adcq $0, %[cy] # cy:T1 <- (M[0]*u + T1 * b + T0) / b\n\t"
#define MONT_FIRSTITER(j) \
"xorq %[T0], %[T0] \n\t" \
"movq 0(%[A]), %%rax \n\t" \
"mulq " STR((j*8)) "(%[B]) \n\t" \
"addq %[T1], %%rax \n\t" \
"movq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \
"adcq $0, %%rdx \n\t" \
"movq %%rdx, %[T1] # now T1:tmp[j-1] <-- X[0] * Y[j] + T1\n\t" \
"movq " STR((j*8)) "(%[M]), %%rax \n\t" \
"mulq %[u] \n\t" \
"addq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \
"adcq %[cy], %%rdx \n\t" \
"adcq $0, %[T0] \n\t" \
"xorq %[cy], %[cy] \n\t" \
"addq %%rdx, %[T1] \n\t" \
"adcq %[T0], %[cy] # cy:T1:tmp[j-1] <---- (X[0] * Y[j] + T1) + (M[j] * u + cy * b) \n\t"
#define MONT_ITERFIRST(i) \
"xorq %[cy], %[cy] \n\t" \
"movq " STR((i*8)) "(%[A]), %%rax \n\t" \
"mulq 0(%[B]) \n\t" \
"addq 0(%[tmp]), %%rax \n\t" \
"adcq 8(%[tmp]), %%rdx \n\t" \
"adcq $0, %[cy] \n\t" \
"movq %%rax, %[T0] \n\t" \
"movq %%rdx, %[T1] # cy:T1:T0 <- A[i] * B[0] + tmp[1] * b + tmp[0]\n\t" \
"mulq %[inv] \n\t" \
"movq %%rax, %[u] # u <- T0 * inv\n\t" \
"mulq 0(%[M]) \n\t" \
"addq %[T0], %%rax \n\t" \
"adcq %%rdx, %[T1] \n\t" \
"adcq $0, %[cy] # cy:T1 <- (M[0]*u + cy * b * b + T1 * b + T0) / b\n\t"
#define MONT_ITERITER(i, j) \
"xorq %[T0], %[T0] \n\t" \
"movq " STR((i*8)) "(%[A]), %%rax \n\t" \
"mulq " STR((j*8)) "(%[B]) \n\t" \
"addq %[T1], %%rax \n\t" \
"movq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \
"adcq $0, %%rdx \n\t" \
"movq %%rdx, %[T1] # now T1:tmp[j-1] <-- X[i] * Y[j] + T1 \n\t" \
"movq " STR((j*8)) "(%[M]), %%rax \n\t" \
"mulq %[u] \n\t" \
"addq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \
"adcq %[cy], %%rdx \n\t" \
"adcq $0, %[T0] \n\t" \
"xorq %[cy], %[cy] \n\t" \
"addq %%rdx, %[T1] \n\t" \
"adcq %[T0], %[cy] # cy:T1:tmp[j-1] <-- (X[i] * Y[j] + T1) + M[j] * u + cy * b \n\t" \
"addq " STR(((j+1)*8)) "(%[tmp]), %[T1] \n\t" \
"adcq $0, %[cy] # cy:T1:tmp[j-1] <-- (X[i] * Y[j] + T1) + M[j] * u + (tmp[j+1] + cy) * b \n\t"
#define MONT_FINALIZE(j) \
"movq %[T1], " STR((j*8)) "(%[tmp]) \n\t" \
"movq %[cy], " STR(((j+1)*8)) "(%[tmp]) \n\t"
/*
Comba multiplication and squaring routines are based on the
public-domain tomsfastmath library by Tom St Denis
<http://www.libtom.org/>
<https://github.com/libtom/tomsfastmath/blob/master/src/sqr/fp_sqr_comba.c
<https://github.com/libtom/tomsfastmath/blob/master/src/mul/fp_mul_comba.c>
Compared to the above, we save 5-20% of cycles by using careful register
renaming to implement Comba forward operation.
*/
#define COMBA_3_BY_3_MUL(c0_, c1_, c2_, res_, A_, B_) \
asm volatile ( \
"movq 0(%[A]), %%rax \n\t" \
"mulq 0(%[B]) \n\t" \
"movq %%rax, 0(%[res]) \n\t" \
"movq %%rdx, %[c0] \n\t" \
\
"xorq %[c1], %[c1] \n\t" \
"movq 0(%[A]), %%rax \n\t" \
"mulq 8(%[B]) \n\t" \
"addq %%rax, %[c0] \n\t" \
"adcq %%rdx, %[c1] \n\t" \
\
"xorq %[c2], %[c2] \n\t" \
"movq 8(%[A]), %%rax \n\t" \
"mulq 0(%[B]) \n\t" \
"addq %%rax, %[c0] \n\t" \
"movq %[c0], 8(%[res]) \n\t" \
"adcq %%rdx, %[c1] \n\t" \
"adcq $0, %[c2] \n\t" \
\
"// register renaming (c1, c2, c0)\n\t" \
"xorq %[c0], %[c0] \n\t" \
"movq 0(%[A]), %%rax \n\t" \
"mulq 16(%[B]) \n\t" \
"addq %%rax, %[c1] \n\t" \
"adcq %%rdx, %[c2] \n\t" \
"adcq $0, %[c0] \n\t" \
\
"movq 8(%[A]), %%rax \n\t" \
"mulq 8(%[B]) \n\t" \
"addq %%rax, %[c1] \n\t" \
"adcq %%rdx, %[c2] \n\t" \
"adcq $0, %[c0] \n\t" \
\
"movq 16(%[A]), %%rax \n\t" \
"mulq 0(%[B]) \n\t" \
"addq %%rax, %[c1] \n\t" \
"movq %[c1], 16(%[res]) \n\t" \
"adcq %%rdx, %[c2] \n\t" \
"adcq $0, %[c0] \n\t" \
\
"// register renaming (c2, c0, c1)\n\t" \
"xorq %[c1], %[c1] \n\t" \
"movq 8(%[A]), %%rax \n\t" \
"mulq 16(%[B]) \n\t" \
"addq %%rax, %[c2] \n\t" \
"adcq %%rdx, %[c0] \n\t" \
"adcq $0, %[c1] \n\t" \
\
"movq 16(%[A]), %%rax \n\t" \
"mulq 8(%[B]) \n\t" \
"addq %%rax, %[c2] \n\t" \
"movq %[c2], 24(%[res]) \n\t" \
"adcq %%rdx, %[c0] \n\t" \
"adcq $0, %[c1] \n\t" \
\
"// register renaming (c0, c1, c2)\n\t" \
"xorq %[c2], %[c2] \n\t" \
"movq 16(%[A]), %%rax \n\t" \
"mulq 16(%[B]) \n\t" \
"addq %%rax, %[c0] \n\t" \
"movq %[c0], 32(%[res]) \n\t" \
"adcq %%rdx, %[c1] \n\t" \
"movq %[c1], 40(%[res]) \n\t" \
: [c0] "=&r" (c0_), [c1] "=&r" (c1_), [c2] "=&r" (c2_) \
: [res] "r" (res_), [A] "r" (A_), [B] "r" (B_) \
: "%rax", "%rdx", "cc", "memory")
#define COMBA_3_BY_3_SQR(c0_, c1_, c2_, res_, A_) \
asm volatile ( \
"xorq %[c1], %[c1] \n\t" \
"xorq %[c2], %[c2] \n\t" \
"movq 0(%[A]), %%rax \n\t" \
"mulq %%rax \n\t" \
"movq %%rax, 0(%[res]) \n\t" \
"movq %%rdx, %[c0] \n\t" \
\
"movq 0(%[A]), %%rax \n\t" \
"mulq 8(%[A]) \n\t" \
"addq %%rax, %[c0] \n\t" \
"adcq %%rdx, %[c1] \n\t" \
"addq %%rax, %[c0] \n\t" \
"movq %[c0], 8(%[res]) \n\t" \
"adcq %%rdx, %[c1] \n\t" \
"adcq $0, %[c2] \n\t" \
\
"// register renaming (c1, c2, c0)\n\t" \
"movq 0(%[A]), %%rax \n\t" \
"xorq %[c0], %[c0] \n\t" \
"mulq 16(%[A]) \n\t" \
"addq %%rax, %[c1] \n\t" \
"adcq %%rdx, %[c2] \n\t" \
"adcq $0, %[c0] \n\t" \
"addq %%rax, %[c1] \n\t" \
"adcq %%rdx, %[c2] \n\t" \
"adcq $0, %[c0] \n\t" \
\
"movq 8(%[A]), %%rax \n\t" \
"mulq %%rax \n\t" \
"addq %%rax, %[c1] \n\t" \
"movq %[c1], 16(%[res]) \n\t" \
"adcq %%rdx, %[c2] \n\t" \
"adcq $0, %[c0] \n\t" \
\
"// register renaming (c2, c0, c1)\n\t" \
"movq 8(%[A]), %%rax \n\t" \
"xorq %[c1], %[c1] \n\t" \
"mulq 16(%[A]) \n\t" \
"addq %%rax, %[c2] \n\t" \
"adcq %%rdx, %[c0] \n\t" \
"adcq $0, %[c1] \n\t" \
"addq %%rax, %[c2] \n\t" \
"movq %[c2], 24(%[res]) \n\t" \
"adcq %%rdx, %[c0] \n\t" \
"adcq $0, %[c1] \n\t" \
\
"// register renaming (c0, c1, c2)\n\t" \
"movq 16(%[A]), %%rax \n\t" \
"mulq %%rax \n\t" \
"addq %%rax, %[c0] \n\t" \
"movq %[c0], 32(%[res]) \n\t" \
"adcq %%rdx, %[c1] \n\t" \
"movq %[c1], 40(%[res]) \n\t" \
\
: [c0] "=&r" (c0_), [c1] "=&r" (c1_), [c2] "=&r" (c2_) \
: [res] "r" (res_), [A] "r" (A_) \
: "%rax", "%rdx", "cc", "memory")
/*
The Montgomery reduction here is based on Algorithm 14.32 in
Handbook of Applied Cryptography
<http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
*/
#define REDUCE_6_LIMB_PRODUCT(k_, tmp1_, tmp2_, tmp3_, inv_, res_, mod_) \
__asm__ volatile \
("///////////////////////////////////\n\t" \
"movq 0(%[res]), %%rax \n\t" \
"mulq %[modprime] \n\t" \
"movq %%rax, %[k] \n\t" \
\
"movq (%[mod]), %%rax \n\t" \
"mulq %[k] \n\t" \
"movq %%rax, %[tmp1] \n\t" \
"movq %%rdx, %[tmp2] \n\t" \
\
"xorq %[tmp3], %[tmp3] \n\t" \
"movq 8(%[mod]), %%rax \n\t" \
"mulq %[k] \n\t" \
"addq %[tmp1], 0(%[res]) \n\t" \
"adcq %%rax, %[tmp2] \n\t" \
"adcq %%rdx, %[tmp3] \n\t" \
\
"xorq %[tmp1], %[tmp1] \n\t" \
"movq 16(%[mod]), %%rax \n\t" \
"mulq %[k] \n\t" \
"addq %[tmp2], 8(%[res]) \n\t" \
"adcq %%rax, %[tmp3] \n\t" \
"adcq %%rdx, %[tmp1] \n\t" \
\
"addq %[tmp3], 16(%[res]) \n\t" \
"adcq %[tmp1], 24(%[res]) \n\t" \
"adcq $0, 32(%[res]) \n\t" \
"adcq $0, 40(%[res]) \n\t" \
\
"///////////////////////////////////\n\t" \
"movq 8(%[res]), %%rax \n\t" \
"mulq %[modprime] \n\t" \
"movq %%rax, %[k] \n\t" \
\
"movq (%[mod]), %%rax \n\t" \
"mulq %[k] \n\t" \
"movq %%rax, %[tmp1] \n\t" \
"movq %%rdx, %[tmp2] \n\t" \
\
"xorq %[tmp3], %[tmp3] \n\t" \
"movq 8(%[mod]), %%rax \n\t" \
"mulq %[k] \n\t" \
"addq %[tmp1], 8(%[res]) \n\t" \
"adcq %%rax, %[tmp2] \n\t" \
"adcq %%rdx, %[tmp3] \n\t" \
\
"xorq %[tmp1], %[tmp1] \n\t" \
"movq 16(%[mod]), %%rax \n\t" \
"mulq %[k] \n\t" \
"addq %[tmp2], 16(%[res]) \n\t" \
"adcq %%rax, %[tmp3] \n\t" \
"adcq %%rdx, %[tmp1] \n\t" \
\
"addq %[tmp3], 24(%[res]) \n\t" \
"adcq %[tmp1], 32(%[res]) \n\t" \
"adcq $0, 40(%[res]) \n\t" \
\
"///////////////////////////////////\n\t" \
"movq 16(%[res]), %%rax \n\t" \
"mulq %[modprime] \n\t" \
"movq %%rax, %[k] \n\t" \
\
"movq (%[mod]), %%rax \n\t" \
"mulq %[k] \n\t" \
"movq %%rax, %[tmp1] \n\t" \
"movq %%rdx, %[tmp2] \n\t" \
\
"xorq %[tmp3], %[tmp3] \n\t" \
"movq 8(%[mod]), %%rax \n\t" \
"mulq %[k] \n\t" \
"addq %[tmp1], 16(%[res]) \n\t" \
"adcq %%rax, %[tmp2] \n\t" \
"adcq %%rdx, %[tmp3] \n\t" \
\
"xorq %[tmp1], %[tmp1] \n\t" \
"movq 16(%[mod]), %%rax \n\t" \
"mulq %[k] \n\t" \
"addq %[tmp2], 24(%[res]) \n\t" \
"adcq %%rax, %[tmp3] \n\t" \
"adcq %%rdx, %[tmp1] \n\t" \
\
"addq %[tmp3], 32(%[res]) \n\t" \
"adcq %[tmp1], 40(%[res]) \n\t" \
: [k] "=&r" (k_), [tmp1] "=&r" (tmp1_), [tmp2] "=&r" (tmp2_), [tmp3] "=&r" (tmp3_) \
: [modprime] "r" (inv_), [res] "r" (res_), [mod] "r" (mod_) \
: "%rax", "%rdx", "cc", "memory")
} // libsnark
#endif // FP_AUX_TCC_

106
src/snark/libsnark/algebra/fields/tests/test_bigint.cpp

@ -1,106 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "algebra/fields/bigint.hpp"
using namespace libsnark;
void test_bigint()
{
static_assert(GMP_NUMB_BITS == 64, "GMP limb not 64-bit");
const char *b1_decimal = "76749407";
const char *b2_decimal = "435020359732196472065729437602";
const char *b3_decimal = "33387554642372758038536799358397002014";
const char *b2_binary = "0000000000000000000000000000010101111101101000000110100001011010"
"1101101010001001000001101000101000100110011001110001111110100010";
bigint<1> b0 = bigint<1>(UINT64_C(0));
bigint<1> b1 = bigint<1>(b1_decimal);
bigint<2> b2 = bigint<2>(b2_decimal);
EXPECT_EQ(b0.as_uint64(), UINT64_C(0));
EXPECT_TRUE(b0.is_zero());
EXPECT_EQ(b1.as_uint64(), UINT64_C(76749407));
EXPECT_FALSE(b1.is_zero());
EXPECT_EQ(b2.as_uint64(), UINT64_C(15747124762497195938));
EXPECT_FALSE(b2.is_zero());
EXPECT_NE(b0, b1);
EXPECT_FALSE(b0 == b1);
EXPECT_EQ(b2.max_bits(), 128u);
EXPECT_EQ(b2.num_bits(), 99u);
for (size_t i = 0; i < 128; i++) {
assert(b2.test_bit(i) == (b2_binary[127-i] == '1'));
}
bigint<3> b3 = b2 * b1;
assert(b3 == bigint<3>(b3_decimal));
assert(!(b3.is_zero()));
bigint<3> b3a { b3 };
assert(b3a == bigint<3>(b3_decimal));
assert(b3a == b3);
assert(!(b3a.is_zero()));
mpz_t m3;
mpz_init(m3);
b3.to_mpz(m3);
bigint<3> b3b { m3 };
assert(b3b == b3);
bigint<2> quotient;
bigint<2> remainder;
bigint<3>::div_qr(quotient, remainder, b3, b2);
EXPECT_LT(quotient.num_bits(), static_cast<size_t>(GMP_NUMB_BITS));
EXPECT_EQ(quotient.as_uint64(), b1.as_uint64());
bigint<1> b1inc = bigint<1>("76749408");
bigint<1> b1a = quotient.shorten(b1inc, "test");
assert(b1a == b1);
assert(remainder.is_zero());
remainder.limit(b2, "test");
try {
(void)(quotient.shorten(b1, "test"));
assert(false);
} catch (std::domain_error) {}
try {
remainder.limit(remainder, "test");
assert(false);
} catch (std::domain_error) {}
bigint<1> br = bigint<1>("42");
b3 += br;
assert(b3 != b3a);
assert(b3 > b3a);
assert(!(b3a > b3));
bigint<3>::div_qr(quotient, remainder, b3, b2);
EXPECT_LT(quotient.num_bits(), static_cast<size_t>(GMP_NUMB_BITS));
EXPECT_EQ(quotient.as_uint64(), b1.as_uint64());
EXPECT_LT(remainder.num_bits(), static_cast<size_t>(GMP_NUMB_BITS));
EXPECT_EQ(remainder.as_uint64(), 42u);
b3a.clear();
EXPECT_TRUE(b3a.is_zero());
EXPECT_EQ(b3a.num_bits(), 0u);
EXPECT_FALSE(b3.is_zero());
bigint<4> bx = bigint<4>().randomize();
bigint<4> by = bigint<4>().randomize();
assert(!(bx == by));
// TODO: test serialization
}
int main(void)
{
test_bigint();
return 0;
}

245
src/snark/libsnark/algebra/fields/tests/test_fields.cpp

@ -1,245 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "common/profiling.hpp"
#include "algebra/curves/edwards/edwards_pp.hpp"
#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp"
#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp"
#ifdef CURVE_BN128
#include "algebra/curves/bn128/bn128_pp.hpp"
#endif
#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp"
#include "algebra/fields/fp6_3over2.hpp"
#include "algebra/fields/fp12_2over3over2.hpp"
using namespace libsnark;
template<typename FieldT>
void test_field()
{
bigint<1> rand1 = bigint<1>("76749407");
bigint<1> rand2 = bigint<1>("44410867");
bigint<1> randsum = bigint<1>("121160274");
FieldT zero = FieldT::zero();
FieldT one = FieldT::one();
FieldT a = FieldT::random_element();
FieldT a_ser;
a_ser = reserialize<FieldT>(a);
assert(a_ser == a);
FieldT b = FieldT::random_element();
FieldT c = FieldT::random_element();
FieldT d = FieldT::random_element();
assert(a != zero);
assert(a != one);
assert(a * a == a.squared());
assert((a + b).squared() == a.squared() + a*b + b*a + b.squared());
assert((a + b)*(c + d) == a*c + a*d + b*c + b*d);
assert(a - b == a + (-b));
assert(a - b == (-b) + a);
assert((a ^ rand1) * (a ^ rand2) == (a^randsum));
assert(a * a.inverse() == one);
assert((a + b) * c.inverse() == a * c.inverse() + (b.inverse() * c).inverse());
}
template<typename FieldT>
void test_sqrt()
{
for (size_t i = 0; i < 100; ++i)
{
FieldT a = FieldT::random_element();
FieldT asq = a.squared();
assert(asq.sqrt() == a || asq.sqrt() == -a);
}
}
template<typename FieldT>
void test_two_squarings()
{
FieldT a = FieldT::random_element();
assert(a.squared() == a * a);
assert(a.squared() == a.squared_complex());
assert(a.squared() == a.squared_karatsuba());
}
template<typename FieldT>
void test_Frobenius()
{
FieldT a = FieldT::random_element();
assert(a.Frobenius_map(0) == a);
FieldT a_q = a ^ FieldT::base_field_char();
for (size_t power = 1; power < 10; ++power)
{
const FieldT a_qi = a.Frobenius_map(power);
assert(a_qi == a_q);
a_q = a_q ^ FieldT::base_field_char();
}
}
template<typename FieldT>
void test_unitary_inverse()
{
EXPECT_EQ(FieldT::extension_degree() % 2, 0u);
FieldT a = FieldT::random_element();
FieldT aqcubed_minus1 = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse();
assert(aqcubed_minus1.inverse() == aqcubed_minus1.unitary_inverse());
}
template<typename FieldT>
void test_cyclotomic_squaring();
template<>
void test_cyclotomic_squaring<Fqk<edwards_pp> >()
{
typedef Fqk<edwards_pp> FieldT;
assert(FieldT::extension_degree() % 2 == 0);
FieldT a = FieldT::random_element();
FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse();
// beta = a^((q^(k/2)-1)*(q+1))
FieldT beta = a_unitary.Frobenius_map(1) * a_unitary;
assert(beta.cyclotomic_squared() == beta.squared());
}
template<>
void test_cyclotomic_squaring<Fqk<mnt4_pp> >()
{
typedef Fqk<mnt4_pp> FieldT;
assert(FieldT::extension_degree() % 2 == 0);
FieldT a = FieldT::random_element();
FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse();
// beta = a^(q^(k/2)-1)
FieldT beta = a_unitary;
assert(beta.cyclotomic_squared() == beta.squared());
}
template<>
void test_cyclotomic_squaring<Fqk<mnt6_pp> >()
{
typedef Fqk<mnt6_pp> FieldT;
assert(FieldT::extension_degree() % 2 == 0);
FieldT a = FieldT::random_element();
FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse();
// beta = a^((q^(k/2)-1)*(q+1))
FieldT beta = a_unitary.Frobenius_map(1) * a_unitary;
assert(beta.cyclotomic_squared() == beta.squared());
}
template<typename ppT>
void test_all_fields()
{
test_field<Fr<ppT> >();
test_field<Fq<ppT> >();
test_field<Fqe<ppT> >();
test_field<Fqk<ppT> >();
test_sqrt<Fr<ppT> >();
test_sqrt<Fq<ppT> >();
test_sqrt<Fqe<ppT> >();
test_Frobenius<Fqe<ppT> >();
test_Frobenius<Fqk<ppT> >();
test_unitary_inverse<Fqk<ppT> >();
}
template<typename Fp4T>
void test_Fp4_tom_cook()
{
typedef typename Fp4T::my_Fp FieldT;
for (size_t i = 0; i < 100; ++i)
{
const Fp4T a = Fp4T::random_element();
const Fp4T b = Fp4T::random_element();
const Fp4T correct_res = a * b;
Fp4T res;
const FieldT
&a0 = a.c0.c0,
&a1 = a.c1.c0,
&a2 = a.c0.c1,
&a3 = a.c1.c1;
const FieldT
&b0 = b.c0.c0,
&b1 = b.c1.c0,
&b2 = b.c0.c1,
&b3 = b.c1.c1;
FieldT
&c0 = res.c0.c0,
&c1 = res.c1.c0,
&c2 = res.c0.c1,
&c3 = res.c1.c1;
const FieldT v0 = a0 * b0;
const FieldT v1 = (a0 + a1 + a2 + a3) * (b0 + b1 + b2 + b3);
const FieldT v2 = (a0 - a1 + a2 - a3) * (b0 - b1 + b2 - b3);
const FieldT v3 = (a0 + FieldT(2)*a1 + FieldT(4)*a2 + FieldT(8)*a3) * (b0 + FieldT(2)*b1 + FieldT(4)*b2 + FieldT(8)*b3);
const FieldT v4 = (a0 - FieldT(2)*a1 + FieldT(4)*a2 - FieldT(8)*a3) * (b0 - FieldT(2)*b1 + FieldT(4)*b2 - FieldT(8)*b3);
const FieldT v5 = (a0 + FieldT(3)*a1 + FieldT(9)*a2 + FieldT(27)*a3) * (b0 + FieldT(3)*b1 + FieldT(9)*b2 + FieldT(27)*b3);
const FieldT v6 = a3 * b3;
const FieldT beta = Fp4T::non_residue;
c0 = v0 + beta*(FieldT(4).inverse()*v0 - FieldT(6).inverse()*(v1 + v2) + FieldT(24).inverse() * (v3 + v4) - FieldT(5) * v6);
c1 = - FieldT(3).inverse()*v0 + v1 - FieldT(2).inverse()*v2 - FieldT(4).inverse()*v3 + FieldT(20).inverse() * v4 + FieldT(30).inverse() * v5 - FieldT(12) * v6 + beta * ( - FieldT(12).inverse() * (v0 - v1) + FieldT(24).inverse()*(v2 - v3) - FieldT(120).inverse() * (v4 - v5) - FieldT(3) * v6);
c2 = - (FieldT(5)*(FieldT(4).inverse()))* v0 + (FieldT(2)*(FieldT(3).inverse()))*(v1 + v2) - FieldT(24).inverse()*(v3 + v4) + FieldT(4)*v6 + beta*v6;
c3 = FieldT(12).inverse() * (FieldT(5)*v0 - FieldT(7)*v1) - FieldT(24).inverse()*(v2 - FieldT(7)*v3 + v4 + v5) + FieldT(15)*v6;
assert(res == correct_res);
// {v0, v3, v4, v5}
const FieldT u = (FieldT::one() - beta).inverse();
assert(v0 == u * c0 + beta * u * c2 - beta * u * FieldT(2).inverse() * v1 - beta * u * FieldT(2).inverse() * v2 + beta * v6);
assert(v3 == - FieldT(15) * u * c0 - FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 - FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v1 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v2
- FieldT(3) * (-FieldT(16) + beta) * v6);
assert(v4 == - FieldT(15) * u * c0 + FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 + FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v2 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v1
- FieldT(3) * (-FieldT(16) + beta) * v6);
assert(v5 == - FieldT(80) * u * c0 - FieldT(240) * u * c1 - FieldT(8) * (FieldT(9) + beta) * u * c2 - FieldT(24) * (FieldT(9) + beta) * u * c3 - FieldT(2) * (-FieldT(81) + beta) * u * v1 + (-FieldT(81) + beta) * u * v2
- FieldT(8) * (-FieldT(81) + beta) * v6);
// c0 + beta c2 - (beta v1)/2 - (beta v2)/ 2 - (-1 + beta) beta v6,
// -15 c0 - 30 c1 - 3 (4 + beta) c2 - 6 (4 + beta) c3 + (24 - (3 beta)/2) v1 + (-8 + beta/2) v2 + 3 (-16 + beta) (-1 + beta) v6,
// -15 c0 + 30 c1 - 3 (4 + beta) c2 + 6 (4 + beta) c3 + (-8 + beta/2) v1 + (24 - (3 beta)/2) v2 + 3 (-16 + beta) (-1 + beta) v6,
// -80 c0 - 240 c1 - 8 (9 + beta) c2 - 24 (9 + beta) c3 - 2 (-81 + beta) v1 + (-81 + beta) v2 + 8 (-81 + beta) (-1 + beta) v6
}
}
int main(void)
{
edwards_pp::init_public_params();
test_all_fields<edwards_pp>();
test_cyclotomic_squaring<Fqk<edwards_pp> >();
mnt4_pp::init_public_params();
test_all_fields<mnt4_pp>();
test_Fp4_tom_cook<mnt4_Fq4>();
test_two_squarings<Fqe<mnt4_pp> >();
test_cyclotomic_squaring<Fqk<mnt4_pp> >();
mnt6_pp::init_public_params();
test_all_fields<mnt6_pp>();
test_cyclotomic_squaring<Fqk<mnt6_pp> >();
alt_bn128_pp::init_public_params();
test_field<alt_bn128_Fq6>();
test_Frobenius<alt_bn128_Fq6>();
test_all_fields<alt_bn128_pp>();
#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled
bn128_pp::init_public_params();
test_field<Fr<bn128_pp> >();
test_field<Fq<bn128_pp> >();
#endif
}

84
src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.hpp

@ -1,84 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for:
- a knowledge commitment, and
- a knowledge commitment vector.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef KNOWLEDGE_COMMITMENT_HPP_
#define KNOWLEDGE_COMMITMENT_HPP_
#include "algebra/fields/fp.hpp"
#include "common/data_structures/sparse_vector.hpp"
namespace libsnark {
/********************** Knowledge commitment *********************************/
/**
* A knowledge commitment is a pair (g,h) where g is in T1 and h in T2,
* and T1 and T2 are groups (written additively).
*
* Such pairs form a group by defining:
* - "zero" = (0,0)
* - "one" = (1,1)
* - a * (g,h) + b * (g',h') := ( a * g + b * g', a * h + b * h').
*/
template<typename T1, typename T2>
struct knowledge_commitment {
T1 g;
T2 h;
knowledge_commitment<T1,T2>() = default;
knowledge_commitment<T1,T2>(const knowledge_commitment<T1,T2> &other) = default;
knowledge_commitment<T1,T2>(knowledge_commitment<T1,T2> &&other) = default;
knowledge_commitment<T1,T2>(const T1 &g, const T2 &h);
knowledge_commitment<T1,T2>& operator=(const knowledge_commitment<T1,T2> &other) = default;
knowledge_commitment<T1,T2>& operator=(knowledge_commitment<T1,T2> &&other) = default;
knowledge_commitment<T1,T2> operator+(const knowledge_commitment<T1, T2> &other) const;
bool is_zero() const;
bool operator==(const knowledge_commitment<T1,T2> &other) const;
bool operator!=(const knowledge_commitment<T1,T2> &other) const;
static knowledge_commitment<T1,T2> zero();
static knowledge_commitment<T1,T2> one();
void print() const;
static size_t size_in_bits();
};
template<typename T1, typename T2, mp_size_t m>
knowledge_commitment<T1,T2> operator*(const bigint<m> &lhs, const knowledge_commitment<T1,T2> &rhs);
template<typename T1, typename T2, mp_size_t m, const bigint<m> &modulus_p>
knowledge_commitment<T1,T2> operator*(const Fp_model<m, modulus_p> &lhs, const knowledge_commitment<T1,T2> &rhs);
template<typename T1,typename T2>
std::ostream& operator<<(std::ostream& out, const knowledge_commitment<T1,T2> &kc);
template<typename T1,typename T2>
std::istream& operator>>(std::istream& in, knowledge_commitment<T1,T2> &kc);
/******************** Knowledge commitment vector ****************************/
/**
* A knowledge commitment vector is a sparse vector of knowledge commitments.
*/
template<typename T1, typename T2>
using knowledge_commitment_vector = sparse_vector<knowledge_commitment<T1, T2> >;
} // libsnark
#include "algebra/knowledge_commitment/knowledge_commitment.tcc"
#endif // KNOWLEDGE_COMMITMENT_HPP_

111
src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.tcc

@ -1,111 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for:
- a knowledge commitment, and
- a knowledge commitment vector.
See knowledge_commitment.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef KNOWLEDGE_COMMITMENT_TCC_
#define KNOWLEDGE_COMMITMENT_TCC_
namespace libsnark {
template<typename T1, typename T2>
knowledge_commitment<T1,T2>::knowledge_commitment(const T1 &g, const T2 &h) :
g(g), h(h)
{
}
template<typename T1, typename T2>
knowledge_commitment<T1,T2> knowledge_commitment<T1,T2>::zero()
{
return knowledge_commitment<T1,T2>(T1::zero(), T2::zero());
}
template<typename T1, typename T2>
knowledge_commitment<T1,T2> knowledge_commitment<T1,T2>::one()
{
return knowledge_commitment<T1,T2>(T1::one(), T2::one());
}
template<typename T1, typename T2>
knowledge_commitment<T1,T2> knowledge_commitment<T1,T2>::operator+(const knowledge_commitment<T1,T2> &other) const
{
return knowledge_commitment<T1,T2>(this->g + other.g,
this->h + other.h);
}
template<typename T1, typename T2>
bool knowledge_commitment<T1,T2>::is_zero() const
{
return (g.is_zero() && h.is_zero());
}
template<typename T1, typename T2>
bool knowledge_commitment<T1,T2>::operator==(const knowledge_commitment<T1,T2> &other) const
{
return (this->g == other.g &&
this->h == other.h);
}
template<typename T1, typename T2>
bool knowledge_commitment<T1,T2>::operator!=(const knowledge_commitment<T1,T2> &other) const
{
return !((*this) == other);
}
template<typename T1, typename T2, mp_size_t m>
knowledge_commitment<T1,T2> operator*(const bigint<m> &lhs, const knowledge_commitment<T1,T2> &rhs)
{
return knowledge_commitment<T1,T2>(lhs * rhs.g,
lhs * rhs.h);
}
template<typename T1, typename T2, mp_size_t m, const bigint<m> &modulus_p>
knowledge_commitment<T1,T2> operator*(const Fp_model<m, modulus_p> &lhs, const knowledge_commitment<T1,T2> &rhs)
{
return (lhs.as_bigint()) * rhs;
}
template<typename T1, typename T2>
void knowledge_commitment<T1,T2>::print() const
{
printf("knowledge_commitment.g:\n");
g.print();
printf("knowledge_commitment.h:\n");
h.print();
}
template<typename T1, typename T2>
size_t knowledge_commitment<T1,T2>::size_in_bits()
{
return T1::size_in_bits() + T2::size_in_bits();
}
template<typename T1,typename T2>
std::ostream& operator<<(std::ostream& out, const knowledge_commitment<T1,T2> &kc)
{
out << kc.g << OUTPUT_SEPARATOR << kc.h;
return out;
}
template<typename T1,typename T2>
std::istream& operator>>(std::istream& in, knowledge_commitment<T1,T2> &kc)
{
in >> kc.g;
consume_OUTPUT_SEPARATOR(in);
in >> kc.h;
return in;
}
} // libsnark
#endif // KNOWLEDGE_COMMITMENT_TCC_

55
src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.hpp

@ -1,55 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef KC_MULTIEXP_HPP_
#define KC_MULTIEXP_HPP_
/*
Split out from multiexp to prevent cyclical
dependencies. I.e. previously multiexp dependend on
knowledge_commitment, which dependend on sparse_vector, which
dependend on multiexp (to do accumulate).
Will probably go away in more general exp refactoring.
*/
#include "algebra/knowledge_commitment/knowledge_commitment.hpp"
namespace libsnark {
template<typename T1, typename T2, mp_size_t n>
knowledge_commitment<T1,T2> opt_window_wnaf_exp(const knowledge_commitment<T1,T2> &base,
const bigint<n> &scalar, const size_t scalar_bits);
template<typename T1, typename T2, typename FieldT>
knowledge_commitment<T1, T2> kc_multi_exp_with_mixed_addition(const knowledge_commitment_vector<T1, T2> &vec,
const size_t min_idx,
const size_t max_idx,
typename std::vector<FieldT>::const_iterator scalar_start,
typename std::vector<FieldT>::const_iterator scalar_end,
const size_t chunks,
const bool use_multiexp=false);
template<typename T1, typename T2>
void kc_batch_to_special(std::vector<knowledge_commitment<T1, T2> > &vec);
template<typename T1, typename T2, typename FieldT>
knowledge_commitment_vector<T1, T2> kc_batch_exp(const size_t scalar_size,
const size_t T1_window,
const size_t T2_window,
const window_table<T1> &T1_table,
const window_table<T2> &T2_table,
const FieldT &T1_coeff,
const FieldT &T2_coeff,
const std::vector<FieldT> &v,
const size_t suggested_num_chunks);
} // libsnark
#include "algebra/scalar_multiplication/kc_multiexp.tcc"
#endif // KC_MULTIEXP_HPP_

276
src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.tcc

@ -1,276 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef KC_MULTIEXP_TCC_
#define KC_MULTIEXP_TCC_
#include "common/assert_except.hpp"
namespace libsnark {
template<typename T1, typename T2, mp_size_t n>
knowledge_commitment<T1,T2> opt_window_wnaf_exp(const knowledge_commitment<T1,T2> &base,
const bigint<n> &scalar, const size_t scalar_bits)
{
return knowledge_commitment<T1,T2>(opt_window_wnaf_exp(base.g, scalar, scalar_bits),
opt_window_wnaf_exp(base.h, scalar, scalar_bits));
}
template<typename T1, typename T2, typename FieldT>
knowledge_commitment<T1, T2> kc_multi_exp_with_mixed_addition(const knowledge_commitment_vector<T1, T2> &vec,
const size_t min_idx,
const size_t max_idx,
typename std::vector<FieldT>::const_iterator scalar_start,
typename std::vector<FieldT>::const_iterator scalar_end,
const size_t chunks,
const bool use_multiexp)
{
enter_block("Process scalar vector");
auto index_it = std::lower_bound(vec.indices.begin(), vec.indices.end(), min_idx);
const size_t offset = index_it - vec.indices.begin();
auto value_it = vec.values.begin() + offset;
const FieldT zero = FieldT::zero();
const FieldT one = FieldT::one();
std::vector<FieldT> p;
std::vector<knowledge_commitment<T1, T2> > g;
knowledge_commitment<T1, T2> acc = knowledge_commitment<T1, T2>::zero();
size_t num_skip = 0;
size_t num_add = 0;
size_t num_other = 0;
const size_t scalar_length = std::distance(scalar_start, scalar_end);
while (index_it != vec.indices.end() && *index_it < max_idx)
{
const size_t scalar_position = (*index_it) - min_idx;
assert_except(scalar_position < scalar_length);
const FieldT scalar = *(scalar_start + scalar_position);
if (scalar == zero)
{
// do nothing
++num_skip;
}
else if (scalar == one)
{
#ifdef USE_MIXED_ADDITION
acc.g = acc.g.mixed_add(value_it->g);
acc.h = acc.h.mixed_add(value_it->h);
#else
acc.g = acc.g + value_it->g;
acc.h = acc.h + value_it->h;
#endif
++num_add;
}
else
{
p.emplace_back(scalar);
g.emplace_back(*value_it);
++num_other;
}
++index_it;
++value_it;
}
//print_indent(); printf("* Elements of w skipped: %zu (%0.2f%%)\n", num_skip, 100.*num_skip/(num_skip+num_add+num_other));
//print_indent(); printf("* Elements of w processed with special addition: %zu (%0.2f%%)\n", num_add, 100.*num_add/(num_skip+num_add+num_other));
//print_indent(); printf("* Elements of w remaining: %zu (%0.2f%%)\n", num_other, 100.*num_other/(num_skip+num_add+num_other));
leave_block("Process scalar vector");
return acc + multi_exp<knowledge_commitment<T1, T2>, FieldT>(g.begin(), g.end(), p.begin(), p.end(), chunks, use_multiexp);
}
template<typename T1, typename T2>
void kc_batch_to_special(std::vector<knowledge_commitment<T1, T2> > &vec)
{
enter_block("Batch-convert knowledge-commitments to special form");
std::vector<T1> g_vec;
g_vec.reserve(vec.size());
for (size_t i = 0; i < vec.size(); ++i)
{
if (!vec[i].g.is_zero())
{
g_vec.emplace_back(vec[i].g);
}
}
batch_to_special_all_non_zeros<T1>(g_vec);
auto g_it = g_vec.begin();
T1 T1_zero_special = T1::zero();
T1_zero_special.to_special();
for (size_t i = 0; i < vec.size(); ++i)
{
if (!vec[i].g.is_zero())
{
vec[i].g = *g_it;
++g_it;
}
else
{
vec[i].g = T1_zero_special;
}
}
g_vec.clear();
std::vector<T2> h_vec;
h_vec.reserve(vec.size());
for (size_t i = 0; i < vec.size(); ++i)
{
if (!vec[i].h.is_zero())
{
h_vec.emplace_back(vec[i].h);
}
}
batch_to_special_all_non_zeros<T2>(h_vec);
auto h_it = h_vec.begin();
T2 T2_zero_special = T2::zero();
T2_zero_special.to_special();
for (size_t i = 0; i < vec.size(); ++i)
{
if (!vec[i].h.is_zero())
{
vec[i].h = *h_it;
++h_it;
}
else
{
vec[i].h = T2_zero_special;
}
}
g_vec.clear();
leave_block("Batch-convert knowledge-commitments to special form");
}
template<typename T1, typename T2, typename FieldT>
knowledge_commitment_vector<T1, T2> kc_batch_exp_internal(const size_t scalar_size,
const size_t T1_window,
const size_t T2_window,
const window_table<T1> &T1_table,
const window_table<T2> &T2_table,
const FieldT &T1_coeff,
const FieldT &T2_coeff,
const std::vector<FieldT> &v,
const size_t start_pos,
const size_t end_pos,
const size_t expected_size)
{
knowledge_commitment_vector<T1, T2> res;
res.values.reserve(expected_size);
res.indices.reserve(expected_size);
for (size_t pos = start_pos; pos != end_pos; ++pos)
{
if (!v[pos].is_zero())
{
res.values.emplace_back(knowledge_commitment<T1, T2>(windowed_exp(scalar_size, T1_window, T1_table, T1_coeff * v[pos]),
windowed_exp(scalar_size, T2_window, T2_table, T2_coeff * v[pos])));
res.indices.emplace_back(pos);
}
}
return res;
}
template<typename T1, typename T2, typename FieldT>
knowledge_commitment_vector<T1, T2> kc_batch_exp(const size_t scalar_size,
const size_t T1_window,
const size_t T2_window,
const window_table<T1> &T1_table,
const window_table<T2> &T2_table,
const FieldT &T1_coeff,
const FieldT &T2_coeff,
const std::vector<FieldT> &v,
const size_t suggested_num_chunks)
{
knowledge_commitment_vector<T1, T2> res;
res.domain_size_ = v.size();
size_t nonzero = 0;
for (size_t i = 0; i < v.size(); ++i)
{
nonzero += (v[i].is_zero() ? 0 : 1);
}
const size_t num_chunks = std::max((size_t)1, std::min(nonzero, suggested_num_chunks));
if (!inhibit_profiling_info)
{
print_indent(); printf("Non-zero coordinate count: %zu/%zu (%0.2f%%)\n", nonzero, v.size(), 100.*nonzero/v.size());
}
std::vector<knowledge_commitment_vector<T1, T2> > tmp(num_chunks);
std::vector<size_t> chunk_pos(num_chunks+1);
const size_t chunk_size = nonzero / num_chunks;
const size_t last_chunk = nonzero - chunk_size * (num_chunks - 1);
chunk_pos[0] = 0;
size_t cnt = 0;
size_t chunkno = 1;
for (size_t i = 0; i < v.size(); ++i)
{
cnt += (v[i].is_zero() ? 0 : 1);
if (cnt == chunk_size && chunkno < num_chunks)
{
chunk_pos[chunkno] = i;
cnt = 0;
++chunkno;
}
}
chunk_pos[num_chunks] = v.size();
#ifdef MULTICORE
#pragma omp parallel for
#endif
for (size_t i = 0; i < num_chunks; ++i)
{
tmp[i] = kc_batch_exp_internal<T1, T2, FieldT>(scalar_size, T1_window, T2_window, T1_table, T2_table, T1_coeff, T2_coeff, v,
chunk_pos[i], chunk_pos[i+1], i == num_chunks - 1 ? last_chunk : chunk_size);
#ifdef USE_MIXED_ADDITION
kc_batch_to_special<T1, T2>(tmp[i].values);
#endif
}
if (num_chunks == 1)
{
tmp[0].domain_size_ = v.size();
return tmp[0];
}
else
{
for (size_t i = 0; i < num_chunks; ++i)
{
res.values.insert(res.values.end(), tmp[i].values.begin(), tmp[i].values.end());
res.indices.insert(res.indices.end(), tmp[i].indices.begin(), tmp[i].indices.end());
}
return res;
}
}
} // libsnark
#endif // KC_MULTIEXP_TCC_

110
src/snark/libsnark/algebra/scalar_multiplication/multiexp.hpp

@ -1,110 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for multi-exponentiation routines.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef MULTIEXP_HPP_
#define MULTIEXP_HPP_
namespace libsnark {
/**
* Naive multi-exponentiation individually multiplies each base by the
* corresponding scalar and adds up the results.
*/
template<typename T, typename FieldT>
T naive_exp(typename std::vector<T>::const_iterator vec_start,
typename std::vector<T>::const_iterator vec_end,
typename std::vector<FieldT>::const_iterator scalar_start,
typename std::vector<FieldT>::const_iterator scalar_end);
template<typename T, typename FieldT>
T naive_plain_exp(typename std::vector<T>::const_iterator vec_start,
typename std::vector<T>::const_iterator vec_end,
typename std::vector<FieldT>::const_iterator scalar_start,
typename std::vector<FieldT>::const_iterator scalar_end);
/**
* Naive multi-exponentiation uses a variant of the Bos-Coster algorithm [1],
* and implementation suggestions from [2].
*
* [1] = Bos and Coster, "Addition chain heuristics", CRYPTO '89
* [2] = Bernstein, Duif, Lange, Schwabe, and Yang, "High-speed high-security signatures", CHES '11
*/
template<typename T, typename FieldT>
T multi_exp(typename std::vector<T>::const_iterator vec_start,
typename std::vector<T>::const_iterator vec_end,
typename std::vector<FieldT>::const_iterator scalar_start,
typename std::vector<FieldT>::const_iterator scalar_end,
const size_t chunks,
const bool use_multiexp=false);
/**
* A variant of multi_exp that takes advantage of the method mixed_add (instead of the operator '+').
*/
template<typename T, typename FieldT>
T multi_exp_with_mixed_addition(typename std::vector<T>::const_iterator vec_start,
typename std::vector<T>::const_iterator vec_end,
typename std::vector<FieldT>::const_iterator scalar_start,
typename std::vector<FieldT>::const_iterator scalar_end,
const size_t chunks,
const bool use_multiexp);
/**
* A window table stores window sizes for different instance sizes for fixed-base multi-scalar multiplications.
*/
template<typename T>
using window_table = std::vector<std::vector<T> >;
/**
* Compute window size for the given number of scalars.
*/
template<typename T>
size_t get_exp_window_size(const size_t num_scalars);
/**
* Compute table of window sizes.
*/
template<typename T>
window_table<T> get_window_table(const size_t scalar_size,
const size_t window,
const T &g);
template<typename T, typename FieldT>
T windowed_exp(const size_t scalar_size,
const size_t window,
const window_table<T> &powers_of_g,
const FieldT &pow);
template<typename T, typename FieldT>
std::vector<T> batch_exp(const size_t scalar_size,
const size_t window,
const window_table<T> &table,
const std::vector<FieldT> &v);
template<typename T, typename FieldT>
std::vector<T> batch_exp_with_coeff(const size_t scalar_size,
const size_t window,
const window_table<T> &table,
const FieldT &coeff,
const std::vector<FieldT> &v);
// defined in every curve
template<typename T>
void batch_to_special_all_non_zeros(std::vector<T> &vec);
template<typename T>
void batch_to_special(std::vector<T> &vec);
} // libsnark
#include "algebra/scalar_multiplication/multiexp.tcc"
#endif // MULTIEXP_HPP_

591
src/snark/libsnark/algebra/scalar_multiplication/multiexp.tcc

@ -1,591 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for multi-exponentiation routines.
See multiexp.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef MULTIEXP_TCC_
#define MULTIEXP_TCC_
#include "algebra/fields/fp_aux.tcc"
#include <algorithm>
#include <cassert>
#include <type_traits>
#include "common/profiling.hpp"
#include "common/utils.hpp"
#include "common/assert_except.hpp"
#include "algebra/scalar_multiplication/wnaf.hpp"
namespace libsnark {
template<mp_size_t n>
class ordered_exponent {
// to use std::push_heap and friends later
public:
size_t idx;
bigint<n> r;
ordered_exponent(const size_t idx, const bigint<n> &r) : idx(idx), r(r) {};
bool operator<(const ordered_exponent<n> &other) const
{
#if defined(__x86_64__) && defined(USE_ASM)
if (n == 3)
{
int64_t res;
__asm__
("// check for overflow \n\t"
"mov $0, %[res] \n\t"
ADD_CMP(16)
ADD_CMP(8)
ADD_CMP(0)
"jmp done%= \n\t"
"subtract%=: \n\t"
"mov $1, %[res] \n\t"
"done%=: \n\t"
: [res] "=&r" (res)
: [A] "r" (other.r.data), [mod] "r" (this->r.data)
: "cc", "%rax");
return res;
}
else if (n == 4)
{
int64_t res;
__asm__
("// check for overflow \n\t"
"mov $0, %[res] \n\t"
ADD_CMP(24)
ADD_CMP(16)
ADD_CMP(8)
ADD_CMP(0)
"jmp done%= \n\t"
"subtract%=: \n\t"
"mov $1, %[res] \n\t"
"done%=: \n\t"
: [res] "=&r" (res)
: [A] "r" (other.r.data), [mod] "r" (this->r.data)
: "cc", "%rax");
return res;
}
else if (n == 5)
{
int64_t res;
__asm__
("// check for overflow \n\t"
"mov $0, %[res] \n\t"
ADD_CMP(32)
ADD_CMP(24)
ADD_CMP(16)
ADD_CMP(8)
ADD_CMP(0)
"jmp done%= \n\t"
"subtract%=: \n\t"
"mov $1, %[res] \n\t"
"done%=: \n\t"
: [res] "=&r" (res)
: [A] "r" (other.r.data), [mod] "r" (this->r.data)
: "cc", "%rax");
return res;
}
else
#endif
{
return (mpn_cmp(this->r.data, other.r.data, n) < 0);
}
}
};
template<typename T, typename FieldT>
T naive_exp(typename std::vector<T>::const_iterator vec_start,
typename std::vector<T>::const_iterator vec_end,
typename std::vector<FieldT>::const_iterator scalar_start,
typename std::vector<FieldT>::const_iterator scalar_end)
{
T result(T::zero());
typename std::vector<T>::const_iterator vec_it;
typename std::vector<FieldT>::const_iterator scalar_it;
for (vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it)
{
bigint<FieldT::num_limbs> scalar_bigint = scalar_it->as_bigint();
result = result + opt_window_wnaf_exp(*vec_it, scalar_bigint, scalar_bigint.num_bits());
}
assert_except(scalar_it == scalar_end);
return result;
}
template<typename T, typename FieldT>
T naive_plain_exp(typename std::vector<T>::const_iterator vec_start,
typename std::vector<T>::const_iterator vec_end,
typename std::vector<FieldT>::const_iterator scalar_start,
typename std::vector<FieldT>::const_iterator scalar_end)
{
T result(T::zero());
typename std::vector<T>::const_iterator vec_it;
typename std::vector<FieldT>::const_iterator scalar_it;
for (vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it)
{
result = result + (*scalar_it) * (*vec_it);
}
assert_except(scalar_it == scalar_end);
return result;
}
/*
The multi-exponentiation algorithm below is a variant of the Bos-Coster algorithm
[Bos and Coster, "Addition chain heuristics", CRYPTO '89].
The implementation uses suggestions from
[Bernstein, Duif, Lange, Schwabe, and Yang, "High-speed high-security signatures", CHES '11].
*/
template<typename T, typename FieldT>
T multi_exp_inner(typename std::vector<T>::const_iterator vec_start,
typename std::vector<T>::const_iterator vec_end,
typename std::vector<FieldT>::const_iterator scalar_start,
typename std::vector<FieldT>::const_iterator scalar_end)
{
const mp_size_t n = std::remove_reference<decltype(*scalar_start)>::type::num_limbs;
if (vec_start == vec_end)
{
return T::zero();
}
if (vec_start + 1 == vec_end)
{
return (*scalar_start)*(*vec_start);
}
std::vector<ordered_exponent<n> > opt_q;
const size_t vec_len = scalar_end - scalar_start;
const size_t odd_vec_len = (vec_len % 2 == 1 ? vec_len : vec_len + 1);
opt_q.reserve(odd_vec_len);
std::vector<T> g;
g.reserve(odd_vec_len);
typename std::vector<T>::const_iterator vec_it;
typename std::vector<FieldT>::const_iterator scalar_it;
size_t i;
for (i=0, vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it, ++i)
{
g.emplace_back(*vec_it);
opt_q.emplace_back(ordered_exponent<n>(i, scalar_it->as_bigint()));
}
std::make_heap(opt_q.begin(),opt_q.end());
assert_except(scalar_it == scalar_end);
if (vec_len != odd_vec_len)
{
g.emplace_back(T::zero());
opt_q.emplace_back(ordered_exponent<n>(odd_vec_len - 1, bigint<n>(UINT64_C(0))));
}
assert_except(g.size() % 2 == 1);
assert_except(opt_q.size() == g.size());
T opt_result = T::zero();
while (true)
{
ordered_exponent<n> &a = opt_q[0];
ordered_exponent<n> &b = (opt_q[1] < opt_q[2] ? opt_q[2] : opt_q[1]);
const size_t abits = a.r.num_bits();
if (b.r.is_zero())
{
// opt_result = opt_result + (a.r * g[a.idx]);
opt_result = opt_result + opt_window_wnaf_exp(g[a.idx], a.r, abits);
break;
}
const size_t bbits = b.r.num_bits();
const size_t limit = (abits-bbits >= 20 ? 20 : abits-bbits);
if (bbits < UINT64_C(1)<<limit)
{
/*
In this case, exponentiating to the power of a is cheaper than
subtracting b from a multiple times, so let's do it directly
*/
// opt_result = opt_result + (a.r * g[a.idx]);
opt_result = opt_result + opt_window_wnaf_exp(g[a.idx], a.r, abits);
#ifdef DEBUG
printf("Skipping the following pair (%zu bit number vs %zu bit):\n", abits, bbits);
a.r.print();
b.r.print();
#endif
a.r.clear();
}
else
{
// x A + y B => (x-y) A + y (B+A)
mpn_sub_n(a.r.data, a.r.data, b.r.data, n);
g[b.idx] = g[b.idx] + g[a.idx];
}
// regardless of whether a was cleared or subtracted from we push it down, then take back up
/* heapify A down */
size_t a_pos = 0;
while (2*a_pos + 2< odd_vec_len)
{
// this is a max-heap so to maintain a heap property we swap with the largest of the two
if (opt_q[2*a_pos+1] < opt_q[2*a_pos+2])
{
std::swap(opt_q[a_pos], opt_q[2*a_pos+2]);
a_pos = 2*a_pos+2;
}
else
{
std::swap(opt_q[a_pos], opt_q[2*a_pos+1]);
a_pos = 2*a_pos+1;
}
}
/* now heapify A up appropriate amount of times */
while (a_pos > 0 && opt_q[(a_pos-1)/2] < opt_q[a_pos])
{
std::swap(opt_q[a_pos], opt_q[(a_pos-1)/2]);
a_pos = (a_pos-1) / 2;
}
}
return opt_result;
}
template<typename T, typename FieldT>
T multi_exp(typename std::vector<T>::const_iterator vec_start,
typename std::vector<T>::const_iterator vec_end,
typename std::vector<FieldT>::const_iterator scalar_start,
typename std::vector<FieldT>::const_iterator scalar_end,
const size_t chunks,
const bool use_multiexp)
{
const size_t total = vec_end - vec_start;
if (total < chunks)
{
return naive_exp<T, FieldT>(vec_start, vec_end, scalar_start, scalar_end);
}
const size_t one = total/chunks;
std::vector<T> partial(chunks, T::zero());
if (use_multiexp)
{
#ifdef MULTICORE
#pragma omp parallel for
#endif
for (size_t i = 0; i < chunks; ++i)
{
partial[i] = multi_exp_inner<T, FieldT>(vec_start + i*one,
(i == chunks-1 ? vec_end : vec_start + (i+1)*one),
scalar_start + i*one,
(i == chunks-1 ? scalar_end : scalar_start + (i+1)*one));
}
}
else
{
#ifdef MULTICORE
#pragma omp parallel for
#endif
for (size_t i = 0; i < chunks; ++i)
{
partial[i] = naive_exp<T, FieldT>(vec_start + i*one,
(i == chunks-1 ? vec_end : vec_start + (i+1)*one),
scalar_start + i*one,
(i == chunks-1 ? scalar_end : scalar_start + (i+1)*one));
}
}
T final = T::zero();
for (size_t i = 0; i < chunks; ++i)
{
final = final + partial[i];
}
return final;
}
template<typename T, typename FieldT>
T multi_exp_with_mixed_addition(typename std::vector<T>::const_iterator vec_start,
typename std::vector<T>::const_iterator vec_end,
typename std::vector<FieldT>::const_iterator scalar_start,
typename std::vector<FieldT>::const_iterator scalar_end,
const size_t chunks,
const bool use_multiexp)
{
assert_except(std::distance(vec_start, vec_end) == std::distance(scalar_start, scalar_end));
enter_block("Process scalar vector");
auto value_it = vec_start;
auto scalar_it = scalar_start;
const FieldT zero = FieldT::zero();
const FieldT one = FieldT::one();
std::vector<FieldT> p;
std::vector<T> g;
T acc = T::zero();
size_t num_skip = 0;
size_t num_add = 0;
size_t num_other = 0;
for (; scalar_it != scalar_end; ++scalar_it, ++value_it)
{
if (*scalar_it == zero)
{
// do nothing
++num_skip;
}
else if (*scalar_it == one)
{
#ifdef USE_MIXED_ADDITION
acc = acc.mixed_add(*value_it);
#else
acc = acc + (*value_it);
#endif
++num_add;
}
else
{
p.emplace_back(*scalar_it);
g.emplace_back(*value_it);
++num_other;
}
}
//print_indent(); printf("* Elements of w skipped: %zu (%0.2f%%)\n", num_skip, 100.*num_skip/(num_skip+num_add+num_other));
//print_indent(); printf("* Elements of w processed with special addition: %zu (%0.2f%%)\n", num_add, 100.*num_add/(num_skip+num_add+num_other));
//print_indent(); printf("* Elements of w remaining: %zu (%0.2f%%)\n", num_other, 100.*num_other/(num_skip+num_add+num_other));
leave_block("Process scalar vector");
return acc + multi_exp<T, FieldT>(g.begin(), g.end(), p.begin(), p.end(), chunks, use_multiexp);
}
template<typename T>
size_t get_exp_window_size(const size_t num_scalars)
{
if (T::fixed_base_exp_window_table.empty())
{
#ifdef LOWMEM
return 14;
#else
return 17;
#endif
}
size_t window = 1;
for (int64_t i = T::fixed_base_exp_window_table.size()-1; i >= 0; --i)
{
#ifdef DEBUG
if (!inhibit_profiling_info)
{
printf("%ld %zu %zu\n", i, num_scalars, T::fixed_base_exp_window_table[i]);
}
#endif
if (T::fixed_base_exp_window_table[i] != 0 && num_scalars >= T::fixed_base_exp_window_table[i])
{
window = i+1;
break;
}
}
if (!inhibit_profiling_info)
{
print_indent(); printf("Choosing window size %zu for %zu elements\n", window, num_scalars);
}
#ifdef LOWMEM
window = std::min((size_t)14, window);
#endif
return window;
}
template<typename T>
window_table<T> get_window_table(const size_t scalar_size,
const size_t window,
const T &g)
{
const size_t in_window = UINT64_C(1)<<window;
const size_t outerc = (scalar_size+window-1)/window;
const size_t last_in_window = UINT64_C(1)<<(scalar_size - (outerc-1)*window);
#ifdef DEBUG
if (!inhibit_profiling_info)
{
print_indent(); printf("* scalar_size=%zu; window=%zu; in_window=%zu; outerc=%zu\n", scalar_size, window, in_window, outerc);
}
#endif
window_table<T> powers_of_g(outerc, std::vector<T>(in_window, T::zero()));
T gouter = g;
for (size_t outer = 0; outer < outerc; ++outer)
{
T ginner = T::zero();
size_t cur_in_window = outer == outerc-1 ? last_in_window : in_window;
for (size_t inner = 0; inner < cur_in_window; ++inner)
{
powers_of_g[outer][inner] = ginner;
ginner = ginner + gouter;
}
for (size_t i = 0; i < window; ++i)
{
gouter = gouter + gouter;
}
}
return powers_of_g;
}
template<typename T, typename FieldT>
T windowed_exp(const size_t scalar_size,
const size_t window,
const window_table<T> &powers_of_g,
const FieldT &pow)
{
const size_t outerc = (scalar_size+window-1)/window;
const bigint<FieldT::num_limbs> pow_val = pow.as_bigint();
/* exp */
T res = powers_of_g[0][0];
for (size_t outer = 0; outer < outerc; ++outer)
{
size_t inner = 0;
for (size_t i = 0; i < window; ++i)
{
if (pow_val.test_bit(outer*window + i))
{
inner |= 1u << i;
}
}
res = res + powers_of_g[outer][inner];
}
return res;
}
template<typename T, typename FieldT>
std::vector<T> batch_exp(const size_t scalar_size,
const size_t window,
const window_table<T> &table,
const std::vector<FieldT> &v)
{
if (!inhibit_profiling_info)
{
print_indent();
}
std::vector<T> res(v.size(), table[0][0]);
#ifdef MULTICORE
#pragma omp parallel for
#endif
for (size_t i = 0; i < v.size(); ++i)
{
res[i] = windowed_exp(scalar_size, window, table, v[i]);
if (!inhibit_profiling_info && (i % 10000 == 0))
{
printf(".");
fflush(stdout);
}
}
if (!inhibit_profiling_info)
{
printf(" DONE!\n");
}
return res;
}
template<typename T, typename FieldT>
std::vector<T> batch_exp_with_coeff(const size_t scalar_size,
const size_t window,
const window_table<T> &table,
const FieldT &coeff,
const std::vector<FieldT> &v)
{
if (!inhibit_profiling_info)
{
print_indent();
}
std::vector<T> res(v.size(), table[0][0]);
#ifdef MULTICORE
#pragma omp parallel for
#endif
for (size_t i = 0; i < v.size(); ++i)
{
res[i] = windowed_exp(scalar_size, window, table, coeff * v[i]);
if (!inhibit_profiling_info && (i % 10000 == 0))
{
printf(".");
fflush(stdout);
}
}
if (!inhibit_profiling_info)
{
printf(" DONE!\n");
}
return res;
}
template<typename T>
void batch_to_special(std::vector<T> &vec)
{
enter_block("Batch-convert elements to special form");
std::vector<T> non_zero_vec;
for (size_t i = 0; i < vec.size(); ++i)
{
if (!vec[i].is_zero())
{
non_zero_vec.emplace_back(vec[i]);
}
}
batch_to_special_all_non_zeros<T>(non_zero_vec);
auto it = non_zero_vec.begin();
T zero_special = T::zero();
zero_special.to_special();
for (size_t i = 0; i < vec.size(); ++i)
{
if (!vec[i].is_zero())
{
vec[i] = *it;
++it;
}
else
{
vec[i] = zero_special;
}
}
leave_block("Batch-convert elements to special form");
}
} // libsnark
#endif // MULTIEXP_TCC_

39
src/snark/libsnark/algebra/scalar_multiplication/wnaf.hpp

@ -1,39 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for wNAF ("width-w Non-Adjacent Form") exponentiation routines.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef WNAF_HPP_
#define WNAF_HPP_
namespace libsnark {
/**
* Find the wNAF representation of the given scalar relative to the given window size.
*/
template<mp_size_t n>
std::vector<int64_t> find_wnaf(const size_t window_size, const bigint<n> &scalar);
/**
* In additive notation, use wNAF exponentiation (with the given window size) to compute scalar * base.
*/
template<typename T, mp_size_t n>
T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint<n> &scalar);
/**
* In additive notation, use wNAF exponentiation (with the window size determined by T) to compute scalar * base.
*/
template<typename T, mp_size_t n>
T opt_window_wnaf_exp(const T &base, const bigint<n> &scalar, const size_t scalar_bits);
} // libsnark
#include "algebra/scalar_multiplication/wnaf.tcc"
#endif // WNAF_HPP_

123
src/snark/libsnark/algebra/scalar_multiplication/wnaf.tcc

@ -1,123 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for wNAF ("weighted Non-Adjacent Form") exponentiation routines.
See wnaf.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef WNAF_TCC_
#define WNAF_TCC_
namespace libsnark {
template<mp_size_t n>
std::vector<int64_t> find_wnaf(const size_t window_size, const bigint<n> &scalar)
{
const size_t length = scalar.max_bits(); // upper bound
std::vector<int64_t> res(length+1);
bigint<n> c = scalar;
int64_t j = 0;
while (!c.is_zero())
{
int64_t u;
if ((c.data[0] & 1) == 1)
{
u = c.data[0] % (1u << (window_size+1));
if (u > (1 << window_size))
{
u = u - (1 << (window_size+1));
}
if (u > 0)
{
mpn_sub_1(c.data, c.data, n, u);
}
else
{
mpn_add_1(c.data, c.data, n, -u);
}
}
else
{
u = 0;
}
res[j] = u;
++j;
mpn_rshift(c.data, c.data, n, 1); // c = c/2
}
return res;
}
template<typename T, mp_size_t n>
T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint<n> &scalar)
{
std::vector<int64_t> naf = find_wnaf(window_size, scalar);
std::vector<T> table(UINT64_C(1)<<(window_size-1));
T tmp = base;
T dbl = base.dbl();
for (size_t i = 0; i < UINT64_C(1)<<(window_size-1); ++i)
{
table[i] = tmp;
tmp = tmp + dbl;
}
T res = T::zero();
bool found_nonzero = false;
for (int64_t i = naf.size()-1; i >= 0; --i)
{
if (found_nonzero)
{
res = res.dbl();
}
if (naf[i] != 0)
{
found_nonzero = true;
if (naf[i] > 0)
{
res = res + table[naf[i]/2];
}
else
{
res = res - table[(-naf[i])/2];
}
}
}
return res;
}
template<typename T, mp_size_t n>
T opt_window_wnaf_exp(const T &base, const bigint<n> &scalar, const size_t scalar_bits)
{
size_t best = 0;
for (int64_t i = T::wnaf_window_table.size() - 1; i >= 0; --i)
{
if (scalar_bits >= T::wnaf_window_table[i])
{
best = i+1;
break;
}
}
if (best > 0)
{
return fixed_window_wnaf_exp(best, base, scalar);
}
else
{
return scalar * base;
}
}
} // libsnark
#endif // WNAF_TCC_

12
src/snark/libsnark/common/assert_except.hpp

@ -1,12 +0,0 @@
#ifndef ASSERT_except_H
#define ASSERT_except_H
#include <exception>
inline void assert_except(bool condition) {
if (!condition) {
throw std::runtime_error("Assertion failed.");
}
}
#endif

74
src/snark/libsnark/common/data_structures/accumulation_vector.hpp

@ -1,74 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for an accumulation vector.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef ACCUMULATION_VECTOR_HPP_
#define ACCUMULATION_VECTOR_HPP_
#include "common/data_structures/sparse_vector.hpp"
namespace libsnark {
template<typename T>
class accumulation_vector;
template<typename T>
std::ostream& operator<<(std::ostream &out, const accumulation_vector<T> &v);
template<typename T>
std::istream& operator>>(std::istream &in, accumulation_vector<T> &v);
/**
* An accumulation vector comprises an accumulation value and a sparse vector.
* The method "accumulate_chunk" allows one to accumlate portions of the sparse
* vector into the accumualation value.
*/
template<typename T>
class accumulation_vector {
public:
T first;
sparse_vector<T> rest;
accumulation_vector() = default;
accumulation_vector(const accumulation_vector<T> &other) = default;
accumulation_vector(accumulation_vector<T> &&other) = default;
accumulation_vector(T &&first, sparse_vector<T> &&rest) : first(std::move(first)), rest(std::move(rest)) {};
accumulation_vector(T &&first, std::vector<T> &&v) : first(std::move(first)), rest(std::move(v)) {}
accumulation_vector(std::vector<T> &&v) : first(T::zero()), rest(std::move(v)) {};
accumulation_vector<T>& operator=(const accumulation_vector<T> &other) = default;
accumulation_vector<T>& operator=(accumulation_vector<T> &&other) = default;
bool operator==(const accumulation_vector<T> &other) const;
bool is_fully_accumulated() const;
size_t domain_size() const;
size_t size() const;
size_t size_in_bits() const;
template<typename FieldT>
accumulation_vector<T> accumulate_chunk(const typename std::vector<FieldT>::const_iterator &it_begin,
const typename std::vector<FieldT>::const_iterator &it_end,
const size_t offset) const;
};
template<typename T>
std::ostream& operator<<(std::ostream &out, const accumulation_vector<T> &v);
template<typename T>
std::istream& operator>>(std::istream &in, accumulation_vector<T> &v);
} // libsnark
#include "common/data_structures/accumulation_vector.tcc"
#endif // ACCUMULATION_VECTOR_HPP_

84
src/snark/libsnark/common/data_structures/accumulation_vector.tcc

@ -1,84 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for an accumulation vector.
See accumulation_vector.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef ACCUMULATION_VECTOR_TCC_
#define ACCUMULATION_VECTOR_TCC_
namespace libsnark {
template<typename T>
bool accumulation_vector<T>::operator==(const accumulation_vector<T> &other) const
{
return (this->first == other.first && this->rest == other.rest);
}
template<typename T>
bool accumulation_vector<T>::is_fully_accumulated() const
{
return rest.empty();
}
template<typename T>
size_t accumulation_vector<T>::domain_size() const
{
return rest.domain_size();
}
template<typename T>
size_t accumulation_vector<T>::size() const
{
return rest.domain_size();
}
template<typename T>
size_t accumulation_vector<T>::size_in_bits() const
{
const size_t first_size_in_bits = T::size_in_bits();
const size_t rest_size_in_bits = rest.size_in_bits();
return first_size_in_bits + rest_size_in_bits;
}
template<typename T>
template<typename FieldT>
accumulation_vector<T> accumulation_vector<T>::accumulate_chunk(const typename std::vector<FieldT>::const_iterator &it_begin,
const typename std::vector<FieldT>::const_iterator &it_end,
const size_t offset) const
{
std::pair<T, sparse_vector<T> > acc_result = rest.template accumulate<FieldT>(it_begin, it_end, offset);
T new_first = first + acc_result.first;
return accumulation_vector<T>(std::move(new_first), std::move(acc_result.second));
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const accumulation_vector<T> &v)
{
out << v.first << OUTPUT_NEWLINE;
out << v.rest << OUTPUT_NEWLINE;
return out;
}
template<typename T>
std::istream& operator>>(std::istream& in, accumulation_vector<T> &v)
{
in >> v.first;
consume_OUTPUT_NEWLINE(in);
in >> v.rest;
consume_OUTPUT_NEWLINE(in);
return in;
}
} // libsnark
#endif // ACCUMULATION_VECTOR_TCC_

71
src/snark/libsnark/common/data_structures/merkle_tree.hpp

@ -1,71 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for a Merkle tree.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef MERKLE_TREE_HPP_
#define MERKLE_TREE_HPP_
#include <map>
#include <vector>
#include "common/utils.hpp"
namespace libsnark {
/**
* A Merkle tree is maintained as two maps:
* - a map from addresses to values, and
* - a map from addresses to hashes.
*
* The second map maintains the intermediate hashes of a Merkle tree
* built atop the values currently stored in the tree (the
* implementation admits a very efficient support for sparse
* trees). Besides offering methods to load and store values, the
* class offers methods to retrieve the root of the Merkle tree and to
* obtain the authentication paths for (the value at) a given address.
*/
typedef bit_vector merkle_authentication_node;
typedef std::vector<merkle_authentication_node> merkle_authentication_path;
template<typename HashT>
class merkle_tree {
private:
typedef typename HashT::hash_value_type hash_value_type;
typedef typename HashT::merkle_authentication_path_type merkle_authentication_path_type;
public:
std::vector<hash_value_type> hash_defaults;
std::map<size_t, bit_vector> values;
std::map<size_t, hash_value_type> hashes;
size_t depth;
size_t value_size;
size_t digest_size;
merkle_tree(const size_t depth, const size_t value_size);
merkle_tree(const size_t depth, const size_t value_size, const std::vector<bit_vector> &contents_as_vector);
merkle_tree(const size_t depth, const size_t value_size, const std::map<size_t, bit_vector> &contents);
bit_vector get_value(const size_t address) const;
void set_value(const size_t address, const bit_vector &value);
hash_value_type get_root() const;
merkle_authentication_path_type get_path(const size_t address) const;
void dump() const;
};
} // libsnark
#include "common/data_structures/merkle_tree.tcc"
#endif // MERKLE_TREE_HPP_

246
src/snark/libsnark/common/data_structures/merkle_tree.tcc

@ -1,246 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for Merkle tree.
See merkle_tree.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef MERKLE_TREE_TCC
#define MERKLE_TREE_TCC
#include <algorithm>
#include "common/profiling.hpp"
#include "common/utils.hpp"
namespace libsnark {
template<typename HashT>
typename HashT::hash_value_type two_to_one_CRH(const typename HashT::hash_value_type &l,
const typename HashT::hash_value_type &r)
{
typename HashT::hash_value_type new_input;
new_input.insert(new_input.end(), l.begin(), l.end());
new_input.insert(new_input.end(), r.begin(), r.end());
const size_t digest_size = HashT::get_digest_len();
assert(l.size() == digest_size);
assert(r.size() == digest_size);
return HashT::get_hash(new_input);
}
template<typename HashT>
merkle_tree<HashT>::merkle_tree(const size_t depth, const size_t value_size) :
depth(depth), value_size(value_size)
{
assert(depth < sizeof(size_t) * 8);
digest_size = HashT::get_digest_len();
assert(value_size <= digest_size);
hash_value_type last(digest_size);
hash_defaults.reserve(depth+1);
hash_defaults.emplace_back(last);
for (size_t i = 0; i < depth; ++i)
{
last = two_to_one_CRH<HashT>(last, last);
hash_defaults.emplace_back(last);
}
std::reverse(hash_defaults.begin(), hash_defaults.end());
}
template<typename HashT>
merkle_tree<HashT>::merkle_tree(const size_t depth,
const size_t value_size,
const std::vector<bit_vector> &contents_as_vector) :
merkle_tree<HashT>(depth, value_size)
{
assert(log2(contents_as_vector.size()) <= depth);
for (size_t address = 0; address < contents_as_vector.size(); ++address)
{
const size_t idx = address + (UINT64_C(1)<<depth) - 1;
values[idx] = contents_as_vector[address];
hashes[idx] = contents_as_vector[address];
hashes[idx].resize(digest_size);
}
size_t idx_begin = (UINT64_C(1)<<depth) - 1;
size_t idx_end = contents_as_vector.size() + ((UINT64_C(1)<<depth) - 1);
for (int layer = depth; layer > 0; --layer)
{
for (size_t idx = idx_begin; idx < idx_end; idx += 2)
{
hash_value_type l = hashes[idx]; // this is sound, because idx_begin is always a left child
hash_value_type r = (idx + 1 < idx_end ? hashes[idx+1] : hash_defaults[layer]);
hash_value_type h = two_to_one_CRH<HashT>(l, r);
hashes[(idx-1)/2] = h;
}
idx_begin = (idx_begin-1)/2;
idx_end = (idx_end-1)/2;
}
}
template<typename HashT>
merkle_tree<HashT>::merkle_tree(const size_t depth,
const size_t value_size,
const std::map<size_t, bit_vector> &contents) :
merkle_tree<HashT>(depth, value_size)
{
if (!contents.empty())
{
assert(contents.rbegin()->first < UINT64_C(1)<<depth);
for (auto it = contents.begin(); it != contents.end(); ++it)
{
const size_t address = it->first;
const bit_vector value = it->second;
const size_t idx = address + (UINT64_C(1)<<depth) - 1;
values[address] = value;
hashes[idx] = value;
hashes[idx].resize(digest_size);
}
auto last_it = hashes.end();
for (int layer = depth; layer > 0; --layer)
{
auto next_last_it = hashes.begin();
for (auto it = hashes.begin(); it != last_it; ++it)
{
const size_t idx = it->first;
const hash_value_type hash = it->second;
if (idx % 2 == 0)
{
// this is the right child of its parent and by invariant we are missing the left child
hashes[(idx-1)/2] = two_to_one_CRH<HashT>(hash_defaults[layer], hash);
}
else
{
if (std::next(it) == last_it || std::next(it)->first != idx + 1)
{
// this is the left child of its parent and is missing its right child
hashes[(idx-1)/2] = two_to_one_CRH<HashT>(hash, hash_defaults[layer]);
}
else
{
// typical case: this is the left child of the parent and adjecent to it there is a right child
hashes[(idx-1)/2] = two_to_one_CRH<HashT>(hash, std::next(it)->second);
++it;
}
}
}
last_it = next_last_it;
}
}
}
template<typename HashT>
bit_vector merkle_tree<HashT>::get_value(const size_t address) const
{
assert(log2(address) <= depth);
auto it = values.find(address);
bit_vector padded_result = (it == values.end() ? bit_vector(digest_size) : it->second);
padded_result.resize(value_size);
return padded_result;
}
template<typename HashT>
void merkle_tree<HashT>::set_value(const size_t address,
const bit_vector &value)
{
assert(log2(address) <= depth);
size_t idx = address + (UINT64_C(1)<<depth) - 1;
assert(value.size() == value_size);
values[address] = value;
hashes[idx] = value;
hashes[idx].resize(digest_size);
for (int layer = depth-1; layer >=0; --layer)
{
idx = (idx-1)/2;
auto it = hashes.find(2*idx+1);
hash_value_type l = (it == hashes.end() ? hash_defaults[layer+1] : it->second);
it = hashes.find(2*idx+2);
hash_value_type r = (it == hashes.end() ? hash_defaults[layer+1] : it->second);
hash_value_type h = two_to_one_CRH<HashT>(l, r);
hashes[idx] = h;
}
}
template<typename HashT>
typename HashT::hash_value_type merkle_tree<HashT>::get_root() const
{
auto it = hashes.find(0);
return (it == hashes.end() ? hash_defaults[0] : it->second);
}
template<typename HashT>
typename HashT::merkle_authentication_path_type merkle_tree<HashT>::get_path(const size_t address) const
{
typename HashT::merkle_authentication_path_type result(depth);
assert(log2(address) <= depth);
size_t idx = address + (UINT64_C(1)<<depth) - 1;
for (size_t layer = depth; layer > 0; --layer)
{
size_t sibling_idx = ((idx + 1) ^ 1) - 1;
auto it = hashes.find(sibling_idx);
if (layer == depth)
{
auto it2 = values.find(sibling_idx - ((UINT64_C(1)<<depth) - 1));
result[layer-1] = (it2 == values.end() ? bit_vector(value_size, false) : it2->second);
result[layer-1].resize(digest_size);
}
else
{
result[layer-1] = (it == hashes.end() ? hash_defaults[layer] : it->second);
}
idx = (idx-1)/2;
}
return result;
}
template<typename HashT>
void merkle_tree<HashT>::dump() const
{
for (size_t i = 0; i < UINT64_C(1)<<depth; ++i)
{
auto it = values.find(i);
printf("[%zu] -> ", i);
const bit_vector value = (it == values.end() ? bit_vector(value_size) : it->second);
for (bool b : value)
{
printf("%d", b ? 1 : 0);
}
printf("\n");
}
printf("\n");
}
} // libsnark
#endif // MERKLE_TREE_TCC

79
src/snark/libsnark/common/data_structures/sparse_vector.hpp

@ -1,79 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for a sparse vector.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SPARSE_VECTOR_HPP_
#define SPARSE_VECTOR_HPP_
#include <vector>
namespace libsnark {
template<typename T>
struct sparse_vector;
template<typename T>
std::ostream& operator<<(std::ostream &out, const sparse_vector<T> &v);
template<typename T>
std::istream& operator>>(std::istream &in, sparse_vector<T> &v);
/**
* A sparse vector is a list of indices along with corresponding values.
* The indices are selected from the set {0,1,...,domain_size-1}.
*/
template<typename T>
struct sparse_vector {
std::vector<uint64_t> indices;
std::vector<T> values;
uint64_t domain_size_ = 0;
sparse_vector() = default;
sparse_vector(const sparse_vector<T> &other) = default;
sparse_vector(sparse_vector<T> &&other) = default;
sparse_vector(std::vector<T> &&v); /* constructor from std::vector */
sparse_vector<T>& operator=(const sparse_vector<T> &other) = default;
sparse_vector<T>& operator=(sparse_vector<T> &&other) = default;
T operator[](const uint64_t idx) const;
bool operator==(const sparse_vector<T> &other) const;
bool operator==(const std::vector<T> &other) const;
bool is_valid() const;
bool empty() const;
uint64_t domain_size() const; // return domain_size_
uint64_t size() const; // return the number of indices (representing the number of non-zero entries)
uint64_t size_in_bits() const; // return the number bits needed to store the sparse vector
/* return a pair consisting of the accumulated value and the sparse vector of non-accumuated values */
template<typename FieldT>
std::pair<T, sparse_vector<T> > accumulate(const typename std::vector<FieldT>::const_iterator &it_begin,
const typename std::vector<FieldT>::const_iterator &it_end,
const uint64_t offset) const;
friend std::ostream& operator<< <T>(std::ostream &out, const sparse_vector<T> &v);
friend std::istream& operator>> <T>(std::istream &in, sparse_vector<T> &v);
};
template<typename T>
std::ostream& operator<<(std::ostream& out, const sparse_vector<T> &v);
template<typename T>
std::istream& operator>>(std::istream& in, sparse_vector<T> &v);
} // libsnark
#include "common/data_structures/sparse_vector.tcc"
#endif // SPARSE_VECTOR_HPP_

316
src/snark/libsnark/common/data_structures/sparse_vector.tcc

@ -1,316 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for a sparse vector.
See sparse_vector.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SPARSE_VECTOR_TCC_
#define SPARSE_VECTOR_TCC_
#include "algebra/scalar_multiplication/multiexp.hpp"
#include <numeric>
namespace libsnark {
template<typename T>
sparse_vector<T>::sparse_vector(std::vector<T> &&v) :
values(std::move(v)), domain_size_(values.size())
{
indices.resize(domain_size_);
std::iota(indices.begin(), indices.end(), 0);
}
template<typename T>
T sparse_vector<T>::operator[](const uint64_t idx) const
{
auto it = std::lower_bound(indices.begin(), indices.end(), idx);
return (it != indices.end() && *it == idx) ? values[it - indices.begin()] : T();
}
template<typename T>
bool sparse_vector<T>::operator==(const sparse_vector<T> &other) const
{
if (this->domain_size_ != other.domain_size_)
{
return false;
}
uint64_t this_pos = 0, other_pos = 0;
while (this_pos < this->indices.size() && other_pos < other.indices.size())
{
if (this->indices[this_pos] == other.indices[other_pos])
{
if (this->values[this_pos] != other.values[other_pos])
{
return false;
}
++this_pos;
++other_pos;
}
else if (this->indices[this_pos] < other.indices[other_pos])
{
if (!this->values[this_pos].is_zero())
{
return false;
}
++this_pos;
}
else
{
if (!other.values[other_pos].is_zero())
{
return false;
}
++other_pos;
}
}
/* at least one of the vectors has been exhausted, so other must be empty */
while (this_pos < this->indices.size())
{
if (!this->values[this_pos].is_zero())
{
return false;
}
++this_pos;
}
while (other_pos < other.indices.size())
{
if (!other.values[other_pos].is_zero())
{
return false;
}
++other_pos;
}
return true;
}
template<typename T>
bool sparse_vector<T>::operator==(const std::vector<T> &other) const
{
if (this->domain_size_ < other.size())
{
return false;
}
uint64_t j = 0;
for (uint64_t i = 0; i < other.size(); ++i)
{
if (this->indices[j] == i)
{
if (this->values[j] != other[j])
{
return false;
}
++j;
}
else
{
if (!other[j].is_zero())
{
return false;
}
}
}
return true;
}
template<typename T>
bool sparse_vector<T>::is_valid() const
{
if (values.size() == indices.size() && values.size() <= domain_size_)
{
return false;
}
for (uint64_t i = 0; i + 1 < indices.size(); ++i)
{
if (indices[i] >= indices[i+1])
{
return false;
}
}
if (!indices.empty() && indices[indices.size()-1] >= domain_size_)
{
return false;
}
return true;
}
template<typename T>
bool sparse_vector<T>::empty() const
{
return indices.empty();
}
template<typename T>
uint64_t sparse_vector<T>::domain_size() const
{
return domain_size_;
}
template<typename T>
uint64_t sparse_vector<T>::size() const
{
return indices.size();
}
template<typename T>
uint64_t sparse_vector<T>::size_in_bits() const
{
return indices.size() * (sizeof(uint64_t) * 8 + T::size_in_bits());
}
template<typename T>
template<typename FieldT>
std::pair<T, sparse_vector<T> > sparse_vector<T>::accumulate(const typename std::vector<FieldT>::const_iterator &it_begin,
const typename std::vector<FieldT>::const_iterator &it_end,
const uint64_t offset) const
{
// TODO: does not really belong here.
const uint64_t chunks = 1;
const bool use_multiexp = true;
T accumulated_value = T::zero();
sparse_vector<T> resulting_vector;
resulting_vector.domain_size_ = domain_size_;
const uint64_t range_len = it_end - it_begin;
bool in_block = false;
uint64_t first_pos = -1, last_pos = -1; // g++ -flto emits unitialized warning, even though in_block guards for such cases.
for (uint64_t i = 0; i < indices.size(); ++i)
{
const bool matching_pos = (offset <= indices[i] && indices[i] < offset + range_len);
// printf("i = %zu, pos[i] = %zu, offset = %zu, w_size = %zu\n", i, indices[i], offset, w_size);
bool copy_over;
if (in_block)
{
if (matching_pos && last_pos == i-1)
{
// block can be extended, do it
last_pos = i;
copy_over = false;
}
else
{
// block has ended here
in_block = false;
copy_over = true;
#ifdef DEBUG
print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]);
#endif
accumulated_value = accumulated_value + multi_exp<T, FieldT>(values.begin() + first_pos,
values.begin() + last_pos + 1,
it_begin + (indices[first_pos] - offset),
it_begin + (indices[last_pos] - offset) + 1,
chunks, use_multiexp);
}
}
else
{
if (matching_pos)
{
// block can be started
first_pos = i;
last_pos = i;
in_block = true;
copy_over = false;
}
else
{
copy_over = true;
}
}
if (copy_over)
{
resulting_vector.indices.emplace_back(indices[i]);
resulting_vector.values.emplace_back(values[i]);
}
}
if (in_block)
{
#ifdef DEBUG
print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]);
#endif
accumulated_value = accumulated_value + multi_exp<T, FieldT>(values.begin() + first_pos,
values.begin() + last_pos + 1,
it_begin + (indices[first_pos] - offset),
it_begin + (indices[last_pos] - offset) + 1,
chunks, use_multiexp);
}
return std::make_pair(accumulated_value, resulting_vector);
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const sparse_vector<T> &v)
{
out << v.domain_size_ << "\n";
out << v.indices.size() << "\n";
for (const uint64_t& i : v.indices)
{
out << i << "\n";
}
out << v.values.size() << "\n";
for (const T& t : v.values)
{
out << t << OUTPUT_NEWLINE;
}
return out;
}
template<typename T>
std::istream& operator>>(std::istream& in, sparse_vector<T> &v)
{
in >> v.domain_size_;
consume_newline(in);
uint64_t s;
in >> s;
consume_newline(in);
v.indices.resize(s);
for (uint64_t i = 0; i < s; ++i)
{
in >> v.indices[i];
consume_newline(in);
}
v.values.clear();
in >> s;
consume_newline(in);
v.values.reserve(s);
for (uint64_t i = 0; i < s; ++i)
{
T t;
in >> t;
consume_OUTPUT_NEWLINE(in);
v.values.emplace_back(t);
}
return in;
}
} // libsnark
#endif // SPARSE_VECTOR_TCC_

53
src/snark/libsnark/common/default_types/ec_pp.hpp

@ -1,53 +0,0 @@
/** @file
*****************************************************************************
This file defines default_ec_pp based on the CURVE=... make flag, which selects
which elliptic curve is used to implement group arithmetic and pairings.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef EC_PP_HPP_
#define EC_PP_HPP_
/************************ Pick the elliptic curve ****************************/
#ifdef CURVE_ALT_BN128
#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp"
namespace libsnark {
typedef alt_bn128_pp default_ec_pp;
} // libsnark
#endif
#ifdef CURVE_BN128
#include "algebra/curves/bn128/bn128_pp.hpp"
namespace libsnark {
typedef bn128_pp default_ec_pp;
} // libsnark
#endif
#ifdef CURVE_EDWARDS
#include "algebra/curves/edwards/edwards_pp.hpp"
namespace libsnark {
typedef edwards_pp default_ec_pp;
} // libsnark
#endif
#ifdef CURVE_MNT4
#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp"
namespace libsnark {
typedef mnt4_pp default_ec_pp;
} // libsnark
#endif
#ifdef CURVE_MNT6
#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp"
namespace libsnark {
typedef mnt6_pp default_ec_pp;
} // libsnark
#endif
#endif // EC_PP_HPP_

22
src/snark/libsnark/common/default_types/r1cs_ppzksnark_pp.hpp

@ -1,22 +0,0 @@
/** @file
*****************************************************************************
This file defines default_r1cs_ppzksnark_pp based on the elliptic curve
choice selected in ec_pp.hpp.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef R1CS_PPZKSNARK_PP_HPP_
#define R1CS_PPZKSNARK_PP_HPP_
#include "common/default_types/ec_pp.hpp"
namespace libsnark {
typedef default_ec_pp default_r1cs_ppzksnark_pp;
} // libsnark
#endif // R1CS_PPZKSNARK_PP_HPP_

399
src/snark/libsnark/common/profiling.cpp

@ -1,399 +0,0 @@
/** @file
*****************************************************************************
Implementation of functions for profiling code blocks.
See profiling.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "common/profiling.hpp"
#include <cassert>
#include <stdexcept>
#include <chrono>
#include <cinttypes>
#include <cstdio>
#include <list>
#include <vector>
#include <ctime>
#include "common/default_types/ec_pp.hpp"
#include "common/utils.hpp"
#ifndef NO_PROCPS
#include <proc/readproc.h>
#endif
#ifdef __MACH__ // required to build on MacOS
#include <time.h>
#include <sys/time.h>
#include <mach/clock.h>
#include <mach/mach.h>
#endif
namespace libsnark {
int64_t get_nsec_time()
{
auto timepoint = std::chrono::high_resolution_clock::now();
return std::chrono::duration_cast<std::chrono::nanoseconds>(timepoint.time_since_epoch()).count();
}
/* Return total CPU time consumed by all threads of the process, in nanoseconds. */
int64_t get_nsec_cpu_time()
{
::timespec ts;
#ifdef __MACH__
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
ts.tv_sec = mts.tv_sec;
ts.tv_nsec = mts.tv_nsec;
#else
if ( ::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) )
throw ::std::runtime_error("clock_gettime(CLOCK_PROCESS_CPUTIME_ID) failed");
// If we expected this to work, don't silently ignore failures, because that would hide the problem and incur an unnecessarily system-call overhead. So if we ever observe this exception, we should probably add a suitable #ifdef .
//TODO: clock_gettime(CLOCK_PROCESS_CPUTIME_ID) is not supported by native Windows. What about Cygwin? Should we #ifdef on CLOCK_PROCESS_CPUTIME_ID or on __linux__?
#endif
return ts.tv_sec * 1000000000ll + ts.tv_nsec;
}
static int64_t start_time;
static int64_t last_time;
static int64_t start_cpu_time;
static int64_t last_cpu_time;
void start_profiling()
{
printf("Reset time counters for profiling\n");
last_time = start_time = get_nsec_time();
last_cpu_time = start_cpu_time = get_nsec_cpu_time();
}
std::map<std::string, size_t> invocation_counts;
static std::map<std::string, int64_t> enter_times;
std::map<std::string, int64_t> last_times;
std::map<std::string, int64_t> cumulative_times;
//TODO: Instead of analogous maps for time and cpu_time, use a single struct-valued map
static std::map<std::string, int64_t> enter_cpu_times;
static std::map<std::string, int64_t> last_cpu_times;
static std::map<std::pair<std::string, std::string>, int64_t> op_counts;
static std::map<std::pair<std::string, std::string>, int64_t> cumulative_op_counts; // ((msg, data_point), value)
// TODO: Convert op_counts and cumulative_op_counts from pair to structs
static size_t indentation = 0;
static std::vector<std::string> block_names;
static std::list<std::pair<std::string, int64_t*> > op_data_points = {
#ifdef PROFILE_OP_COUNTS
std::make_pair("Fradd", &Fr<default_ec_pp>::add_cnt),
std::make_pair("Frsub", &Fr<default_ec_pp>::sub_cnt),
std::make_pair("Frmul", &Fr<default_ec_pp>::mul_cnt),
std::make_pair("Frinv", &Fr<default_ec_pp>::inv_cnt),
std::make_pair("Fqadd", &Fq<default_ec_pp>::add_cnt),
std::make_pair("Fqsub", &Fq<default_ec_pp>::sub_cnt),
std::make_pair("Fqmul", &Fq<default_ec_pp>::mul_cnt),
std::make_pair("Fqinv", &Fq<default_ec_pp>::inv_cnt),
std::make_pair("G1add", &G1<default_ec_pp>::add_cnt),
std::make_pair("G1dbl", &G1<default_ec_pp>::dbl_cnt),
std::make_pair("G2add", &G2<default_ec_pp>::add_cnt),
std::make_pair("G2dbl", &G2<default_ec_pp>::dbl_cnt)
#endif
};
bool inhibit_profiling_info = true;
bool inhibit_profiling_counters = false;
void clear_profiling_counters()
{
invocation_counts.clear();
last_times.clear();
last_cpu_times.clear();
cumulative_times.clear();
}
void print_cumulative_time_entry(const std::string &key, const int64_t factor)
{
const double total_ms = (cumulative_times.at(key) * 1e-6);
const size_t cnt = invocation_counts.at(key);
const double avg_ms = total_ms / cnt;
printf(" %-45s: %12.5fms = %" PRId64 " * %0.5fms (%zu invocations, %0.5fms = %" PRId64 " * %0.5fms per invocation)\n", key.c_str(), total_ms, factor, total_ms/factor, cnt, avg_ms, factor, avg_ms/factor);
}
void print_cumulative_times(const int64_t factor)
{
printf("Dumping times:\n");
for (auto& kv : cumulative_times)
{
print_cumulative_time_entry(kv.first, factor);
}
}
void print_cumulative_op_counts(const bool only_fq)
{
#ifdef PROFILE_OP_COUNTS
printf("Dumping operation counts:\n");
for (auto& msg : invocation_counts)
{
printf(" %-45s: ", msg.first.c_str());
bool first = true;
for (auto& data_point : op_data_points)
{
if (only_fq && data_point.first.compare(0, 2, "Fq") != 0)
{
continue;
}
if (!first)
{
printf(", ");
}
printf("%-5s = %7.0f (%3zu)",
data_point.first.c_str(),
1. * cumulative_op_counts[std::make_pair(msg.first, data_point.first)] / msg.second,
msg.second);
first = false;
}
printf("\n");
}
#else
UNUSED(only_fq);
#endif
}
void print_op_profiling(const std::string &msg)
{
#ifdef PROFILE_OP_COUNTS
printf("\n");
print_indent();
printf("(opcounts) = (");
bool first = true;
for (std::pair<std::string, int64_t*> p : op_data_points)
{
if (!first)
{
printf(", ");
}
printf("%s=%lld", p.first.c_str(), *(p.second)-op_counts[std::make_pair(msg, p.first)]);
first = false;
}
printf(")");
#else
UNUSED(msg);
#endif
}
static void print_times_from_last_and_start(int64_t now, int64_t last,
int64_t cpu_now, int64_t cpu_last)
{
int64_t time_from_start = now - start_time;
int64_t time_from_last = now - last;
int64_t cpu_time_from_start = cpu_now - start_cpu_time;
int64_t cpu_time_from_last = cpu_now - cpu_last;
if (time_from_last != 0) {
double parallelism_from_last = 1.0 * cpu_time_from_last / time_from_last;
printf("[%0.4fs x%0.2f]", time_from_last * 1e-9, parallelism_from_last);
} else {
printf("[ ]");
}
if (time_from_start != 0) {
double parallelism_from_start = 1.0 * cpu_time_from_start / time_from_start;
printf("\t(%0.4fs x%0.2f from start)", time_from_start * 1e-9, parallelism_from_start);
}
}
void print_time(const char* msg)
{
if (inhibit_profiling_info)
{
return;
}
int64_t now = get_nsec_time();
int64_t cpu_now = get_nsec_cpu_time();
printf("%-35s\t", msg);
print_times_from_last_and_start(now, last_time, cpu_now, last_cpu_time);
#ifdef PROFILE_OP_COUNTS
print_op_profiling(msg);
#endif
printf("\n");
fflush(stdout);
last_time = now;
last_cpu_time = cpu_now;
}
void print_header(const char *msg)
{
printf("\n================================================================================\n");
printf("%s\n", msg);
printf("================================================================================\n\n");
}
void print_indent()
{
for (size_t i = 0; i < indentation; ++i)
{
printf(" ");
}
}
void op_profiling_enter(const std::string &msg)
{
for (std::pair<std::string, int64_t*> p : op_data_points)
{
op_counts[std::make_pair(msg, p.first)] = *(p.second);
}
}
void enter_block(const std::string &msg, const bool indent)
{
if (inhibit_profiling_counters)
{
return;
}
block_names.emplace_back(msg);
int64_t t = get_nsec_time();
enter_times[msg] = t;
int64_t cpu_t = get_nsec_cpu_time();
enter_cpu_times[msg] = cpu_t;
if (inhibit_profiling_info)
{
return;
}
#ifdef MULTICORE
#pragma omp critical
#endif
{
op_profiling_enter(msg);
print_indent();
printf("(enter) %-35s\t", msg.c_str());
print_times_from_last_and_start(t, t, cpu_t, cpu_t);
printf("\n");
fflush(stdout);
if (indent)
{
++indentation;
}
}
}
void leave_block(const std::string &msg, const bool indent)
{
if (inhibit_profiling_counters)
{
return;
}
#ifndef MULTICORE
assert(*(--block_names.end()) == msg);
#endif
block_names.pop_back();
++invocation_counts[msg];
int64_t t = get_nsec_time();
last_times[msg] = (t - enter_times[msg]);
cumulative_times[msg] += (t - enter_times[msg]);
int64_t cpu_t = get_nsec_cpu_time();
last_cpu_times[msg] = (cpu_t - enter_cpu_times[msg]);
#ifdef PROFILE_OP_COUNTS
for (std::pair<std::string, int64_t*> p : op_data_points)
{
cumulative_op_counts[std::make_pair(msg, p.first)] += *(p.second)-op_counts[std::make_pair(msg, p.first)];
}
#endif
if (inhibit_profiling_info)
{
return;
}
#ifdef MULTICORE
#pragma omp critical
#endif
{
if (indent)
{
--indentation;
}
print_indent();
printf("(leave) %-35s\t", msg.c_str());
print_times_from_last_and_start(t, enter_times[msg], cpu_t, enter_cpu_times[msg]);
print_op_profiling(msg);
printf("\n");
fflush(stdout);
}
}
void print_mem(const std::string &s)
{
#ifndef NO_PROCPS
struct proc_t usage;
look_up_our_self(&usage);
if (s.empty())
{
printf("* Peak vsize (physical memory+swap) in mebibytes: %lu\n", usage.vsize >> 20);
}
else
{
printf("* Peak vsize (physical memory+swap) in mebibytes (%s): %lu\n", s.c_str(), usage.vsize >> 20);
}
#else
printf("* Memory profiling not supported in NO_PROCPS mode\n");
#endif
}
void print_compilation_info()
{
#ifdef __GNUC__
printf("g++ version: %s\n", __VERSION__);
//printf("Compiled on %s %s\n", __DATE__, __TIME__);
#endif
#ifdef STATIC
printf("STATIC: yes\n");
#else
printf("STATIC: no\n");
#endif
#ifdef MULTICORE
printf("MULTICORE: yes\n");
#else
printf("MULTICORE: no\n");
#endif
#ifdef DEBUG
printf("DEBUG: yes\n");
#else
printf("DEBUG: no\n");
#endif
#ifdef PROFILE_OP_COUNTS
printf("PROFILE_OP_COUNTS: yes\n");
#else
printf("PROFILE_OP_COUNTS: no\n");
#endif
#ifdef _GLIBCXX_DEBUG
printf("_GLIBCXX_DEBUG: yes\n");
#else
printf("_GLIBCXX_DEBUG: no\n");
#endif
}
} // libsnark

51
src/snark/libsnark/common/profiling.hpp

@ -1,51 +0,0 @@
/** @file
*****************************************************************************
Declaration of functions for profiling code blocks.
Reports time, operation counts, memory usage, and others.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef PROFILING_HPP_
#define PROFILING_HPP_
#include <cstddef>
#include <map>
#include <string>
#include <vector>
namespace libsnark {
void start_profiling();
int64_t get_nsec_time();
void print_time(const char* msg);
void print_header(const char* msg);
void print_indent();
extern bool inhibit_profiling_info;
extern bool inhibit_profiling_counters;
extern std::map<std::string, size_t> invocation_counts;
extern std::map<std::string, int64_t> last_times;
extern std::map<std::string, int64_t> cumulative_times;
void clear_profiling_counters();
void print_cumulative_time_entry(const std::string &key, const int64_t factor=1);
void print_cumulative_times(const int64_t factor=1);
void print_cumulative_op_counts(const bool only_fq=false);
void enter_block(const std::string &msg, const bool indent=true);
void leave_block(const std::string &msg, const bool indent=true);
void print_mem(const std::string &s = "");
void print_compilation_info();
} // libsnark
#endif // PROFILING_HPP_

104
src/snark/libsnark/common/serialization.hpp

@ -1,104 +0,0 @@
/** @file
*****************************************************************************
Declaration of serialization routines and constants.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SERIALIZATION_HPP_
#define SERIALIZATION_HPP_
#include <istream>
#include <map>
#include <ostream>
#include <set>
#include <vector>
namespace libsnark {
/*
* @todo
* The serialization is fragile. Shoud be rewritten using a standard, portable-format
* library like boost::serialize.
*
* However, for now the following conventions are used within the code.
*
* All algebraic objects support either binary or decimal output using
* the standard C++ stream operators (operator<<, operator>>).
*
* The binary mode is activated by defining a BINARY_OUTPUT
* preprocessor macro (e.g. g++ -DBINARY_OUTPUT ...).
*
* Binary output assumes that the stream is to be binary read at its
* current position so any white space should be consumed beforehand.
*
* Consecutive algebraic objects are separated by OUTPUT_NEWLINE and
* within themselves (e.g. X and Y coordinates for field elements) with
* OUTPUT_SEPARATOR (as defined below).
*
* Therefore to dump two integers, two Fp elements and another integer
* one would:
*
* out << 3 << "\n";
* out << 4 << "\n";
* out << FieldT(56) << OUTPUT_NEWLINE;
* out << FieldT(78) << OUTPUT_NEWLINE;
* out << 9 << "\n";
*
* Then reading back it its reader's responsibility (!) to consume "\n"
* after 4, but Fp::operator<< will correctly consume OUTPUT_NEWLINE.
*
* The reader should also consume "\n" after 9, so that another field
* element can be properly chained. This is especially important for
* binary output.
*
* The binary serialization of algebraic objects is currently *not*
* portable between machines of different word sizes.
*/
#ifdef BINARY_OUTPUT
#define OUTPUT_NEWLINE ""
#define OUTPUT_SEPARATOR ""
#else
#define OUTPUT_NEWLINE "\n"
#define OUTPUT_SEPARATOR " "
#endif
inline void consume_newline(std::istream &in);
inline void consume_OUTPUT_NEWLINE(std::istream &in);
inline void consume_OUTPUT_SEPARATOR(std::istream &in);
inline void output_bool(std::ostream &out, const bool b);
inline void output_bool_vector(std::ostream &out, const std::vector<bool> &v);
template<typename T>
T reserialize(const T &obj);
template<typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T> &v);
template<typename T>
std::istream& operator>>(std::ostream& out, std::vector<T> &v);
template<typename T1, typename T2>
std::ostream& operator<<(std::ostream& out, const std::map<T1, T2> &m);
template<typename T1, typename T2>
std::istream& operator>>(std::istream& in, std::map<T1, T2> &m);
template<typename T>
std::ostream& operator<<(std::ostream& out, const std::set<T> &s);
template<typename T>
std::istream& operator>>(std::istream& in, std::set<T> &s);
} // libsnark
#include "common/serialization.tcc"
#endif // SERIALIZATION_HPP_

181
src/snark/libsnark/common/serialization.tcc

@ -1,181 +0,0 @@
/** @file
*****************************************************************************
Implementation of serialization routines.
See serialization.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SERIALIZATION_TCC_
#define SERIALIZATION_TCC_
#include <cassert>
#include <sstream>
#include "common/utils.hpp"
#include "common/assert_except.hpp"
namespace libsnark {
inline void consume_newline(std::istream &in)
{
char c;
in.read(&c, 1);
}
inline void consume_OUTPUT_NEWLINE(std::istream &in)
{
#ifdef BINARY_OUTPUT
// nothing to consume
UNUSED(in);
#else
char c;
in.read(&c, 1);
#endif
}
inline void consume_OUTPUT_SEPARATOR(std::istream &in)
{
#ifdef BINARY_OUTPUT
// nothing to consume
UNUSED(in);
#else
char c;
in.read(&c, 1);
#endif
}
inline void output_bool(std::ostream &out, const bool b)
{
out << (b ? 1 : 0) << "\n";
}
inline void output_bool_vector(std::ostream &out, const std::vector<bool> &v)
{
out << v.size() << "\n";
for (const bool b : v)
{
output_bool(out, b);
}
}
template<typename T>
T reserialize(const T &obj)
{
std::stringstream ss;
ss << obj;
T tmp;
ss >> tmp;
assert_except(obj == tmp);
return tmp;
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T> &v)
{
static_assert(!std::is_same<T, bool>::value, "this does not work for std::vector<bool>");
out << v.size() << "\n";
for (const T& t : v)
{
out << t << OUTPUT_NEWLINE;
}
return out;
}
template<typename T>
std::istream& operator>>(std::istream& in, std::vector<T> &v)
{
static_assert(!std::is_same<T, bool>::value, "this does not work for std::vector<bool>");
size_t size;
in >> size;
consume_newline(in);
v.resize(0);
for (size_t i = 0; i < size; ++i)
{
T elt;
in >> elt;
consume_OUTPUT_NEWLINE(in);
v.push_back(elt);
}
return in;
}
template<typename T1, typename T2>
std::ostream& operator<<(std::ostream& out, const std::map<T1, T2> &m)
{
out << m.size() << "\n";
for (auto &it : m)
{
out << it.first << "\n";
out << it.second << "\n";
}
return out;
}
template<typename T1, typename T2>
std::istream& operator>>(std::istream& in, std::map<T1, T2> &m)
{
m.clear();
size_t size;
in >> size;
consume_newline(in);
for (size_t i = 0; i < size; ++i)
{
T1 k;
T2 v;
in >> k;
consume_newline(in);
in >> v;
consume_newline(in);
m[k] = v;
}
return in;
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const std::set<T> &s)
{
out << s.size() << "\n";
for (auto &el : s)
{
out << el << "\n";
}
return out;
}
template<typename T>
std::istream& operator>>(std::istream& in, std::set<T> &s)
{
s.clear();
size_t size;
in >> size;
consume_newline(in);
for (size_t i = 0; i < size; ++i)
{
T el;
in >> el;
consume_newline(in);
s.insert(el);
}
return in;
}
}
#endif // SERIALIZATION_TCC_

26
src/snark/libsnark/common/template_utils.hpp

@ -1,26 +0,0 @@
/** @file
*****************************************************************************
Declaration of functions for supporting the use of templates.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef TEMPLATE_UTILS_HPP_
#define TEMPLATE_UTILS_HPP_
namespace libsnark {
/* A commonly used SFINAE helper type */
template<typename T>
struct void_type
{
typedef void type;
};
} // libsnark
#endif // TEMPLATE_UTILS_HPP_

102
src/snark/libsnark/common/utils.cpp

@ -1,102 +0,0 @@
/** @file
*****************************************************************************
Implementation of misc math and serialization utility functions
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstdarg>
#include "common/utils.hpp"
namespace libsnark {
size_t log2(size_t n)
/* returns ceil(log2(n)), so UINT64_C(1)<<log2(n) is the smallest power of 2,
that is not less than n. */
{
uint64_t r = ((n & (n-1)) == 0 ? 0 : 1); // add 1 if n is not power of 2
while (n > 1)
{
n >>= 1;
r++;
}
return r;
}
uint64_t bitreverse(uint64_t n, const uint64_t l)
{
uint64_t r = 0;
for (uint64_t k = 0; k < l; ++k)
{
r = (r << 1) | (n & 1);
n >>= 1;
}
return r;
}
bit_vector int_list_to_bits(const std::initializer_list<uint64_t> &l, const size_t wordsize)
{
bit_vector res(wordsize*l.size());
for (uint64_t i = 0; i < l.size(); ++i)
{
for (uint64_t j = 0; j < wordsize; ++j)
{
res[i*wordsize + j] = (*(l.begin()+i) & (UINT64_C(1)<<(wordsize-1-j)));
}
}
return res;
}
int64_t div_ceil(int64_t x, int64_t y)
{
return (x + (y-1)) / y;
}
bool is_little_endian()
{
uint64_t a = 0x12345678;
unsigned char *c = (unsigned char*)(&a);
return (*c = 0x78);
}
std::string FORMAT(const std::string &prefix, const char* format, ...)
{
const static uint64_t MAX_FMT = 256;
char buf[MAX_FMT];
va_list args;
va_start(args, format);
vsnprintf(buf, MAX_FMT, format, args);
va_end(args);
return prefix + std::string(buf);
}
void serialize_bit_vector(std::ostream &out, const bit_vector &v)
{
out << v.size() << "\n";
for (uint64_t i = 0; i < v.size(); ++i)
{
out << v[i] << "\n";
}
}
void deserialize_bit_vector(std::istream &in, bit_vector &v)
{
uint64_t size;
in >> size;
v.resize(size);
for (uint64_t i = 0; i < size; ++i)
{
bool b;
in >> b;
v[i] = b;
}
}
} // libsnark

62
src/snark/libsnark/common/utils.hpp

@ -1,62 +0,0 @@
/** @file
*****************************************************************************
Declaration of misc math and serialization utility functions
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef UTILS_HPP_
#define UTILS_HPP_
#include <cassert>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
namespace libsnark {
typedef std::vector<bool> bit_vector;
/// returns ceil(log2(n)), so UINT64_C(1)<<log2(n) is the smallest power of 2, that is not less than n
size_t log2(size_t n);
inline size_t exp2(size_t k) { return UINT64_C(1) << k; }
uint64_t bitreverse(uint64_t n, const uint64_t l);
bit_vector int_list_to_bits(const std::initializer_list<uint64_t> &l, const size_t wordsize);
int64_t div_ceil(int64_t x, int64_t y);
bool is_little_endian();
std::string FORMAT(const std::string &prefix, const char* format, ...);
/* A variadic template to suppress unused argument warnings */
template<typename ... Types>
void UNUSED(Types&&...) {}
#ifdef DEBUG
#define FMT FORMAT
#else
#define FMT(...) (UNUSED(__VA_ARGS__), "")
#endif
void serialize_bit_vector(std::ostream &out, const bit_vector &v);
void deserialize_bit_vector(std::istream &in, bit_vector &v);
#ifdef __APPLE__
template<typename T>
unsigned long size_in_bits(const std::vector<T> &v);
#else
template<typename T>
uint64_t size_in_bits(const std::vector<T> &v);
#endif
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
} // libsnark
#include "common/utils.tcc" /* note that utils has a templatized part (utils.tcc) and non-templatized part (utils.cpp) */
#endif // UTILS_HPP_

31
src/snark/libsnark/common/utils.tcc

@ -1,31 +0,0 @@
/** @file
*****************************************************************************
Implementation of templatized utility functions
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef UTILS_TCC_
#define UTILS_TCC_
namespace libsnark {
#ifdef __APPLE__
template<typename T>
unsigned long size_in_bits(const std::vector<T> &v)
{
return v.size() * T::size_in_bits();
}
#else
template<typename T>
size_t size_in_bits(const std::vector<T> &v)
{
return v.size() * T::size_in_bits();
}
#endif
} // libsnark
#endif // UTILS_TCC_

48
src/snark/libsnark/gadgetlib1/constraint_profiling.cpp

@ -1,48 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for profiling constraints.
See constraint_profiling.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "gadgetlib1/constraint_profiling.hpp"
#include "common/profiling.hpp"
namespace libsnark {
size_t constraint_profiling_indent = 0;
std::vector<constraint_profiling_entry> constraint_profiling_table;
size_t PRINT_CONSTRAINT_PROFILING()
{
size_t accounted = 0;
print_indent();
printf("Constraint profiling:\n");
for (constraint_profiling_entry &ent : constraint_profiling_table)
{
if (ent.indent == 0)
{
accounted += ent.count;
}
print_indent();
for (size_t i = 0; i < ent.indent; ++i)
{
printf(" ");
}
printf("* Number of constraints in [%s]: %zu\n", ent.annotation.c_str(), ent.count);
}
constraint_profiling_table.clear();
constraint_profiling_indent = 0;
return accounted;
}
}

42
src/snark/libsnark/gadgetlib1/constraint_profiling.hpp

@ -1,42 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for profiling constraints.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef CONSTRAINT_PROFILING_HPP_
#define CONSTRAINT_PROFILING_HPP_
#include <cstddef>
#include <map>
#include <string>
#include <vector>
namespace libsnark {
extern size_t constraint_profiling_indent;
struct constraint_profiling_entry {
size_t indent;
std::string annotation;
size_t count;
};
extern std::vector<constraint_profiling_entry> constraint_profiling_table;
#define PROFILE_CONSTRAINTS(pb, annotation) \
for (size_t _num_constraints_before = pb.num_constraints(), _iter = (++constraint_profiling_indent, 0), _cp_pos = constraint_profiling_table.size(); \
_iter == 0; \
constraint_profiling_table.insert(constraint_profiling_table.begin() + _cp_pos, constraint_profiling_entry{--constraint_profiling_indent, annotation, pb.num_constraints() - _num_constraints_before}), \
_iter = 1)
size_t PRINT_CONSTRAINT_PROFILING(); // returns # of top level constraints
} // libsnark
#endif // CONSTRAINT_PROFILING_HPP_

23
src/snark/libsnark/gadgetlib1/examples/simple_example.hpp

@ -1,23 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SIMPLE_EXAMPLE_HPP_
#define SIMPLE_EXAMPLE_HPP_
#include "examples/r1cs_examples.hpp"
namespace libsnark {
template<typename FieldT>
r1cs_example<FieldT> gen_r1cs_example_from_protoboard(const size_t num_constraints,
const size_t num_inputs);
} // libsnark
#include "gadgetlib1/examples/simple_example.tcc"
#endif // SIMPLE_EXAMPLE_HPP_

54
src/snark/libsnark/gadgetlib1/examples/simple_example.tcc

@ -1,54 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SIMPLE_EXAMPLE_TCC_
#define SIMPLE_EXAMPLE_TCC_
#include <cassert>
#include "gadgetlib1/gadgets/basic_gadgets.hpp"
namespace libsnark {
/* NOTE: all examples here actually generate one constraint less to account for soundness constraint in QAP */
template<typename FieldT>
r1cs_example<FieldT> gen_r1cs_example_from_protoboard(const size_t num_constraints,
const size_t num_inputs)
{
const size_t new_num_constraints = num_constraints - 1;
/* construct dummy example: inner products of two vectors */
protoboard<FieldT> pb;
pb_variable_array<FieldT> A;
pb_variable_array<FieldT> B;
pb_variable<FieldT> res;
// the variables on the protoboard are (ONE (constant 1 term), res, A[0], ..., A[num_constraints-1], B[0], ..., B[num_constraints-1])
res.allocate(pb, "res");
A.allocate(pb, new_num_constraints, "A");
B.allocate(pb, new_num_constraints, "B");
inner_product_gadget<FieldT> compute_inner_product(pb, A, B, res, "compute_inner_product");
compute_inner_product.generate_r1cs_constraints();
/* fill in random example */
for (size_t i = 0; i < new_num_constraints; ++i)
{
pb.val(A[i]) = FieldT::random_element();
pb.val(B[i]) = FieldT::random_element();
}
compute_inner_product.generate_r1cs_witness();
pb.constraint_system.num_inputs = num_inputs;
const r1cs_variable_assignment<FieldT> va = pb.values;
const r1cs_variable_assignment<FieldT> input(va.begin(), va.begin() + num_inputs);
return r1cs_example<FieldT>(pb.constraint_system, input, va, num_inputs);
}
} // libsnark
#endif // R1CS_EXAMPLES_TCC_

27
src/snark/libsnark/gadgetlib1/gadget.hpp

@ -1,27 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef GADGET_HPP_
#define GADGET_HPP_
#include "gadgetlib1/protoboard.hpp"
namespace libsnark {
template<typename FieldT>
class gadget {
protected:
protoboard<FieldT> &pb;
const std::string annotation_prefix;
public:
gadget(protoboard<FieldT> &pb, const std::string &annotation_prefix="");
};
} // libsnark
#include "gadgetlib1/gadget.tcc"
#endif // GADGET_HPP_

23
src/snark/libsnark/gadgetlib1/gadget.tcc

@ -1,23 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef GADGET_TCC_
#define GADGET_TCC_
namespace libsnark {
template<typename FieldT>
gadget<FieldT>::gadget(protoboard<FieldT> &pb, const std::string &annotation_prefix) :
pb(pb), annotation_prefix(annotation_prefix)
{
#ifdef DEBUG
assert(annotation_prefix != "");
#endif
}
} // libsnark
#endif // GADGET_TCC_

351
src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.hpp

@ -1,351 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef BASIC_GADGETS_HPP_
#define BASIC_GADGETS_HPP_
#include <cassert>
#include <memory>
#include "gadgetlib1/gadget.hpp"
namespace libsnark {
/* forces lc to take value 0 or 1 by adding constraint lc * (1-lc) = 0 */
template<typename FieldT>
void generate_boolean_r1cs_constraint(protoboard<FieldT> &pb, const pb_linear_combination<FieldT> &lc, const std::string &annotation_prefix="");
template<typename FieldT>
void generate_r1cs_equals_const_constraint(protoboard<FieldT> &pb, const pb_linear_combination<FieldT> &lc, const FieldT& c, const std::string &annotation_prefix="");
template<typename FieldT>
class packing_gadget : public gadget<FieldT> {
private:
/* no internal variables */
public:
const pb_linear_combination_array<FieldT> bits;
const pb_linear_combination<FieldT> packed;
packing_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &bits,
const pb_linear_combination<FieldT> &packed,
const std::string &annotation_prefix="") :
gadget<FieldT>(pb, annotation_prefix), bits(bits), packed(packed) {}
void generate_r1cs_constraints(const bool enforce_bitness);
/* adds constraint result = \sum bits[i] * 2^i */
void generate_r1cs_witness_from_packed();
void generate_r1cs_witness_from_bits();
};
template<typename FieldT>
class multipacking_gadget : public gadget<FieldT> {
private:
std::vector<packing_gadget<FieldT> > packers;
public:
const pb_linear_combination_array<FieldT> bits;
const pb_linear_combination_array<FieldT> packed_vars;
const size_t chunk_size;
const size_t num_chunks;
// const size_t last_chunk_size;
multipacking_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &bits,
const pb_linear_combination_array<FieldT> &packed_vars,
const size_t chunk_size,
const std::string &annotation_prefix="");
void generate_r1cs_constraints(const bool enforce_bitness);
void generate_r1cs_witness_from_packed();
void generate_r1cs_witness_from_bits();
};
template<typename FieldT>
class field_vector_copy_gadget : public gadget<FieldT> {
public:
const pb_variable_array<FieldT> source;
const pb_variable_array<FieldT> target;
const pb_linear_combination<FieldT> do_copy;
field_vector_copy_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &source,
const pb_variable_array<FieldT> &target,
const pb_linear_combination<FieldT> &do_copy,
const std::string &annotation_prefix="");
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
template<typename FieldT>
class bit_vector_copy_gadget : public gadget<FieldT> {
public:
const pb_variable_array<FieldT> source_bits;
const pb_variable_array<FieldT> target_bits;
const pb_linear_combination<FieldT> do_copy;
pb_variable_array<FieldT> packed_source;
pb_variable_array<FieldT> packed_target;
std::shared_ptr<multipacking_gadget<FieldT> > pack_source;
std::shared_ptr<multipacking_gadget<FieldT> > pack_target;
std::shared_ptr<field_vector_copy_gadget<FieldT> > copier;
const size_t chunk_size;
const size_t num_chunks;
bit_vector_copy_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &source_bits,
const pb_variable_array<FieldT> &target_bits,
const pb_linear_combination<FieldT> &do_copy,
const size_t chunk_size,
const std::string &annotation_prefix="");
void generate_r1cs_constraints(const bool enforce_source_bitness, const bool enforce_target_bitness);
void generate_r1cs_witness();
};
template<typename FieldT>
class dual_variable_gadget : public gadget<FieldT> {
private:
std::shared_ptr<packing_gadget<FieldT> > consistency_check;
public:
pb_variable<FieldT> packed;
pb_variable_array<FieldT> bits;
dual_variable_gadget(protoboard<FieldT> &pb,
const size_t width,
const std::string &annotation_prefix="") :
gadget<FieldT>(pb, annotation_prefix)
{
packed.allocate(pb, FMT(this->annotation_prefix, " packed"));
bits.allocate(pb, width, FMT(this->annotation_prefix, " bits"));
consistency_check.reset(new packing_gadget<FieldT>(pb,
bits,
packed,
FMT(this->annotation_prefix, " consistency_check")));
}
dual_variable_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &bits,
const std::string &annotation_prefix="") :
gadget<FieldT>(pb, annotation_prefix), bits(bits)
{
packed.allocate(pb, FMT(this->annotation_prefix, " packed"));
consistency_check.reset(new packing_gadget<FieldT>(pb,
bits,
packed,
FMT(this->annotation_prefix, " consistency_check")));
}
dual_variable_gadget(protoboard<FieldT> &pb,
const pb_variable<FieldT> &packed,
const size_t width,
const std::string &annotation_prefix="") :
gadget<FieldT>(pb, annotation_prefix), packed(packed)
{
bits.allocate(pb, width, FMT(this->annotation_prefix, " bits"));
consistency_check.reset(new packing_gadget<FieldT>(pb,
bits,
packed,
FMT(this->annotation_prefix, " consistency_check")));
}
void generate_r1cs_constraints(const bool enforce_bitness);
void generate_r1cs_witness_from_packed();
void generate_r1cs_witness_from_bits();
};
/*
the gadgets below are Fp specific:
I * X = R
(1-R) * X = 0
if X = 0 then R = 0
if X != 0 then R = 1 and I = X^{-1}
*/
template<typename FieldT>
class disjunction_gadget : public gadget<FieldT> {
private:
pb_variable<FieldT> inv;
public:
const pb_variable_array<FieldT> inputs;
const pb_variable<FieldT> output;
disjunction_gadget(protoboard<FieldT>& pb,
const pb_variable_array<FieldT> &inputs,
const pb_variable<FieldT> &output,
const std::string &annotation_prefix="") :
gadget<FieldT>(pb, annotation_prefix), inputs(inputs), output(output)
{
assert(inputs.size() >= 1);
inv.allocate(pb, FMT(this->annotation_prefix, " inv"));
}
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
template<typename FieldT>
void test_disjunction_gadget(const size_t n);
template<typename FieldT>
class conjunction_gadget : public gadget<FieldT> {
private:
pb_variable<FieldT> inv;
public:
const pb_variable_array<FieldT> inputs;
const pb_variable<FieldT> output;
conjunction_gadget(protoboard<FieldT>& pb,
const pb_variable_array<FieldT> &inputs,
const pb_variable<FieldT> &output,
const std::string &annotation_prefix="") :
gadget<FieldT>(pb, annotation_prefix), inputs(inputs), output(output)
{
assert(inputs.size() >= 1);
inv.allocate(pb, FMT(this->annotation_prefix, " inv"));
}
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
template<typename FieldT>
void test_conjunction_gadget(const size_t n);
template<typename FieldT>
class comparison_gadget : public gadget<FieldT> {
private:
pb_variable_array<FieldT> alpha;
pb_variable<FieldT> alpha_packed;
std::shared_ptr<packing_gadget<FieldT> > pack_alpha;
std::shared_ptr<disjunction_gadget<FieldT> > all_zeros_test;
pb_variable<FieldT> not_all_zeros;
public:
const size_t n;
const pb_linear_combination<FieldT> A;
const pb_linear_combination<FieldT> B;
const pb_variable<FieldT> less;
const pb_variable<FieldT> less_or_eq;
comparison_gadget(protoboard<FieldT>& pb,
const size_t n,
const pb_linear_combination<FieldT> &A,
const pb_linear_combination<FieldT> &B,
const pb_variable<FieldT> &less,
const pb_variable<FieldT> &less_or_eq,
const std::string &annotation_prefix="") :
gadget<FieldT>(pb, annotation_prefix), n(n), A(A), B(B), less(less), less_or_eq(less_or_eq)
{
alpha.allocate(pb, n, FMT(this->annotation_prefix, " alpha"));
alpha.emplace_back(less_or_eq); // alpha[n] is less_or_eq
alpha_packed.allocate(pb, FMT(this->annotation_prefix, " alpha_packed"));
not_all_zeros.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros"));
pack_alpha.reset(new packing_gadget<FieldT>(pb, alpha, alpha_packed,
FMT(this->annotation_prefix, " pack_alpha")));
all_zeros_test.reset(new disjunction_gadget<FieldT>(pb,
pb_variable_array<FieldT>(alpha.begin(), alpha.begin() + n),
not_all_zeros,
FMT(this->annotation_prefix, " all_zeros_test")));
};
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
template<typename FieldT>
void test_comparison_gadget(const size_t n);
template<typename FieldT>
class inner_product_gadget : public gadget<FieldT> {
private:
/* S_i = \sum_{k=0}^{i+1} A[i] * B[i] */
pb_variable_array<FieldT> S;
public:
const pb_linear_combination_array<FieldT> A;
const pb_linear_combination_array<FieldT> B;
const pb_variable<FieldT> result;
inner_product_gadget(protoboard<FieldT>& pb,
const pb_linear_combination_array<FieldT> &A,
const pb_linear_combination_array<FieldT> &B,
const pb_variable<FieldT> &result,
const std::string &annotation_prefix="") :
gadget<FieldT>(pb, annotation_prefix), A(A), B(B), result(result)
{
assert(A.size() >= 1);
assert(A.size() == B.size());
S.allocate(pb, A.size()-1, FMT(this->annotation_prefix, " S"));
}
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
template<typename FieldT>
void test_inner_product_gadget(const size_t n);
template<typename FieldT>
class loose_multiplexing_gadget : public gadget<FieldT> {
/*
this implements loose multiplexer:
index not in bounds -> success_flag = 0
index in bounds && success_flag = 1 -> result is correct
however if index is in bounds we can also set success_flag to 0 (and then result will be forced to be 0)
*/
public:
pb_variable_array<FieldT> alpha;
private:
std::shared_ptr<inner_product_gadget<FieldT> > compute_result;
public:
const pb_linear_combination_array<FieldT> arr;
const pb_variable<FieldT> index;
const pb_variable<FieldT> result;
const pb_variable<FieldT> success_flag;
loose_multiplexing_gadget(protoboard<FieldT>& pb,
const pb_linear_combination_array<FieldT> &arr,
const pb_variable<FieldT> &index,
const pb_variable<FieldT> &result,
const pb_variable<FieldT> &success_flag,
const std::string &annotation_prefix="") :
gadget<FieldT>(pb, annotation_prefix), arr(arr), index(index), result(result), success_flag(success_flag)
{
alpha.allocate(pb, arr.size(), FMT(this->annotation_prefix, " alpha"));
compute_result.reset(new inner_product_gadget<FieldT>(pb, alpha, arr, result, FMT(this->annotation_prefix, " compute_result")));
};
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
template<typename FieldT>
void test_loose_multiplexing_gadget(const size_t n);
template<typename FieldT, typename VarT>
void create_linear_combination_constraints(protoboard<FieldT> &pb,
const std::vector<FieldT> &base,
const std::vector<std::pair<VarT, FieldT> > &v,
const VarT &target,
const std::string &annotation_prefix);
template<typename FieldT, typename VarT>
void create_linear_combination_witness(protoboard<FieldT> &pb,
const std::vector<FieldT> &base,
const std::vector<std::pair<VarT, FieldT> > &v,
const VarT &target);
} // libsnark
#include "gadgetlib1/gadgets/basic_gadgets.tcc"
#endif // BASIC_GADGETS_HPP_

705
src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.tcc

@ -1,705 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef BASIC_GADGETS_TCC_
#define BASIC_GADGETS_TCC_
#include "common/profiling.hpp"
#include "common/utils.hpp"
namespace libsnark {
template<typename FieldT>
void generate_boolean_r1cs_constraint(protoboard<FieldT> &pb, const pb_linear_combination<FieldT> &lc, const std::string &annotation_prefix)
/* forces lc to take value 0 or 1 by adding constraint lc * (1-lc) = 0 */
{
pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lc, 1-lc, 0),
FMT(annotation_prefix, " boolean_r1cs_constraint"));
}
template<typename FieldT>
void generate_r1cs_equals_const_constraint(protoboard<FieldT> &pb, const pb_linear_combination<FieldT> &lc, const FieldT& c, const std::string &annotation_prefix)
{
pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1, lc, c),
FMT(annotation_prefix, " constness_constraint"));
}
template<typename FieldT>
void packing_gadget<FieldT>::generate_r1cs_constraints(const bool enforce_bitness)
/* adds constraint result = \sum bits[i] * 2^i */
{
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1, pb_packing_sum<FieldT>(bits), packed), FMT(this->annotation_prefix, " packing_constraint"));
if (enforce_bitness)
{
for (size_t i = 0; i < bits.size(); ++i)
{
generate_boolean_r1cs_constraint<FieldT>(this->pb, bits[i], FMT(this->annotation_prefix, " bitness_%zu", i));
}
}
}
template<typename FieldT>
void packing_gadget<FieldT>::generate_r1cs_witness_from_packed()
{
packed.evaluate(this->pb);
assert(this->pb.lc_val(packed).as_bigint().num_bits() <= bits.size());
bits.fill_with_bits_of_field_element(this->pb, this->pb.lc_val(packed));
}
template<typename FieldT>
void packing_gadget<FieldT>::generate_r1cs_witness_from_bits()
{
bits.evaluate(this->pb);
this->pb.lc_val(packed) = bits.get_field_element_from_bits(this->pb);
}
template<typename FieldT>
multipacking_gadget<FieldT>::multipacking_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &bits,
const pb_linear_combination_array<FieldT> &packed_vars,
const size_t chunk_size,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix), bits(bits), packed_vars(packed_vars),
chunk_size(chunk_size),
num_chunks(div_ceil(bits.size(), chunk_size))
// last_chunk_size(bits.size() - (num_chunks-1) * chunk_size)
{
assert(packed_vars.size() == num_chunks);
for (size_t i = 0; i < num_chunks; ++i)
{
packers.emplace_back(packing_gadget<FieldT>(this->pb, pb_linear_combination_array<FieldT>(bits.begin() + i * chunk_size,
bits.begin() + std::min((i+1) * chunk_size, bits.size())),
packed_vars[i], FMT(this->annotation_prefix, " packers_%zu", i)));
}
}
template<typename FieldT>
void multipacking_gadget<FieldT>::generate_r1cs_constraints(const bool enforce_bitness)
{
for (size_t i = 0; i < num_chunks; ++i)
{
packers[i].generate_r1cs_constraints(enforce_bitness);
}
}
template<typename FieldT>
void multipacking_gadget<FieldT>::generate_r1cs_witness_from_packed()
{
for (size_t i = 0; i < num_chunks; ++i)
{
packers[i].generate_r1cs_witness_from_packed();
}
}
template<typename FieldT>
void multipacking_gadget<FieldT>::generate_r1cs_witness_from_bits()
{
for (size_t i = 0; i < num_chunks; ++i)
{
packers[i].generate_r1cs_witness_from_bits();
}
}
template<typename FieldT>
size_t multipacking_num_chunks(const size_t num_bits)
{
return div_ceil(num_bits, FieldT::capacity());
}
template<typename FieldT>
field_vector_copy_gadget<FieldT>::field_vector_copy_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &source,
const pb_variable_array<FieldT> &target,
const pb_linear_combination<FieldT> &do_copy,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix), source(source), target(target), do_copy(do_copy)
{
assert(source.size() == target.size());
}
template<typename FieldT>
void field_vector_copy_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < source.size(); ++i)
{
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(do_copy, source[i] - target[i], 0),
FMT(this->annotation_prefix, " copying_check_%zu", i));
}
}
template<typename FieldT>
void field_vector_copy_gadget<FieldT>::generate_r1cs_witness()
{
do_copy.evaluate(this->pb);
assert(this->pb.lc_val(do_copy) == FieldT::one() || this->pb.lc_val(do_copy) == FieldT::zero());
if (this->pb.lc_val(do_copy) != FieldT::zero())
{
for (size_t i = 0; i < source.size(); ++i)
{
this->pb.val(target[i]) = this->pb.val(source[i]);
}
}
}
template<typename FieldT>
bit_vector_copy_gadget<FieldT>::bit_vector_copy_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &source_bits,
const pb_variable_array<FieldT> &target_bits,
const pb_linear_combination<FieldT> &do_copy,
const size_t chunk_size,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix), source_bits(source_bits), target_bits(target_bits), do_copy(do_copy),
chunk_size(chunk_size), num_chunks(div_ceil(source_bits.size(), chunk_size))
{
assert(source_bits.size() == target_bits.size());
packed_source.allocate(pb, num_chunks, FMT(annotation_prefix, " packed_source"));
pack_source.reset(new multipacking_gadget<FieldT>(pb, source_bits, packed_source, chunk_size, FMT(annotation_prefix, " pack_source")));
packed_target.allocate(pb, num_chunks, FMT(annotation_prefix, " packed_target"));
pack_target.reset(new multipacking_gadget<FieldT>(pb, target_bits, packed_target, chunk_size, FMT(annotation_prefix, " pack_target")));
copier.reset(new field_vector_copy_gadget<FieldT>(pb, packed_source, packed_target, do_copy, FMT(annotation_prefix, " copier")));
}
template<typename FieldT>
void bit_vector_copy_gadget<FieldT>::generate_r1cs_constraints(const bool enforce_source_bitness, const bool enforce_target_bitness)
{
pack_source->generate_r1cs_constraints(enforce_source_bitness);
pack_target->generate_r1cs_constraints(enforce_target_bitness);
copier->generate_r1cs_constraints();
}
template<typename FieldT>
void bit_vector_copy_gadget<FieldT>::generate_r1cs_witness()
{
do_copy.evaluate(this->pb);
assert(this->pb.lc_val(do_copy) == FieldT::zero() || this->pb.lc_val(do_copy) == FieldT::one());
if (this->pb.lc_val(do_copy) == FieldT::one())
{
for (size_t i = 0; i < source_bits.size(); ++i)
{
this->pb.val(target_bits[i]) = this->pb.val(source_bits[i]);
}
}
pack_source->generate_r1cs_witness_from_bits();
pack_target->generate_r1cs_witness_from_bits();
}
template<typename FieldT>
void dual_variable_gadget<FieldT>::generate_r1cs_constraints(const bool enforce_bitness)
{
consistency_check->generate_r1cs_constraints(enforce_bitness);
}
template<typename FieldT>
void dual_variable_gadget<FieldT>::generate_r1cs_witness_from_packed()
{
consistency_check->generate_r1cs_witness_from_packed();
}
template<typename FieldT>
void dual_variable_gadget<FieldT>::generate_r1cs_witness_from_bits()
{
consistency_check->generate_r1cs_witness_from_bits();
}
template<typename FieldT>
void disjunction_gadget<FieldT>::generate_r1cs_constraints()
{
/* inv * sum = output */
linear_combination<FieldT> a1, b1, c1;
a1.add_term(inv);
for (size_t i = 0; i < inputs.size(); ++i)
{
b1.add_term(inputs[i]);
}
c1.add_term(output);
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(a1, b1, c1), FMT(this->annotation_prefix, " inv*sum=output"));
/* (1-output) * sum = 0 */
linear_combination<FieldT> a2, b2, c2;
a2.add_term(ONE);
a2.add_term(output, -1);
for (size_t i = 0; i < inputs.size(); ++i)
{
b2.add_term(inputs[i]);
}
c2.add_term(ONE, 0);
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(a2, b2, c2), FMT(this->annotation_prefix, " (1-output)*sum=0"));
}
template<typename FieldT>
void disjunction_gadget<FieldT>::generate_r1cs_witness()
{
FieldT sum = FieldT::zero();
for (size_t i = 0; i < inputs.size(); ++i)
{
sum += this->pb.val(inputs[i]);
}
if (sum.is_zero())
{
this->pb.val(inv) = FieldT::zero();
this->pb.val(output) = FieldT::zero();
}
else
{
this->pb.val(inv) = sum.inverse();
this->pb.val(output) = FieldT::one();
}
}
template<typename FieldT>
void test_disjunction_gadget(const size_t n)
{
printf("testing disjunction_gadget on all %zu bit strings\n", n);
protoboard<FieldT> pb;
pb_variable_array<FieldT> inputs;
inputs.allocate(pb, n, "inputs");
pb_variable<FieldT> output;
output.allocate(pb, "output");
disjunction_gadget<FieldT> d(pb, inputs, output, "d");
d.generate_r1cs_constraints();
for (size_t w = 0; w < UINT64_C(1)<<n; ++w)
{
for (size_t j = 0; j < n; ++j)
{
pb.val(inputs[j]) = FieldT((w & (UINT64_C(1)<<j)) ? 1 : 0);
}
d.generate_r1cs_witness();
#ifdef DEBUG
printf("positive test for %zu\n", w);
#endif
assert(pb.val(output) == (w ? FieldT::one() : FieldT::zero()));
assert(pb.is_satisfied());
#ifdef DEBUG
printf("negative test for %zu\n", w);
#endif
pb.val(output) = (w ? FieldT::zero() : FieldT::one());
assert(!pb.is_satisfied());
}
print_time("disjunction tests successful");
}
template<typename FieldT>
void conjunction_gadget<FieldT>::generate_r1cs_constraints()
{
/* inv * (n-sum) = 1-output */
linear_combination<FieldT> a1, b1, c1;
a1.add_term(inv);
b1.add_term(ONE, inputs.size());
for (size_t i = 0; i < inputs.size(); ++i)
{
b1.add_term(inputs[i], -1);
}
c1.add_term(ONE);
c1.add_term(output, -1);
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(a1, b1, c1), FMT(this->annotation_prefix, " inv*(n-sum)=(1-output)"));
/* output * (n-sum) = 0 */
linear_combination<FieldT> a2, b2, c2;
a2.add_term(output);
b2.add_term(ONE, inputs.size());
for (size_t i = 0; i < inputs.size(); ++i)
{
b2.add_term(inputs[i], -1);
}
c2.add_term(ONE, 0);
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(a2, b2, c2), FMT(this->annotation_prefix, " output*(n-sum)=0"));
}
template<typename FieldT>
void conjunction_gadget<FieldT>::generate_r1cs_witness()
{
FieldT sum = FieldT(inputs.size());
for (size_t i = 0; i < inputs.size(); ++i)
{
sum -= this->pb.val(inputs[i]);
}
if (sum.is_zero())
{
this->pb.val(inv) = FieldT::zero();
this->pb.val(output) = FieldT::one();
}
else
{
this->pb.val(inv) = sum.inverse();
this->pb.val(output) = FieldT::zero();
}
}
template<typename FieldT>
void test_conjunction_gadget(const size_t n)
{
printf("testing conjunction_gadget on all %zu bit strings\n", n);
protoboard<FieldT> pb;
pb_variable_array<FieldT> inputs;
inputs.allocate(pb, n, "inputs");
pb_variable<FieldT> output;
output.allocate(pb, "output");
conjunction_gadget<FieldT> c(pb, inputs, output, "c");
c.generate_r1cs_constraints();
for (size_t w = 0; w < UINT64_C(1)<<n; ++w)
{
for (size_t j = 0; j < n; ++j)
{
pb.val(inputs[j]) = (w & (UINT64_C(1)<<j)) ? FieldT::one() : FieldT::zero();
}
c.generate_r1cs_witness();
#ifdef DEBUG
printf("positive test for %zu\n", w);
#endif
assert(pb.val(output) == (w == (UINT64_C(1)<<n) - 1 ? FieldT::one() : FieldT::zero()));
assert(pb.is_satisfied());
#ifdef DEBUG
printf("negative test for %zu\n", w);
#endif
pb.val(output) = (w == (UINT64_C(1)<<n) - 1 ? FieldT::zero() : FieldT::one());
assert(!pb.is_satisfied());
}
print_time("conjunction tests successful");
}
template<typename FieldT>
void comparison_gadget<FieldT>::generate_r1cs_constraints()
{
/*
packed(alpha) = 2^n + B - A
not_all_zeros = \bigvee_{i=0}^{n-1} alpha_i
if B - A > 0, then 2^n + B - A > 2^n,
so alpha_n = 1 and not_all_zeros = 1
if B - A = 0, then 2^n + B - A = 2^n,
so alpha_n = 1 and not_all_zeros = 0
if B - A < 0, then 2^n + B - A \in {0, 1, \ldots, 2^n-1},
so alpha_n = 0
therefore alpha_n = less_or_eq and alpha_n * not_all_zeros = less
*/
/* not_all_zeros to be Boolean, alpha_i are Boolean by packing gadget */
generate_boolean_r1cs_constraint<FieldT>(this->pb, not_all_zeros,
FMT(this->annotation_prefix, " not_all_zeros"));
/* constraints for packed(alpha) = 2^n + B - A */
pack_alpha->generate_r1cs_constraints(true);
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1, (FieldT(2)^n) + B - A, alpha_packed), FMT(this->annotation_prefix, " main_constraint"));
/* compute result */
all_zeros_test->generate_r1cs_constraints();
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(less_or_eq, not_all_zeros, less),
FMT(this->annotation_prefix, " less"));
}
template<typename FieldT>
void comparison_gadget<FieldT>::generate_r1cs_witness()
{
A.evaluate(this->pb);
B.evaluate(this->pb);
/* unpack 2^n + B - A into alpha_packed */
this->pb.val(alpha_packed) = (FieldT(2)^n) + this->pb.lc_val(B) - this->pb.lc_val(A);
pack_alpha->generate_r1cs_witness_from_packed();
/* compute result */
all_zeros_test->generate_r1cs_witness();
this->pb.val(less) = this->pb.val(less_or_eq) * this->pb.val(not_all_zeros);
}
template<typename FieldT>
void test_comparison_gadget(const size_t n)
{
printf("testing comparison_gadget on all %zu bit inputs\n", n);
protoboard<FieldT> pb;
pb_variable<FieldT> A, B, less, less_or_eq;
A.allocate(pb, "A");
B.allocate(pb, "B");
less.allocate(pb, "less");
less_or_eq.allocate(pb, "less_or_eq");
comparison_gadget<FieldT> cmp(pb, n, A, B, less, less_or_eq, "cmp");
cmp.generate_r1cs_constraints();
for (size_t a = 0; a < UINT64_C(1)<<n; ++a)
{
for (size_t b = 0; b < UINT64_C(1)<<n; ++b)
{
pb.val(A) = FieldT(a);
pb.val(B) = FieldT(b);
cmp.generate_r1cs_witness();
#ifdef DEBUG
printf("positive test for %zu < %zu\n", a, b);
#endif
assert(pb.val(less) == (a < b ? FieldT::one() : FieldT::zero()));
assert(pb.val(less_or_eq) == (a <= b ? FieldT::one() : FieldT::zero()));
assert(pb.is_satisfied());
}
}
print_time("comparison tests successful");
}
template<typename FieldT>
void inner_product_gadget<FieldT>::generate_r1cs_constraints()
{
/*
S_i = \sum_{k=0}^{i+1} A[i] * B[i]
S[0] = A[0] * B[0]
S[i+1] - S[i] = A[i] * B[i]
*/
for (size_t i = 0; i < A.size(); ++i)
{
this->pb.add_r1cs_constraint(
r1cs_constraint<FieldT>(A[i], B[i],
(i == A.size()-1 ? result : S[i]) + (i == 0 ? 0 * ONE : -S[i-1])),
FMT(this->annotation_prefix, " S_%zu", i));
}
}
template<typename FieldT>
void inner_product_gadget<FieldT>::generate_r1cs_witness()
{
FieldT total = FieldT::zero();
for (size_t i = 0; i < A.size(); ++i)
{
A[i].evaluate(this->pb);
B[i].evaluate(this->pb);
total += this->pb.lc_val(A[i]) * this->pb.lc_val(B[i]);
this->pb.val(i == A.size()-1 ? result : S[i]) = total;
}
}
template<typename FieldT>
void test_inner_product_gadget(const size_t n)
{
printf("testing inner_product_gadget on all %zu bit strings\n", n);
protoboard<FieldT> pb;
pb_variable_array<FieldT> A;
A.allocate(pb, n, "A");
pb_variable_array<FieldT> B;
B.allocate(pb, n, "B");
pb_variable<FieldT> result;
result.allocate(pb, "result");
inner_product_gadget<FieldT> g(pb, A, B, result, "g");
g.generate_r1cs_constraints();
for (size_t i = 0; i < UINT64_C(1)<<n; ++i)
{
for (size_t j = 0; j < UINT64_C(1)<<n; ++j)
{
size_t correct = 0;
for (size_t k = 0; k < n; ++k)
{
pb.val(A[k]) = (i & (UINT64_C(1)<<k) ? FieldT::one() : FieldT::zero());
pb.val(B[k]) = (j & (UINT64_C(1)<<k) ? FieldT::one() : FieldT::zero());
correct += ((i & (UINT64_C(1)<<k)) && (j & (UINT64_C(1)<<k)) ? 1 : 0);
}
g.generate_r1cs_witness();
#ifdef DEBUG
printf("positive test for (%zu, %zu)\n", i, j);
#endif
assert(pb.val(result) == FieldT(correct));
assert(pb.is_satisfied());
#ifdef DEBUG
printf("negative test for (%zu, %zu)\n", i, j);
#endif
pb.val(result) = FieldT(100*n+19);
assert(!pb.is_satisfied());
}
}
print_time("inner_product_gadget tests successful");
}
template<typename FieldT>
void loose_multiplexing_gadget<FieldT>::generate_r1cs_constraints()
{
/* \alpha_i (index - i) = 0 */
for (size_t i = 0; i < arr.size(); ++i)
{
this->pb.add_r1cs_constraint(
r1cs_constraint<FieldT>(alpha[i], index - i, 0),
FMT(this->annotation_prefix, " alpha_%zu", i));
}
/* 1 * (\sum \alpha_i) = success_flag */
linear_combination<FieldT> a, b, c;
a.add_term(ONE);
for (size_t i = 0; i < arr.size(); ++i)
{
b.add_term(alpha[i]);
}
c.add_term(success_flag);
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(a, b, c), FMT(this->annotation_prefix, " main_constraint"));
/* now success_flag is constrained to either 0 (if index is out of
range) or \alpha_i. constrain it and \alpha_i to zero */
generate_boolean_r1cs_constraint<FieldT>(this->pb, success_flag, FMT(this->annotation_prefix, " success_flag"));
/* compute result */
compute_result->generate_r1cs_constraints();
}
template<typename FieldT>
void loose_multiplexing_gadget<FieldT>::generate_r1cs_witness()
{
/* assumes that idx can be fit in uint64_t; true for our purposes for now */
const bigint<FieldT::num_limbs> valint = this->pb.val(index).as_bigint();
uint64_t idx = valint.as_uint64();
const bigint<FieldT::num_limbs> arrsize(arr.size());
if (idx >= arr.size() || mpn_cmp(valint.data, arrsize.data, FieldT::num_limbs) >= 0)
{
for (size_t i = 0; i < arr.size(); ++i)
{
this->pb.val(alpha[i]) = FieldT::zero();
}
this->pb.val(success_flag) = FieldT::zero();
}
else
{
for (size_t i = 0; i < arr.size(); ++i)
{
this->pb.val(alpha[i]) = (i == idx ? FieldT::one() : FieldT::zero());
}
this->pb.val(success_flag) = FieldT::one();
}
compute_result->generate_r1cs_witness();
}
template<typename FieldT>
void test_loose_multiplexing_gadget(const size_t n)
{
printf("testing loose_multiplexing_gadget on 2**%zu pb_variable<FieldT> array inputs\n", n);
protoboard<FieldT> pb;
pb_variable_array<FieldT> arr;
arr.allocate(pb, UINT64_C(1)<<n, "arr");
pb_variable<FieldT> index, result, success_flag;
index.allocate(pb, "index");
result.allocate(pb, "result");
success_flag.allocate(pb, "success_flag");
loose_multiplexing_gadget<FieldT> g(pb, arr, index, result, success_flag, "g");
g.generate_r1cs_constraints();
for (size_t i = 0; i < UINT64_C(1)<<n; ++i)
{
pb.val(arr[i]) = FieldT((19*i) % (UINT64_C(1)<<n));
}
for (int idx = -1; idx <= (int)(UINT64_C(1)<<n); ++idx)
{
pb.val(index) = FieldT(idx);
g.generate_r1cs_witness();
if (0 <= idx && idx <= (int)(UINT64_C(1)<<n) - 1)
{
printf("demuxing element %d (in bounds)\n", idx);
assert(pb.val(result) == FieldT((19*idx) % (UINT64_C(1)<<n)));
assert(pb.val(success_flag) == FieldT::one());
assert(pb.is_satisfied());
pb.val(result) -= FieldT::one();
assert(!pb.is_satisfied());
}
else
{
printf("demuxing element %d (out of bounds)\n", idx);
assert(pb.val(success_flag) == FieldT::zero());
assert(pb.is_satisfied());
pb.val(success_flag) = FieldT::one();
assert(!pb.is_satisfied());
}
}
printf("loose_multiplexing_gadget tests successful\n");
}
template<typename FieldT, typename VarT>
void create_linear_combination_constraints(protoboard<FieldT> &pb,
const std::vector<FieldT> &base,
const std::vector<std::pair<VarT, FieldT> > &v,
const VarT &target,
const std::string &annotation_prefix)
{
for (size_t i = 0; i < base.size(); ++i)
{
linear_combination<FieldT> a, b, c;
a.add_term(ONE);
b.add_term(ONE, base[i]);
for (auto &p : v)
{
b.add_term(p.first.all_vars[i], p.second);
}
c.add_term(target.all_vars[i]);
pb.add_r1cs_constraint(r1cs_constraint<FieldT>(a, b, c), FMT(annotation_prefix, " linear_combination_%zu", i));
}
}
template<typename FieldT, typename VarT>
void create_linear_combination_witness(protoboard<FieldT> &pb,
const std::vector<FieldT> &base,
const std::vector<std::pair<VarT, FieldT> > &v,
const VarT &target)
{
for (size_t i = 0; i < base.size(); ++i)
{
pb.val(target.all_vars[i]) = base[i];
for (auto &p : v)
{
pb.val(target.all_vars[i]) += p.second * pb.val(p.first.all_vars[i]);
}
}
}
} // libsnark
#endif // BASIC_GADGETS_TCC_

45
src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.hpp

@ -1,45 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for a gadget that can be created from an R1CS constraint system.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef GADGET_FROM_R1CS_HPP_
#define GADGET_FROM_R1CS_HPP_
#include <map>
#include "gadgetlib1/gadget.hpp"
namespace libsnark {
template<typename FieldT>
class gadget_from_r1cs : public gadget<FieldT> {
private:
const std::vector<pb_variable_array<FieldT> > vars;
const r1cs_constraint_system<FieldT> cs;
std::map<size_t, size_t> cs_to_vars;
public:
gadget_from_r1cs(protoboard<FieldT> &pb,
const std::vector<pb_variable_array<FieldT> > &vars,
const r1cs_constraint_system<FieldT> &cs,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness(const r1cs_primary_input<FieldT> &primary_input,
const r1cs_auxiliary_input<FieldT> &auxiliary_input);
};
} // libsnark
#include "gadgetlib1/gadgets/gadget_from_r1cs.tcc"
#endif // GADGET_FROM_R1CS_HPP_

123
src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.tcc

@ -1,123 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for a gadget that can be created from an R1CS constraint system.
See gadget_from_r1cs.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef GADGET_FROM_R1CS_TCC_
#define GADGET_FROM_R1CS_TCC_
namespace libsnark {
template<typename FieldT>
gadget_from_r1cs<FieldT>::gadget_from_r1cs(protoboard<FieldT> &pb,
const std::vector<pb_variable_array<FieldT> > &vars,
const r1cs_constraint_system<FieldT> &cs,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
vars(vars),
cs(cs)
{
cs_to_vars[0] = 0; /* constant term maps to constant term */
size_t cs_var_idx = 1;
for (auto va : vars)
{
#ifdef DEBUG
printf("gadget_from_r1cs: translating a block of variables with length %zu\n", va.size());
#endif
for (auto v : va)
{
cs_to_vars[cs_var_idx] = v.index;
#ifdef DEBUG
if (v.index != 0)
{
// handle annotations, except for re-annotating constant term
const std::map<size_t, std::string>::const_iterator it = cs.variable_annotations.find(cs_var_idx);
std::string annotation = FMT(annotation_prefix, " variable_%zu", cs_var_idx);
if (it != cs.variable_annotations.end())
{
annotation = annotation_prefix + " " + it->second;
}
pb.augment_variable_annotation(v, annotation);
}
#endif
++cs_var_idx;
}
}
#ifdef DEBUG
printf("gadget_from_r1cs: sum of all block lengths: %zu\n", cs_var_idx-1);
printf("gadget_from_r1cs: cs.num_variables(): %zu\n", cs.num_variables());
#endif
assert(cs_var_idx - 1 == cs.num_variables());
}
template<typename FieldT>
void gadget_from_r1cs<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < cs.num_constraints(); ++i)
{
const r1cs_constraint<FieldT> &constr = cs.constraints[i];
r1cs_constraint<FieldT> translated_constr;
for (const linear_term<FieldT> &t: constr.a.terms)
{
translated_constr.a.terms.emplace_back(linear_term<FieldT>(pb_variable<FieldT>(cs_to_vars[t.index]), t.coeff));
}
for (const linear_term<FieldT> &t: constr.b.terms)
{
translated_constr.b.terms.emplace_back(linear_term<FieldT>(pb_variable<FieldT>(cs_to_vars[t.index]), t.coeff));
}
for (const linear_term<FieldT> &t: constr.c.terms)
{
translated_constr.c.terms.emplace_back(linear_term<FieldT>(pb_variable<FieldT>(cs_to_vars[t.index]), t.coeff));
}
std::string annotation = FMT(this->annotation_prefix, " constraint_%zu", i);
#ifdef DEBUG
auto it = cs.constraint_annotations.find(i);
if (it != cs.constraint_annotations.end())
{
annotation = this->annotation_prefix + " " + it->second;
}
#endif
this->pb.add_r1cs_constraint(translated_constr, annotation);
}
}
template<typename FieldT>
void gadget_from_r1cs<FieldT>::generate_r1cs_witness(const r1cs_primary_input<FieldT> &primary_input,
const r1cs_auxiliary_input<FieldT> &auxiliary_input)
{
assert(cs.num_inputs() == primary_input.size());
assert(cs.num_variables() == primary_input.size() + auxiliary_input.size());
for (size_t i = 0; i < primary_input.size(); ++i)
{
this->pb.val(pb_variable<FieldT>(cs_to_vars[i+1])) = primary_input[i];
}
for (size_t i = 0; i < auxiliary_input.size(); ++i)
{
this->pb.val(pb_variable<FieldT>(cs_to_vars[primary_input.size()+i+1])) = auxiliary_input[i];
}
}
} // libsnark
#endif // GADGET_FROM_R1CS_TCC_

42
src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp

@ -1,42 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef DIGEST_SELECTOR_GADGET_HPP_
#define DIGEST_SELECTOR_GADGET_HPP_
#include <vector>
#include "gadgetlib1/gadgets/basic_gadgets.hpp"
#include "gadgetlib1/gadgets/hashes/hash_io.hpp"
namespace libsnark {
template<typename FieldT>
class digest_selector_gadget : public gadget<FieldT> {
public:
size_t digest_size;
digest_variable<FieldT> input;
pb_linear_combination<FieldT> is_right;
digest_variable<FieldT> left;
digest_variable<FieldT> right;
digest_selector_gadget(protoboard<FieldT> &pb,
const size_t digest_size,
const digest_variable<FieldT> &input,
const pb_linear_combination<FieldT> &is_right,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
} // libsnark
#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc"
#endif // DIGEST_SELECTOR_GADGET_HPP_

62
src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc

@ -1,62 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef DIGEST_SELECTOR_GADGET_TCC_
#define DIGEST_SELECTOR_GADGET_TCC_
namespace libsnark {
template<typename FieldT>
digest_selector_gadget<FieldT>::digest_selector_gadget(protoboard<FieldT> &pb,
const size_t digest_size,
const digest_variable<FieldT> &input,
const pb_linear_combination<FieldT> &is_right,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix), digest_size(digest_size), input(input), is_right(is_right), left(left), right(right)
{
}
template<typename FieldT>
void digest_selector_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < digest_size; ++i)
{
/*
input = is_right * right + (1-is_right) * left
input - left = is_right(right - left)
*/
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(is_right, right.bits[i] - left.bits[i], input.bits[i] - left.bits[i]),
FMT(this->annotation_prefix, " propagate_%zu", i));
}
}
template<typename FieldT>
void digest_selector_gadget<FieldT>::generate_r1cs_witness()
{
is_right.evaluate(this->pb);
assert(this->pb.lc_val(is_right) == FieldT::one() || this->pb.lc_val(is_right) == FieldT::zero());
if (this->pb.lc_val(is_right) == FieldT::one())
{
for (size_t i = 0; i < digest_size; ++i)
{
this->pb.val(right.bits[i]) = this->pb.val(input.bits[i]);
}
}
else
{
for (size_t i = 0; i < digest_size; ++i)
{
this->pb.val(left.bits[i]) = this->pb.val(input.bits[i]);
}
}
}
} // libsnark
#endif // DIGEST_SELECTOR_GADGET_TCC_

63
src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.hpp

@ -1,63 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef HASH_IO_HPP_
#define HASH_IO_HPP_
#include <cstddef>
#include <vector>
#include "gadgetlib1/gadgets/basic_gadgets.hpp"
namespace libsnark {
template<typename FieldT>
class digest_variable : public gadget<FieldT> {
public:
size_t digest_size;
pb_variable_array<FieldT> bits;
digest_variable<FieldT>(protoboard<FieldT> &pb,
const size_t digest_size,
const std::string &annotation_prefix);
digest_variable<FieldT>(protoboard<FieldT> &pb,
const size_t digest_size,
const pb_variable_array<FieldT> &partial_bits,
const pb_variable<FieldT> &padding,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness(const bit_vector& contents);
bit_vector get_digest() const;
};
template<typename FieldT>
class block_variable : public gadget<FieldT> {
public:
size_t block_size;
pb_variable_array<FieldT> bits;
block_variable(protoboard<FieldT> &pb,
const size_t block_size,
const std::string &annotation_prefix);
block_variable(protoboard<FieldT> &pb,
const std::vector<pb_variable_array<FieldT> > &parts,
const std::string &annotation_prefix);
block_variable(protoboard<FieldT> &pb,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness(const bit_vector& contents);
bit_vector get_block() const;
};
} // libsnark
#include "gadgetlib1/gadgets/hashes/hash_io.tcc"
#endif // HASH_IO_HPP_

105
src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.tcc

@ -1,105 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef HASH_IO_TCC_
#define HASH_IO_TCC_
namespace libsnark {
template<typename FieldT>
digest_variable<FieldT>::digest_variable(protoboard<FieldT> &pb,
const size_t digest_size,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix), digest_size(digest_size)
{
bits.allocate(pb, digest_size, FMT(this->annotation_prefix, " bits"));
}
template<typename FieldT>
digest_variable<FieldT>::digest_variable(protoboard<FieldT> &pb,
const size_t digest_size,
const pb_variable_array<FieldT> &partial_bits,
const pb_variable<FieldT> &padding,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix), digest_size(digest_size)
{
assert(bits.size() <= digest_size);
bits = partial_bits;
while (bits.size() != digest_size)
{
bits.emplace_back(padding);
}
}
template<typename FieldT>
void digest_variable<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < digest_size; ++i)
{
generate_boolean_r1cs_constraint<FieldT>(this->pb, bits[i], FMT(this->annotation_prefix, " bits_%zu", i));
}
}
template<typename FieldT>
void digest_variable<FieldT>::generate_r1cs_witness(const bit_vector& contents)
{
bits.fill_with_bits(this->pb, contents);
}
template<typename FieldT>
bit_vector digest_variable<FieldT>::get_digest() const
{
return bits.get_bits(this->pb);
}
template<typename FieldT>
block_variable<FieldT>::block_variable(protoboard<FieldT> &pb,
const size_t block_size,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix), block_size(block_size)
{
bits.allocate(pb, block_size, FMT(this->annotation_prefix, " bits"));
}
template<typename FieldT>
block_variable<FieldT>::block_variable(protoboard<FieldT> &pb,
const std::vector<pb_variable_array<FieldT> > &parts,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix)
{
for (auto &part : parts)
{
bits.insert(bits.end(), part.begin(), part.end());
}
}
template<typename FieldT>
block_variable<FieldT>::block_variable(protoboard<FieldT> &pb,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix)
{
assert(left.bits.size() == right.bits.size());
block_size = 2 * left.bits.size();
bits.insert(bits.end(), left.bits.begin(), left.bits.end());
bits.insert(bits.end(), right.bits.begin(), right.bits.end());
}
template<typename FieldT>
void block_variable<FieldT>::generate_r1cs_witness(const bit_vector& contents)
{
bits.fill_with_bits(this->pb, contents);
}
template<typename FieldT>
bit_vector block_variable<FieldT>::get_block() const
{
return bits.get_bits(this->pb);
}
} // libsnark
#endif // HASH_IO_TCC_

160
src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp

@ -1,160 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for auxiliary gadgets for the SHA256 gadget.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_AUX_HPP_
#define SHA256_AUX_HPP_
#include "gadgetlib1/gadgets/basic_gadgets.hpp"
namespace libsnark {
template<typename FieldT>
class lastbits_gadget : public gadget<FieldT> {
public:
pb_variable<FieldT> X;
size_t X_bits;
pb_variable<FieldT> result;
pb_linear_combination_array<FieldT> result_bits;
pb_linear_combination_array<FieldT> full_bits;
std::shared_ptr<packing_gadget<FieldT> > unpack_bits;
std::shared_ptr<packing_gadget<FieldT> > pack_result;
lastbits_gadget(protoboard<FieldT> &pb,
const pb_variable<FieldT> &X,
const size_t X_bits,
const pb_variable<FieldT> &result,
const pb_linear_combination_array<FieldT> &result_bits,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
template<typename FieldT>
class XOR3_gadget : public gadget<FieldT> {
private:
pb_variable<FieldT> tmp;
public:
pb_linear_combination<FieldT> A;
pb_linear_combination<FieldT> B;
pb_linear_combination<FieldT> C;
bool assume_C_is_zero;
pb_linear_combination<FieldT> out;
XOR3_gadget(protoboard<FieldT> &pb,
const pb_linear_combination<FieldT> &A,
const pb_linear_combination<FieldT> &B,
const pb_linear_combination<FieldT> &C,
const bool assume_C_is_zero,
const pb_linear_combination<FieldT> &out,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
class small_sigma_gadget : public gadget<FieldT> {
private:
pb_variable_array<FieldT> W;
pb_variable<FieldT> result;
public:
pb_variable_array<FieldT> result_bits;
std::vector<std::shared_ptr<XOR3_gadget<FieldT> > > compute_bits;
std::shared_ptr<packing_gadget<FieldT> > pack_result;
small_sigma_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &W,
const pb_variable<FieldT> &result,
const size_t rot1,
const size_t rot2,
const size_t shift,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
class big_sigma_gadget : public gadget<FieldT> {
private:
pb_linear_combination_array<FieldT> W;
pb_variable<FieldT> result;
public:
pb_variable_array<FieldT> result_bits;
std::vector<std::shared_ptr<XOR3_gadget<FieldT> > > compute_bits;
std::shared_ptr<packing_gadget<FieldT> > pack_result;
big_sigma_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &W,
const pb_variable<FieldT> &result,
const size_t rot1,
const size_t rot2,
const size_t rot3,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
class choice_gadget : public gadget<FieldT> {
private:
pb_variable_array<FieldT> result_bits;
public:
pb_linear_combination_array<FieldT> X;
pb_linear_combination_array<FieldT> Y;
pb_linear_combination_array<FieldT> Z;
pb_variable<FieldT> result;
std::shared_ptr<packing_gadget<FieldT> > pack_result;
choice_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &X,
const pb_linear_combination_array<FieldT> &Y,
const pb_linear_combination_array<FieldT> &Z,
const pb_variable<FieldT> &result, const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
class majority_gadget : public gadget<FieldT> {
private:
pb_variable_array<FieldT> result_bits;
std::shared_ptr<packing_gadget<FieldT> > pack_result;
public:
pb_linear_combination_array<FieldT> X;
pb_linear_combination_array<FieldT> Y;
pb_linear_combination_array<FieldT> Z;
pb_variable<FieldT> result;
majority_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &X,
const pb_linear_combination_array<FieldT> &Y,
const pb_linear_combination_array<FieldT> &Z,
const pb_variable<FieldT> &result,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
} // libsnark
#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc"
#endif // SHA256_AUX_HPP_

297
src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc

@ -1,297 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for auxiliary gadgets for the SHA256 gadget.
See sha256_aux.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_AUX_TCC_
#define SHA256_AUX_TCC_
namespace libsnark {
template<typename FieldT>
lastbits_gadget<FieldT>::lastbits_gadget(protoboard<FieldT> &pb,
const pb_variable<FieldT> &X,
const size_t X_bits,
const pb_variable<FieldT> &result,
const pb_linear_combination_array<FieldT> &result_bits,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
X(X),
X_bits(X_bits),
result(result),
result_bits(result_bits)
{
full_bits = result_bits;
for (size_t i = result_bits.size(); i < X_bits; ++i)
{
pb_variable<FieldT> full_bits_overflow;
full_bits_overflow.allocate(pb, FMT(this->annotation_prefix, " full_bits_%zu", i));
full_bits.emplace_back(full_bits_overflow);
}
unpack_bits.reset(new packing_gadget<FieldT>(pb, full_bits, X, FMT(this->annotation_prefix, " unpack_bits")));
pack_result.reset(new packing_gadget<FieldT>(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result")));
}
template<typename FieldT>
void lastbits_gadget<FieldT>::generate_r1cs_constraints()
{
unpack_bits->generate_r1cs_constraints(true);
pack_result->generate_r1cs_constraints(false);
}
template<typename FieldT>
void lastbits_gadget<FieldT>::generate_r1cs_witness()
{
unpack_bits->generate_r1cs_witness_from_packed();
pack_result->generate_r1cs_witness_from_bits();
}
template<typename FieldT>
XOR3_gadget<FieldT>::XOR3_gadget(protoboard<FieldT> &pb,
const pb_linear_combination<FieldT> &A,
const pb_linear_combination<FieldT> &B,
const pb_linear_combination<FieldT> &C,
const bool assume_C_is_zero,
const pb_linear_combination<FieldT> &out,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
A(A),
B(B),
C(C),
assume_C_is_zero(assume_C_is_zero),
out(out)
{
if (!assume_C_is_zero)
{
tmp.allocate(pb, FMT(this->annotation_prefix, " tmp"));
}
}
template<typename FieldT>
void XOR3_gadget<FieldT>::generate_r1cs_constraints()
{
/*
tmp = A + B - 2AB i.e. tmp = A xor B
out = tmp + C - 2tmp C i.e. out = tmp xor C
*/
if (assume_C_is_zero)
{
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(2*A, B, A + B - out), FMT(this->annotation_prefix, " implicit_tmp_equals_out"));
}
else
{
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(2*A, B, A + B - tmp), FMT(this->annotation_prefix, " tmp"));
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(2 * tmp, C, tmp + C - out), FMT(this->annotation_prefix, " out"));
}
}
template<typename FieldT>
void XOR3_gadget<FieldT>::generate_r1cs_witness()
{
if (assume_C_is_zero)
{
this->pb.lc_val(out) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B);
}
else
{
this->pb.val(tmp) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B);
this->pb.lc_val(out) = this->pb.val(tmp) + this->pb.lc_val(C) - FieldT(2) * this->pb.val(tmp) * this->pb.lc_val(C);
}
}
#define SHA256_GADGET_ROTR(A, i, k) A[((i)+(k)) % 32]
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
small_sigma_gadget<FieldT>::small_sigma_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &W,
const pb_variable<FieldT> &result,
const size_t rot1,
const size_t rot2,
const size_t shift,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
W(W),
result(result)
{
result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
compute_bits.resize(32);
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i].reset(new XOR3_gadget<FieldT>(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2),
(i + shift < 32 ? W[i+shift] : ONE),
(i + shift >= 32), result_bits[i],
FMT(this->annotation_prefix, " compute_bits_%zu", i)));
}
pack_result.reset(new packing_gadget<FieldT>(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result")));
}
template<typename FieldT>
void small_sigma_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i]->generate_r1cs_constraints();
}
pack_result->generate_r1cs_constraints(false);
}
template<typename FieldT>
void small_sigma_gadget<FieldT>::generate_r1cs_witness()
{
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i]->generate_r1cs_witness();
}
pack_result->generate_r1cs_witness_from_bits();
}
template<typename FieldT>
big_sigma_gadget<FieldT>::big_sigma_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &W,
const pb_variable<FieldT> &result,
const size_t rot1,
const size_t rot2,
const size_t rot3,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
W(W),
result(result)
{
result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
compute_bits.resize(32);
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i].reset(new XOR3_gadget<FieldT>(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2), SHA256_GADGET_ROTR(W, i, rot3), false, result_bits[i],
FMT(this->annotation_prefix, " compute_bits_%zu", i)));
}
pack_result.reset(new packing_gadget<FieldT>(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result")));
}
template<typename FieldT>
void big_sigma_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i]->generate_r1cs_constraints();
}
pack_result->generate_r1cs_constraints(false);
}
template<typename FieldT>
void big_sigma_gadget<FieldT>::generate_r1cs_witness()
{
for (size_t i = 0; i < 32; ++i)
{
compute_bits[i]->generate_r1cs_witness();
}
pack_result->generate_r1cs_witness_from_bits();
}
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
choice_gadget<FieldT>::choice_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &X,
const pb_linear_combination_array<FieldT> &Y,
const pb_linear_combination_array<FieldT> &Z,
const pb_variable<FieldT> &result, const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
X(X),
Y(Y),
Z(Z),
result(result)
{
result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
pack_result.reset(new packing_gadget<FieldT>(pb, result_bits, result, FMT(this->annotation_prefix, " result")));
}
template<typename FieldT>
void choice_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < 32; ++i)
{
/*
result = x * y + (1-x) * z
result - z = x * (y - z)
*/
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(X[i], Y[i] - Z[i], result_bits[i] - Z[i]), FMT(this->annotation_prefix, " result_bits_%zu", i));
}
pack_result->generate_r1cs_constraints(false);
}
template<typename FieldT>
void choice_gadget<FieldT>::generate_r1cs_witness()
{
for (size_t i = 0; i < 32; ++i)
{
this->pb.val(result_bits[i]) = this->pb.lc_val(X[i]) * this->pb.lc_val(Y[i]) + (FieldT::one() - this->pb.lc_val(X[i])) * this->pb.lc_val(Z[i]);
}
pack_result->generate_r1cs_witness_from_bits();
}
/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
template<typename FieldT>
majority_gadget<FieldT>::majority_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &X,
const pb_linear_combination_array<FieldT> &Y,
const pb_linear_combination_array<FieldT> &Z,
const pb_variable<FieldT> &result,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
X(X),
Y(Y),
Z(Z),
result(result)
{
result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
pack_result.reset(new packing_gadget<FieldT>(pb, result_bits, result, FMT(this->annotation_prefix, " result")));
}
template<typename FieldT>
void majority_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < 32; ++i)
{
/*
2*result + aux = x + y + z
x, y, z, aux -- bits
aux = x + y + z - 2*result
*/
generate_boolean_r1cs_constraint<FieldT>(this->pb, result_bits[i], FMT(this->annotation_prefix, " result_%zu", i));
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(X[i] + Y[i] + Z[i] - 2 * result_bits[i],
1 - (X[i] + Y[i] + Z[i] - 2 * result_bits[i]),
0),
FMT(this->annotation_prefix, " result_bits_%zu", i));
}
pack_result->generate_r1cs_constraints(false);
}
template<typename FieldT>
void majority_gadget<FieldT>::generate_r1cs_witness()
{
for (size_t i = 0; i < 32; ++i)
{
const uint64_t v = (this->pb.lc_val(X[i]) + this->pb.lc_val(Y[i]) + this->pb.lc_val(Z[i])).as_uint64();
this->pb.val(result_bits[i]) = FieldT(v / 2);
}
pack_result->generate_r1cs_witness_from_bits();
}
} // libsnark
#endif // SHA256_AUX_TCC_

108
src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp

@ -1,108 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for gadgets for the SHA256 message schedule and round function.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_COMPONENTS_HPP_
#define SHA256_COMPONENTS_HPP_
#include "gadgetlib1/gadgets/basic_gadgets.hpp"
#include "gadgetlib1/gadgets/hashes/hash_io.hpp"
#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp"
namespace libsnark {
const size_t SHA256_digest_size = 256;
const size_t SHA256_block_size = 512;
template<typename FieldT>
pb_linear_combination_array<FieldT> SHA256_default_IV(protoboard<FieldT> &pb);
template<typename FieldT>
class sha256_message_schedule_gadget : public gadget<FieldT> {
public:
std::vector<pb_variable_array<FieldT> > W_bits;
std::vector<std::shared_ptr<packing_gadget<FieldT> > > pack_W;
std::vector<pb_variable<FieldT> > sigma0;
std::vector<pb_variable<FieldT> > sigma1;
std::vector<std::shared_ptr<small_sigma_gadget<FieldT> > > compute_sigma0;
std::vector<std::shared_ptr<small_sigma_gadget<FieldT> > > compute_sigma1;
std::vector<pb_variable<FieldT> > unreduced_W;
std::vector<std::shared_ptr<lastbits_gadget<FieldT> > > mod_reduce_W;
public:
pb_variable_array<FieldT> M;
pb_variable_array<FieldT> packed_W;
sha256_message_schedule_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &M,
const pb_variable_array<FieldT> &packed_W,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
template<typename FieldT>
class sha256_round_function_gadget : public gadget<FieldT> {
public:
pb_variable<FieldT> sigma0;
pb_variable<FieldT> sigma1;
std::shared_ptr<big_sigma_gadget<FieldT> > compute_sigma0;
std::shared_ptr<big_sigma_gadget<FieldT> > compute_sigma1;
pb_variable<FieldT> choice;
pb_variable<FieldT> majority;
std::shared_ptr<choice_gadget<FieldT> > compute_choice;
std::shared_ptr<majority_gadget<FieldT> > compute_majority;
pb_variable<FieldT> packed_d;
std::shared_ptr<packing_gadget<FieldT> > pack_d;
pb_variable<FieldT> packed_h;
std::shared_ptr<packing_gadget<FieldT> > pack_h;
pb_variable<FieldT> unreduced_new_a;
pb_variable<FieldT> unreduced_new_e;
std::shared_ptr<lastbits_gadget<FieldT> > mod_reduce_new_a;
std::shared_ptr<lastbits_gadget<FieldT> > mod_reduce_new_e;
pb_variable<FieldT> packed_new_a;
pb_variable<FieldT> packed_new_e;
public:
pb_linear_combination_array<FieldT> a;
pb_linear_combination_array<FieldT> b;
pb_linear_combination_array<FieldT> c;
pb_linear_combination_array<FieldT> d;
pb_linear_combination_array<FieldT> e;
pb_linear_combination_array<FieldT> f;
pb_linear_combination_array<FieldT> g;
pb_linear_combination_array<FieldT> h;
pb_variable<FieldT> W;
uint32_t K;
pb_linear_combination_array<FieldT> new_a;
pb_linear_combination_array<FieldT> new_e;
sha256_round_function_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &a,
const pb_linear_combination_array<FieldT> &b,
const pb_linear_combination_array<FieldT> &c,
const pb_linear_combination_array<FieldT> &d,
const pb_linear_combination_array<FieldT> &e,
const pb_linear_combination_array<FieldT> &f,
const pb_linear_combination_array<FieldT> &g,
const pb_linear_combination_array<FieldT> &h,
const pb_variable<FieldT> &W,
const uint32_t &K,
const pb_linear_combination_array<FieldT> &new_a,
const pb_linear_combination_array<FieldT> &new_e,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
} // libsnark
#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc"
#endif // SHA256_COMPONENTS_HPP_

250
src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc

@ -1,250 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for gadgets for the SHA256 message schedule and round function.
See sha256_components.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_COMPONENTS_TCC_
#define SHA256_COMPONENTS_TCC_
namespace libsnark {
const uint32_t SHA256_K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
const uint32_t SHA256_H[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
template<typename FieldT>
pb_linear_combination_array<FieldT> SHA256_default_IV(protoboard<FieldT> &pb)
{
pb_linear_combination_array<FieldT> result;
result.reserve(SHA256_digest_size);
for (size_t i = 0; i < SHA256_digest_size; ++i)
{
int iv_val = (SHA256_H[i / 32] >> (31-(i % 32))) & 1;
pb_linear_combination<FieldT> iv_element;
iv_element.assign(pb, iv_val * ONE);
iv_element.evaluate(pb);
result.emplace_back(iv_element);
}
return result;
}
template<typename FieldT>
sha256_message_schedule_gadget<FieldT>::sha256_message_schedule_gadget(protoboard<FieldT> &pb,
const pb_variable_array<FieldT> &M,
const pb_variable_array<FieldT> &packed_W,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
M(M),
packed_W(packed_W)
{
W_bits.resize(64);
pack_W.resize(16);
for (size_t i = 0; i < 16; ++i)
{
W_bits[i] = pb_variable_array<FieldT>(M.rbegin() + (15-i) * 32, M.rbegin() + (16-i) * 32);
pack_W[i].reset(new packing_gadget<FieldT>(pb, W_bits[i], packed_W[i], FMT(this->annotation_prefix, " pack_W_%zu", i)));
}
/* NB: some of those will be un-allocated */
sigma0.resize(64);
sigma1.resize(64);
compute_sigma0.resize(64);
compute_sigma1.resize(64);
unreduced_W.resize(64);
mod_reduce_W.resize(64);
for (size_t i = 16; i < 64; ++i)
{
/* allocate result variables for sigma0/sigma1 invocations */
sigma0[i].allocate(pb, FMT(this->annotation_prefix, " sigma0_%zu", i));
sigma1[i].allocate(pb, FMT(this->annotation_prefix, " sigma1_%zu", i));
/* compute sigma0/sigma1 */
compute_sigma0[i].reset(new small_sigma_gadget<FieldT>(pb, W_bits[i-15], sigma0[i], 7, 18, 3, FMT(this->annotation_prefix, " compute_sigma0_%zu", i)));
compute_sigma1[i].reset(new small_sigma_gadget<FieldT>(pb, W_bits[i-2], sigma1[i], 17, 19, 10, FMT(this->annotation_prefix, " compute_sigma1_%zu", i)));
/* unreduced_W = sigma0(W_{i-15}) + sigma1(W_{i-2}) + W_{i-7} + W_{i-16} before modulo 2^32 */
unreduced_W[i].allocate(pb, FMT(this->annotation_prefix, "unreduced_W_%zu", i));
/* allocate the bit representation of packed_W[i] */
W_bits[i].allocate(pb, 32, FMT(this->annotation_prefix, " W_bits_%zu", i));
/* and finally reduce this into packed and bit representations */
mod_reduce_W[i].reset(new lastbits_gadget<FieldT>(pb, unreduced_W[i], 32+2, packed_W[i], W_bits[i], FMT(this->annotation_prefix, " mod_reduce_W_%zu", i)));
}
}
template<typename FieldT>
void sha256_message_schedule_gadget<FieldT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < 16; ++i)
{
pack_W[i]->generate_r1cs_constraints(false); // do not enforce bitness here; caller be aware.
}
for (size_t i = 16; i < 64; ++i)
{
compute_sigma0[i]->generate_r1cs_constraints();
compute_sigma1[i]->generate_r1cs_constraints();
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1,
sigma0[i] + sigma1[i] + packed_W[i-16] + packed_W[i-7],
unreduced_W[i]),
FMT(this->annotation_prefix, " unreduced_W_%zu", i));
mod_reduce_W[i]->generate_r1cs_constraints();
}
}
template<typename FieldT>
void sha256_message_schedule_gadget<FieldT>::generate_r1cs_witness()
{
for (size_t i = 0; i < 16; ++i)
{
pack_W[i]->generate_r1cs_witness_from_bits();
}
for (size_t i = 16; i < 64; ++i)
{
compute_sigma0[i]->generate_r1cs_witness();
compute_sigma1[i]->generate_r1cs_witness();
this->pb.val(unreduced_W[i]) = this->pb.val(sigma0[i]) + this->pb.val(sigma1[i]) + this->pb.val(packed_W[i-16]) + this->pb.val(packed_W[i-7]);
mod_reduce_W[i]->generate_r1cs_witness();
}
}
template<typename FieldT>
sha256_round_function_gadget<FieldT>::sha256_round_function_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &a,
const pb_linear_combination_array<FieldT> &b,
const pb_linear_combination_array<FieldT> &c,
const pb_linear_combination_array<FieldT> &d,
const pb_linear_combination_array<FieldT> &e,
const pb_linear_combination_array<FieldT> &f,
const pb_linear_combination_array<FieldT> &g,
const pb_linear_combination_array<FieldT> &h,
const pb_variable<FieldT> &W,
const uint32_t &K,
const pb_linear_combination_array<FieldT> &new_a,
const pb_linear_combination_array<FieldT> &new_e,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
a(a),
b(b),
c(c),
d(d),
e(e),
f(f),
g(g),
h(h),
W(W),
K(K),
new_a(new_a),
new_e(new_e)
{
/* compute sigma0 and sigma1 */
sigma0.allocate(pb, FMT(this->annotation_prefix, " sigma0"));
sigma1.allocate(pb, FMT(this->annotation_prefix, " sigma1"));
compute_sigma0.reset(new big_sigma_gadget<FieldT>(pb, a, sigma0, 2, 13, 22, FMT(this->annotation_prefix, " compute_sigma0")));
compute_sigma1.reset(new big_sigma_gadget<FieldT>(pb, e, sigma1, 6, 11, 25, FMT(this->annotation_prefix, " compute_sigma1")));
/* compute choice */
choice.allocate(pb, FMT(this->annotation_prefix, " choice"));
compute_choice.reset(new choice_gadget<FieldT>(pb, e, f, g, choice, FMT(this->annotation_prefix, " compute_choice")));
/* compute majority */
majority.allocate(pb, FMT(this->annotation_prefix, " majority"));
compute_majority.reset(new majority_gadget<FieldT>(pb, a, b, c, majority, FMT(this->annotation_prefix, " compute_majority")));
/* pack d */
packed_d.allocate(pb, FMT(this->annotation_prefix, " packed_d"));
pack_d.reset(new packing_gadget<FieldT>(pb, d, packed_d, FMT(this->annotation_prefix, " pack_d")));
/* pack h */
packed_h.allocate(pb, FMT(this->annotation_prefix, " packed_h"));
pack_h.reset(new packing_gadget<FieldT>(pb, h, packed_h, FMT(this->annotation_prefix, " pack_h")));
/* compute the actual results for the round */
unreduced_new_a.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_a"));
unreduced_new_e.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_e"));
packed_new_a.allocate(pb, FMT(this->annotation_prefix, " packed_new_a"));
packed_new_e.allocate(pb, FMT(this->annotation_prefix, " packed_new_e"));
mod_reduce_new_a.reset(new lastbits_gadget<FieldT>(pb, unreduced_new_a, 32+3, packed_new_a, new_a, FMT(this->annotation_prefix, " mod_reduce_new_a")));
mod_reduce_new_e.reset(new lastbits_gadget<FieldT>(pb, unreduced_new_e, 32+3, packed_new_e, new_e, FMT(this->annotation_prefix, " mod_reduce_new_e")));
}
template<typename FieldT>
void sha256_round_function_gadget<FieldT>::generate_r1cs_constraints()
{
compute_sigma0->generate_r1cs_constraints();
compute_sigma1->generate_r1cs_constraints();
compute_choice->generate_r1cs_constraints();
compute_majority->generate_r1cs_constraints();
pack_d->generate_r1cs_constraints(false);
pack_h->generate_r1cs_constraints(false);
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1,
packed_h + sigma1 + choice + K + W + sigma0 + majority,
unreduced_new_a),
FMT(this->annotation_prefix, " unreduced_new_a"));
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1,
packed_d + packed_h + sigma1 + choice + K + W,
unreduced_new_e),
FMT(this->annotation_prefix, " unreduced_new_e"));
mod_reduce_new_a->generate_r1cs_constraints();
mod_reduce_new_e->generate_r1cs_constraints();
}
template<typename FieldT>
void sha256_round_function_gadget<FieldT>::generate_r1cs_witness()
{
compute_sigma0->generate_r1cs_witness();
compute_sigma1->generate_r1cs_witness();
compute_choice->generate_r1cs_witness();
compute_majority->generate_r1cs_witness();
pack_d->generate_r1cs_witness_from_bits();
pack_h->generate_r1cs_witness_from_bits();
this->pb.val(unreduced_new_a) = this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W) + this->pb.val(sigma0) + this->pb.val(majority);
this->pb.val(unreduced_new_e) = this->pb.val(packed_d) + this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W);
mod_reduce_new_a->generate_r1cs_witness();
mod_reduce_new_e->generate_r1cs_witness();
}
} // libsnark
#endif // SHA256_COMPONENTS_TCC_

98
src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp

@ -1,98 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for top-level SHA256 gadgets.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_GADGET_HPP_
#define SHA256_GADGET_HPP_
#include "common/data_structures/merkle_tree.hpp"
#include "gadgetlib1/gadgets/basic_gadgets.hpp"
#include "gadgetlib1/gadgets/hashes/hash_io.hpp"
#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp"
namespace libsnark {
/**
* Gadget for the SHA256 compression function.
*/
template<typename FieldT>
class sha256_compression_function_gadget : public gadget<FieldT> {
public:
std::vector<pb_linear_combination_array<FieldT> > round_a;
std::vector<pb_linear_combination_array<FieldT> > round_b;
std::vector<pb_linear_combination_array<FieldT> > round_c;
std::vector<pb_linear_combination_array<FieldT> > round_d;
std::vector<pb_linear_combination_array<FieldT> > round_e;
std::vector<pb_linear_combination_array<FieldT> > round_f;
std::vector<pb_linear_combination_array<FieldT> > round_g;
std::vector<pb_linear_combination_array<FieldT> > round_h;
pb_variable_array<FieldT> packed_W;
std::shared_ptr<sha256_message_schedule_gadget<FieldT> > message_schedule;
std::vector<sha256_round_function_gadget<FieldT> > round_functions;
pb_variable_array<FieldT> unreduced_output;
pb_variable_array<FieldT> reduced_output;
std::vector<lastbits_gadget<FieldT> > reduce_output;
public:
pb_linear_combination_array<FieldT> prev_output;
pb_variable_array<FieldT> new_block;
digest_variable<FieldT> output;
sha256_compression_function_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &prev_output,
const pb_variable_array<FieldT> &new_block,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
};
/**
* Gadget for the SHA256 compression function, viewed as a 2-to-1 hash
* function, and using the same initialization vector as in SHA256
* specification. Thus, any collision for
* sha256_two_to_one_hash_gadget trivially extends to a collision for
* full SHA256 (by appending the same padding).
*/
template<typename FieldT>
class sha256_two_to_one_hash_gadget : public gadget<FieldT> {
public:
typedef bit_vector hash_value_type;
typedef merkle_authentication_path merkle_authentication_path_type;
std::shared_ptr<sha256_compression_function_gadget<FieldT> > f;
sha256_two_to_one_hash_gadget(protoboard<FieldT> &pb,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix);
sha256_two_to_one_hash_gadget(protoboard<FieldT> &pb,
const size_t block_length,
const block_variable<FieldT> &input_block,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix);
void generate_r1cs_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now
void generate_r1cs_witness();
static size_t get_block_len();
static size_t get_digest_len();
static bit_vector get_hash(const bit_vector &input);
static size_t expected_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now
};
} // libsnark
#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc"
#endif // SHA256_GADGET_HPP_

230
src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc

@ -1,230 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for top-level SHA256 gadgets.
See sha256_gadget.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef SHA256_GADGET_TCC_
#define SHA256_GADGET_TCC_
namespace libsnark {
template<typename FieldT>
sha256_compression_function_gadget<FieldT>::sha256_compression_function_gadget(protoboard<FieldT> &pb,
const pb_linear_combination_array<FieldT> &prev_output,
const pb_variable_array<FieldT> &new_block,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
prev_output(prev_output),
new_block(new_block),
output(output)
{
/* message schedule and inputs for it */
packed_W.allocate(pb, 64, FMT(this->annotation_prefix, " packed_W"));
message_schedule.reset(new sha256_message_schedule_gadget<FieldT>(pb, new_block, packed_W, FMT(this->annotation_prefix, " message_schedule")));
/* initalize */
round_a.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 7*32, prev_output.rbegin() + 8*32));
round_b.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 6*32, prev_output.rbegin() + 7*32));
round_c.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 5*32, prev_output.rbegin() + 6*32));
round_d.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 4*32, prev_output.rbegin() + 5*32));
round_e.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 3*32, prev_output.rbegin() + 4*32));
round_f.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 2*32, prev_output.rbegin() + 3*32));
round_g.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 1*32, prev_output.rbegin() + 2*32));
round_h.push_back(pb_linear_combination_array<FieldT>(prev_output.rbegin() + 0*32, prev_output.rbegin() + 1*32));
/* do the rounds */
for (size_t i = 0; i < 64; ++i)
{
round_h.push_back(round_g[i]);
round_g.push_back(round_f[i]);
round_f.push_back(round_e[i]);
round_d.push_back(round_c[i]);
round_c.push_back(round_b[i]);
round_b.push_back(round_a[i]);
pb_variable_array<FieldT> new_round_a_variables;
new_round_a_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_a_variables_%zu", i+1));
round_a.emplace_back(new_round_a_variables);
pb_variable_array<FieldT> new_round_e_variables;
new_round_e_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_e_variables_%zu", i+1));
round_e.emplace_back(new_round_e_variables);
round_functions.push_back(sha256_round_function_gadget<FieldT>(pb,
round_a[i], round_b[i], round_c[i], round_d[i],
round_e[i], round_f[i], round_g[i], round_h[i],
packed_W[i], SHA256_K[i], round_a[i+1], round_e[i+1],
FMT(this->annotation_prefix, " round_functions_%zu", i)));
}
/* finalize */
unreduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " unreduced_output"));
reduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " reduced_output"));
for (size_t i = 0; i < 8; ++i)
{
reduce_output.push_back(lastbits_gadget<FieldT>(pb,
unreduced_output[i],
32+1,
reduced_output[i],
pb_variable_array<FieldT>(output.bits.rbegin() + (7-i) * 32, output.bits.rbegin() + (8-i) * 32),
FMT(this->annotation_prefix, " reduce_output_%zu", i)));
}
}
template<typename FieldT>
void sha256_compression_function_gadget<FieldT>::generate_r1cs_constraints()
{
message_schedule->generate_r1cs_constraints();
for (size_t i = 0; i < 64; ++i)
{
round_functions[i].generate_r1cs_constraints();
}
for (size_t i = 0; i < 4; ++i)
{
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1,
round_functions[3-i].packed_d + round_functions[63-i].packed_new_a,
unreduced_output[i]),
FMT(this->annotation_prefix, " unreduced_output_%zu", i));
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1,
round_functions[3-i].packed_h + round_functions[63-i].packed_new_e,
unreduced_output[4+i]),
FMT(this->annotation_prefix, " unreduced_output_%zu", 4+i));
}
for (size_t i = 0; i < 8; ++i)
{
reduce_output[i].generate_r1cs_constraints();
}
}
template<typename FieldT>
void sha256_compression_function_gadget<FieldT>::generate_r1cs_witness()
{
message_schedule->generate_r1cs_witness();
#ifdef DEBUG
printf("Input:\n");
for (size_t j = 0; j < 16; ++j)
{
printf("%lx ", this->pb.val(packed_W[j]).as_uint64());
}
printf("\n");
#endif
for (size_t i = 0; i < 64; ++i)
{
round_functions[i].generate_r1cs_witness();
}
for (size_t i = 0; i < 4; ++i)
{
this->pb.val(unreduced_output[i]) = this->pb.val(round_functions[3-i].packed_d) + this->pb.val(round_functions[63-i].packed_new_a);
this->pb.val(unreduced_output[4+i]) = this->pb.val(round_functions[3-i].packed_h) + this->pb.val(round_functions[63-i].packed_new_e);
}
for (size_t i = 0; i < 8; ++i)
{
reduce_output[i].generate_r1cs_witness();
}
#ifdef DEBUG
printf("Output:\n");
for (size_t j = 0; j < 8; ++j)
{
printf("%lx ", this->pb.val(reduced_output[j]).as_uint64());
}
printf("\n");
#endif
}
template<typename FieldT>
sha256_two_to_one_hash_gadget<FieldT>::sha256_two_to_one_hash_gadget(protoboard<FieldT> &pb,
const digest_variable<FieldT> &left,
const digest_variable<FieldT> &right,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix)
{
/* concatenate block = left || right */
pb_variable_array<FieldT> block;
block.insert(block.end(), left.bits.begin(), left.bits.end());
block.insert(block.end(), right.bits.begin(), right.bits.end());
/* compute the hash itself */
f.reset(new sha256_compression_function_gadget<FieldT>(pb, SHA256_default_IV<FieldT>(pb), block, output, FMT(this->annotation_prefix, " f")));
}
template<typename FieldT>
sha256_two_to_one_hash_gadget<FieldT>::sha256_two_to_one_hash_gadget(protoboard<FieldT> &pb,
const size_t block_length,
const block_variable<FieldT> &input_block,
const digest_variable<FieldT> &output,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix)
{
assert(block_length == SHA256_block_size);
assert(input_block.bits.size() == block_length);
f.reset(new sha256_compression_function_gadget<FieldT>(pb, SHA256_default_IV<FieldT>(pb), input_block.bits, output, FMT(this->annotation_prefix, " f")));
}
template<typename FieldT>
void sha256_two_to_one_hash_gadget<FieldT>::generate_r1cs_constraints(const bool ensure_output_bitness)
{
UNUSED(ensure_output_bitness);
f->generate_r1cs_constraints();
}
template<typename FieldT>
void sha256_two_to_one_hash_gadget<FieldT>::generate_r1cs_witness()
{
f->generate_r1cs_witness();
}
template<typename FieldT>
size_t sha256_two_to_one_hash_gadget<FieldT>::get_block_len()
{
return SHA256_block_size;
}
template<typename FieldT>
size_t sha256_two_to_one_hash_gadget<FieldT>::get_digest_len()
{
return SHA256_digest_size;
}
template<typename FieldT>
bit_vector sha256_two_to_one_hash_gadget<FieldT>::get_hash(const bit_vector &input)
{
protoboard<FieldT> pb;
block_variable<FieldT> input_variable(pb, SHA256_block_size, "input");
digest_variable<FieldT> output_variable(pb, SHA256_digest_size, "output");
sha256_two_to_one_hash_gadget<FieldT> f(pb, SHA256_block_size, input_variable, output_variable, "f");
input_variable.generate_r1cs_witness(input);
f.generate_r1cs_witness();
return output_variable.get_digest();
}
template<typename FieldT>
size_t sha256_two_to_one_hash_gadget<FieldT>::expected_constraints(const bool ensure_output_bitness)
{
UNUSED(ensure_output_bitness);
return 27280; /* hardcoded for now */
}
} // libsnark
#endif // SHA256_GADGET_TCC_

55
src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py

@ -1,55 +0,0 @@
#!/usr/bin/env python
##
# @author This file is part of libsnark, developed by SCIPR Lab
# and contributors (see AUTHORS).
# @copyright MIT license (see LICENSE file)
import random
import pypy_sha256 # PyPy's implementation of SHA256 compression function; see copyright and authorship notice within.
BLOCK_LEN = 512
BLOCK_BYTES = BLOCK_LEN // 8
HASH_LEN = 256
HASH_BYTES = HASH_LEN // 8
def gen_random_bytes(n):
return [random.randint(0, 255) for i in xrange(n)]
def words_to_bytes(arr):
return sum(([x >> 24, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff] for x in arr), [])
def bytes_to_words(arr):
l = len(arr)
assert l % 4 == 0
return [(arr[i*4 + 3] << 24) + (arr[i*4+2] << 16) + (arr[i*4+1] << 8) + arr[i*4] for i in xrange(l//4)]
def cpp_val(s, log_radix=32):
if log_radix == 8:
hexfmt = '0x%02x'
elif log_radix == 32:
hexfmt = '0x%08x'
s = bytes_to_words(s)
else:
raise
return 'int_list_to_bits({%s}, %d)' % (', '.join(hexfmt % x for x in s), log_radix)
def H_bytes(x):
assert len(x) == BLOCK_BYTES
state = pypy_sha256.sha_init()
state['data'] = words_to_bytes(bytes_to_words(x))
pypy_sha256.sha_transform(state)
return words_to_bytes(bytes_to_words(words_to_bytes(state['digest'])))
def generate_sha256_gadget_tests():
left = gen_random_bytes(HASH_BYTES)
right = gen_random_bytes(HASH_BYTES)
hash = H_bytes(left + right)
print "const bit_vector left_bv = %s;" % cpp_val(left)
print "const bit_vector right_bv = %s;" % cpp_val(right)
print "const bit_vector hash_bv = %s;" % cpp_val(hash)
if __name__ == '__main__':
random.seed(0) # for reproducibility
generate_sha256_gadget_tests()

263
src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py

@ -1,263 +0,0 @@
#!/usr/bin/env python
#
# SHA256 compression function implementation below is a verbatim copy of PyPy's implementation from
# https://bitbucket.org/pypy/pypy/raw/f1f064b3faf1e012f7a9a9ab08f18074637ebe8a/lib_pypy/_sha256.py .
#
# It is licensed under the MIT license and copyright PyPy Copyright holders 2003-2015
# See https://bitbucket.org/pypy/pypy/src/tip/LICENSE for the full copyright notice.
#
SHA_BLOCKSIZE = 64
SHA_DIGESTSIZE = 32
def new_shaobject():
return {
'digest': [0]*8,
'count_lo': 0,
'count_hi': 0,
'data': [0]* SHA_BLOCKSIZE,
'local': 0,
'digestsize': 0
}
ROR = lambda x, y: (((x & 0xffffffff) >> (y & 31)) | (x << (32 - (y & 31)))) & 0xffffffff
Ch = lambda x, y, z: (z ^ (x & (y ^ z)))
Maj = lambda x, y, z: (((x | y) & z) | (x & y))
S = lambda x, n: ROR(x, n)
R = lambda x, n: (x & 0xffffffff) >> n
Sigma0 = lambda x: (S(x, 2) ^ S(x, 13) ^ S(x, 22))
Sigma1 = lambda x: (S(x, 6) ^ S(x, 11) ^ S(x, 25))
Gamma0 = lambda x: (S(x, 7) ^ S(x, 18) ^ R(x, 3))
Gamma1 = lambda x: (S(x, 17) ^ S(x, 19) ^ R(x, 10))
def sha_transform(sha_info):
W = []
d = sha_info['data']
for i in range(0,16):
W.append( (d[4*i]<<24) + (d[4*i+1]<<16) + (d[4*i+2]<<8) + d[4*i+3])
for i in range(16,64):
W.append( (Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]) & 0xffffffff )
ss = sha_info['digest'][:]
def RND(a,b,c,d,e,f,g,h,i,ki):
t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i];
t1 = Sigma0(a) + Maj(a, b, c);
d += t0;
h = t0 + t1;
return d & 0xffffffff, h & 0xffffffff
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],0,0x428a2f98);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],1,0x71374491);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],2,0xb5c0fbcf);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],3,0xe9b5dba5);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],4,0x3956c25b);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],5,0x59f111f1);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],6,0x923f82a4);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],7,0xab1c5ed5);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],8,0xd807aa98);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],9,0x12835b01);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],10,0x243185be);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],11,0x550c7dc3);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],12,0x72be5d74);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],13,0x80deb1fe);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],14,0x9bdc06a7);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],15,0xc19bf174);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],16,0xe49b69c1);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],17,0xefbe4786);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],18,0x0fc19dc6);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],19,0x240ca1cc);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],20,0x2de92c6f);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],21,0x4a7484aa);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],22,0x5cb0a9dc);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],23,0x76f988da);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],24,0x983e5152);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],25,0xa831c66d);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],26,0xb00327c8);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],27,0xbf597fc7);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],28,0xc6e00bf3);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],29,0xd5a79147);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],30,0x06ca6351);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],31,0x14292967);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],32,0x27b70a85);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],33,0x2e1b2138);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],34,0x4d2c6dfc);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],35,0x53380d13);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],36,0x650a7354);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],37,0x766a0abb);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],38,0x81c2c92e);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],39,0x92722c85);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],40,0xa2bfe8a1);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],41,0xa81a664b);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],42,0xc24b8b70);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],43,0xc76c51a3);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],44,0xd192e819);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],45,0xd6990624);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],46,0xf40e3585);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],47,0x106aa070);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],48,0x19a4c116);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],49,0x1e376c08);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],50,0x2748774c);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],51,0x34b0bcb5);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],52,0x391c0cb3);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],53,0x4ed8aa4a);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],54,0x5b9cca4f);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],55,0x682e6ff3);
ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],56,0x748f82ee);
ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],57,0x78a5636f);
ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],58,0x84c87814);
ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],59,0x8cc70208);
ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],60,0x90befffa);
ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],61,0xa4506ceb);
ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],62,0xbef9a3f7);
ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],63,0xc67178f2);
dig = []
for i, x in enumerate(sha_info['digest']):
dig.append( (x + ss[i]) & 0xffffffff )
sha_info['digest'] = dig
def sha_init():
sha_info = new_shaobject()
sha_info['digest'] = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19]
sha_info['count_lo'] = 0
sha_info['count_hi'] = 0
sha_info['local'] = 0
sha_info['digestsize'] = 32
return sha_info
def sha224_init():
sha_info = new_shaobject()
sha_info['digest'] = [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4]
sha_info['count_lo'] = 0
sha_info['count_hi'] = 0
sha_info['local'] = 0
sha_info['digestsize'] = 28
return sha_info
def sha_update(sha_info, buffer):
if isinstance(buffer, str):
raise TypeError("Unicode strings must be encoded before hashing")
count = len(buffer)
buffer_idx = 0
clo = (sha_info['count_lo'] + (count << 3)) & 0xffffffff
if clo < sha_info['count_lo']:
sha_info['count_hi'] += 1
sha_info['count_lo'] = clo
sha_info['count_hi'] += (count >> 29)
if sha_info['local']:
i = SHA_BLOCKSIZE - sha_info['local']
if i > count:
i = count
# copy buffer
sha_info['data'][sha_info['local']:sha_info['local']+i] = buffer[buffer_idx:buffer_idx+i]
count -= i
buffer_idx += i
sha_info['local'] += i
if sha_info['local'] == SHA_BLOCKSIZE:
sha_transform(sha_info)
sha_info['local'] = 0
else:
return
while count >= SHA_BLOCKSIZE:
# copy buffer
sha_info['data'] = list(buffer[buffer_idx:buffer_idx + SHA_BLOCKSIZE])
count -= SHA_BLOCKSIZE
buffer_idx += SHA_BLOCKSIZE
sha_transform(sha_info)
# copy buffer
pos = sha_info['local']
sha_info['data'][pos:pos+count] = buffer[buffer_idx:buffer_idx + count]
sha_info['local'] = count
def sha_final(sha_info):
lo_bit_count = sha_info['count_lo']
hi_bit_count = sha_info['count_hi']
count = (lo_bit_count >> 3) & 0x3f
sha_info['data'][count] = 0x80;
count += 1
if count > SHA_BLOCKSIZE - 8:
# zero the bytes in data after the count
sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count))
sha_transform(sha_info)
# zero bytes in data
sha_info['data'] = [0] * SHA_BLOCKSIZE
else:
sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count))
sha_info['data'][56] = (hi_bit_count >> 24) & 0xff
sha_info['data'][57] = (hi_bit_count >> 16) & 0xff
sha_info['data'][58] = (hi_bit_count >> 8) & 0xff
sha_info['data'][59] = (hi_bit_count >> 0) & 0xff
sha_info['data'][60] = (lo_bit_count >> 24) & 0xff
sha_info['data'][61] = (lo_bit_count >> 16) & 0xff
sha_info['data'][62] = (lo_bit_count >> 8) & 0xff
sha_info['data'][63] = (lo_bit_count >> 0) & 0xff
sha_transform(sha_info)
dig = []
for i in sha_info['digest']:
dig.extend([ ((i>>24) & 0xff), ((i>>16) & 0xff), ((i>>8) & 0xff), (i & 0xff) ])
return ''.join([chr(i) for i in dig])
class sha256(object):
digest_size = digestsize = SHA_DIGESTSIZE
block_size = SHA_BLOCKSIZE
def __init__(self, s=None):
self._sha = sha_init()
if s:
sha_update(self._sha, s)
def update(self, s):
sha_update(self._sha, s)
def digest(self):
return sha_final(self._sha.copy())[:self._sha['digestsize']]
def hexdigest(self):
return ''.join(['%.2x' % ord(i) for i in self.digest()])
def copy(self):
new = sha256.__new__(sha256)
new._sha = self._sha.copy()
return new
class sha224(sha256):
digest_size = digestsize = 28
def __init__(self, s=None):
self._sha = sha224_init()
if s:
sha_update(self._sha, s)
def copy(self):
new = sha224.__new__(sha224)
new._sha = self._sha.copy()
return new
def test():
a_str = "just a test string"
assert 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' == sha256().hexdigest()
assert 'd7b553c6f09ac85d142415f857c5310f3bbbe7cdd787cce4b985acedd585266f' == sha256(a_str).hexdigest()
assert '8113ebf33c97daa9998762aacafe750c7cefc2b2f173c90c59663a57fe626f21' == sha256(a_str*7).hexdigest()
s = sha256(a_str)
s.update(a_str)
assert '03d9963e05a094593190b6fc794cb1a3e1ac7d7883f0b5855268afeccc70d461' == s.hexdigest()
if __name__ == "__main__":
test()

46
src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp

@ -1,46 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include "common/default_types/ec_pp.hpp"
#include "common/utils.hpp"
#include "common/profiling.hpp"
#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp"
using namespace libsnark;
template<typename FieldT>
void test_two_to_one()
{
protoboard<FieldT> pb;
digest_variable<FieldT> left(pb, SHA256_digest_size, "left");
digest_variable<FieldT> right(pb, SHA256_digest_size, "right");
digest_variable<FieldT> output(pb, SHA256_digest_size, "output");
sha256_two_to_one_hash_gadget<FieldT> f(pb, left, right, output, "f");
f.generate_r1cs_constraints();
printf("Number of constraints for sha256_two_to_one_hash_gadget: %zu\n", pb.num_constraints());
const bit_vector left_bv = int_list_to_bits({0x426bc2d8, 0x4dc86782, 0x81e8957a, 0x409ec148, 0xe6cffbe8, 0xafe6ba4f, 0x9c6f1978, 0xdd7af7e9}, 32);
const bit_vector right_bv = int_list_to_bits({0x038cce42, 0xabd366b8, 0x3ede7e00, 0x9130de53, 0x72cdf73d, 0xee825114, 0x8cb48d1b, 0x9af68ad0}, 32);
const bit_vector hash_bv = int_list_to_bits({0xeffd0b7f, 0x1ccba116, 0x2ee816f7, 0x31c62b48, 0x59305141, 0x990e5c0a, 0xce40d33d, 0x0b1167d1}, 32);
left.generate_r1cs_witness(left_bv);
right.generate_r1cs_witness(right_bv);
f.generate_r1cs_witness();
output.generate_r1cs_witness(hash_bv);
assert(pb.is_satisfied());
}
int main(void)
{
start_profiling();
default_ec_pp::init_public_params();
test_two_to_one<Fr<default_ec_pp> >();
}

38
src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp

@ -1,38 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP_
#define MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP_
#include "common/data_structures/merkle_tree.hpp"
#include "gadgetlib1/gadget.hpp"
#include "gadgetlib1/gadgets/hashes/hash_io.hpp"
namespace libsnark {
template<typename FieldT, typename HashT>
class merkle_authentication_path_variable : public gadget<FieldT> {
public:
const size_t tree_depth;
std::vector<digest_variable<FieldT> > left_digests;
std::vector<digest_variable<FieldT> > right_digests;
merkle_authentication_path_variable(protoboard<FieldT> &pb,
const size_t tree_depth,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness(const size_t address, const merkle_authentication_path &path);
merkle_authentication_path get_authentication_path(const size_t address) const;
};
} // libsnark
#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc"
#endif // MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP

76
src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc

@ -1,76 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC_
#define MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC_
namespace libsnark {
template<typename FieldT, typename HashT>
merkle_authentication_path_variable<FieldT, HashT>::merkle_authentication_path_variable(protoboard<FieldT> &pb,
const size_t tree_depth,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
tree_depth(tree_depth)
{
for (size_t i = 0; i < tree_depth; ++i)
{
left_digests.emplace_back(digest_variable<FieldT>(pb, HashT::get_digest_len(), FMT(annotation_prefix, " left_digests_%zu", i)));
right_digests.emplace_back(digest_variable<FieldT>(pb, HashT::get_digest_len(), FMT(annotation_prefix, " right_digests_%zu", i)));
}
}
template<typename FieldT, typename HashT>
void merkle_authentication_path_variable<FieldT, HashT>::generate_r1cs_constraints()
{
for (size_t i = 0; i < tree_depth; ++i)
{
left_digests[i].generate_r1cs_constraints();
right_digests[i].generate_r1cs_constraints();
}
}
template<typename FieldT, typename HashT>
void merkle_authentication_path_variable<FieldT, HashT>::generate_r1cs_witness(const size_t address, const merkle_authentication_path &path)
{
assert(path.size() == tree_depth);
for (size_t i = 0; i < tree_depth; ++i)
{
if (address & (UINT64_C(1) << (tree_depth-1-i)))
{
left_digests[i].generate_r1cs_witness(path[i]);
}
else
{
right_digests[i].generate_r1cs_witness(path[i]);
}
}
}
template<typename FieldT, typename HashT>
merkle_authentication_path merkle_authentication_path_variable<FieldT, HashT>::get_authentication_path(const size_t address) const
{
merkle_authentication_path result;
for (size_t i = 0; i < tree_depth; ++i)
{
if (address & (UINT64_C(1) << (tree_depth-1-i)))
{
result.emplace_back(left_digests[i].get_digest());
}
else
{
result.emplace_back(right_digests[i].get_digest());
}
}
return result;
}
} // libsnark
#endif // MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC

73
src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp

@ -1,73 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for the Merkle tree check read gadget.
The gadget checks the following: given a root R, address A, value V, and
authentication path P, check that P is a valid authentication path for the
value V as the A-th leaf in a Merkle tree with root R.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef MERKLE_TREE_CHECK_READ_GADGET_HPP_
#define MERKLE_TREE_CHECK_READ_GADGET_HPP_
#include "common/data_structures/merkle_tree.hpp"
#include "gadgetlib1/gadget.hpp"
#include "gadgetlib1/gadgets/hashes/hash_io.hpp"
#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp"
#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp"
namespace libsnark {
template<typename FieldT, typename HashT>
class merkle_tree_check_read_gadget : public gadget<FieldT> {
private:
std::vector<HashT> hashers;
std::vector<block_variable<FieldT> > hasher_inputs;
std::vector<digest_selector_gadget<FieldT> > propagators;
std::vector<digest_variable<FieldT> > internal_output;
std::shared_ptr<digest_variable<FieldT> > computed_root;
std::shared_ptr<bit_vector_copy_gadget<FieldT> > check_root;
public:
const size_t digest_size;
const size_t tree_depth;
pb_linear_combination_array<FieldT> address_bits;
digest_variable<FieldT> leaf;
digest_variable<FieldT> root;
merkle_authentication_path_variable<FieldT, HashT> path;
pb_linear_combination<FieldT> read_successful;
merkle_tree_check_read_gadget(protoboard<FieldT> &pb,
const size_t tree_depth,
const pb_linear_combination_array<FieldT> &address_bits,
const digest_variable<FieldT> &leaf_digest,
const digest_variable<FieldT> &root_digest,
const merkle_authentication_path_variable<FieldT, HashT> &path,
const pb_linear_combination<FieldT> &read_successful,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
static size_t root_size_in_bits();
/* for debugging purposes */
static size_t expected_constraints(const size_t tree_depth);
};
template<typename FieldT, typename HashT>
void test_merkle_tree_check_read_gadget();
} // libsnark
#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc"
#endif // MERKLE_TREE_CHECK_READ_GADGET_HPP_

196
src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc

@ -1,196 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for the Merkle tree check read.
See merkle_tree_check_read_gadget.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef MERKLE_TREE_CHECK_READ_GADGET_TCC_
#define MERKLE_TREE_CHECK_READ_GADGET_TCC_
namespace libsnark {
template<typename FieldT, typename HashT>
merkle_tree_check_read_gadget<FieldT, HashT>::merkle_tree_check_read_gadget(protoboard<FieldT> &pb,
const size_t tree_depth,
const pb_linear_combination_array<FieldT> &address_bits,
const digest_variable<FieldT> &leaf,
const digest_variable<FieldT> &root,
const merkle_authentication_path_variable<FieldT, HashT> &path,
const pb_linear_combination<FieldT> &read_successful,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
digest_size(HashT::get_digest_len()),
tree_depth(tree_depth),
address_bits(address_bits),
leaf(leaf),
root(root),
path(path),
read_successful(read_successful)
{
/*
The tricky part here is ordering. For Merkle tree
authentication paths, path[0] corresponds to one layer below
the root (and path[tree_depth-1] corresponds to the layer
containing the leaf), while address_bits has the reverse order:
address_bits[0] is LSB, and corresponds to layer containing the
leaf, and address_bits[tree_depth-1] is MSB, and corresponds to
the subtree directly under the root.
*/
assert(tree_depth > 0);
assert(tree_depth == address_bits.size());
for (size_t i = 0; i < tree_depth-1; ++i)
{
internal_output.emplace_back(digest_variable<FieldT>(pb, digest_size, FMT(this->annotation_prefix, " internal_output_%zu", i)));
}
computed_root.reset(new digest_variable<FieldT>(pb, digest_size, FMT(this->annotation_prefix, " computed_root")));
for (size_t i = 0; i < tree_depth; ++i)
{
block_variable<FieldT> inp(pb, path.left_digests[i], path.right_digests[i], FMT(this->annotation_prefix, " inp_%zu", i));
hasher_inputs.emplace_back(inp);
hashers.emplace_back(HashT(pb, 2*digest_size, inp, (i == 0 ? *computed_root : internal_output[i-1]),
FMT(this->annotation_prefix, " load_hashers_%zu", i)));
}
for (size_t i = 0; i < tree_depth; ++i)
{
/*
The propagators take a computed hash value (or leaf in the
base case) and propagate it one layer up, either in the left
or the right slot of authentication_path_variable.
*/
propagators.emplace_back(digest_selector_gadget<FieldT>(pb, digest_size, i < tree_depth - 1 ? internal_output[i] : leaf,
address_bits[tree_depth-1-i], path.left_digests[i], path.right_digests[i],
FMT(this->annotation_prefix, " digest_selector_%zu", i)));
}
check_root.reset(new bit_vector_copy_gadget<FieldT>(pb, computed_root->bits, root.bits, read_successful, FieldT::capacity(), FMT(annotation_prefix, " check_root")));
}
template<typename FieldT, typename HashT>
void merkle_tree_check_read_gadget<FieldT, HashT>::generate_r1cs_constraints()
{
/* ensure correct hash computations */
for (size_t i = 0; i < tree_depth; ++i)
{
// Note that we check root outside and have enforced booleanity of path.left_digests/path.right_digests outside in path.generate_r1cs_constraints
hashers[i].generate_r1cs_constraints(false);
}
/* ensure consistency of path.left_digests/path.right_digests with internal_output */
for (size_t i = 0; i < tree_depth; ++i)
{
propagators[i].generate_r1cs_constraints();
}
check_root->generate_r1cs_constraints(false, false);
}
template<typename FieldT, typename HashT>
void merkle_tree_check_read_gadget<FieldT, HashT>::generate_r1cs_witness()
{
/* do the hash computations bottom-up */
for (int i = tree_depth-1; i >= 0; --i)
{
/* propagate previous input */
propagators[i].generate_r1cs_witness();
/* compute hash */
hashers[i].generate_r1cs_witness();
}
check_root->generate_r1cs_witness();
}
template<typename FieldT, typename HashT>
size_t merkle_tree_check_read_gadget<FieldT, HashT>::root_size_in_bits()
{
return HashT::get_digest_len();
}
template<typename FieldT, typename HashT>
size_t merkle_tree_check_read_gadget<FieldT, HashT>::expected_constraints(const size_t tree_depth)
{
/* NB: this includes path constraints */
const size_t hasher_constraints = tree_depth * HashT::expected_constraints(false);
const size_t propagator_constraints = tree_depth * HashT::get_digest_len();
const size_t authentication_path_constraints = 2 * tree_depth * HashT::get_digest_len();
const size_t check_root_constraints = 3 * div_ceil(HashT::get_digest_len(), FieldT::capacity());
return hasher_constraints + propagator_constraints + authentication_path_constraints + check_root_constraints;
}
template<typename FieldT, typename HashT>
void test_merkle_tree_check_read_gadget()
{
/* prepare test */
const size_t digest_len = HashT::get_digest_len();
const size_t tree_depth = 16;
std::vector<merkle_authentication_node> path(tree_depth);
bit_vector prev_hash(digest_len);
std::generate(prev_hash.begin(), prev_hash.end(), [&]() { return std::rand() % 2; });
bit_vector leaf = prev_hash;
bit_vector address_bits;
size_t address = 0;
for (int64_t level = tree_depth-1; level >= 0; --level)
{
const bool computed_is_right = (std::rand() % 2);
address |= (computed_is_right ? UINT64_C(1) << (tree_depth-1-level) : 0);
address_bits.push_back(computed_is_right);
bit_vector other(digest_len);
std::generate(other.begin(), other.end(), [&]() { return std::rand() % 2; });
bit_vector block = prev_hash;
block.insert(computed_is_right ? block.begin() : block.end(), other.begin(), other.end());
bit_vector h = HashT::get_hash(block);
path[level] = other;
prev_hash = h;
}
bit_vector root = prev_hash;
/* execute test */
protoboard<FieldT> pb;
pb_variable_array<FieldT> address_bits_va;
address_bits_va.allocate(pb, tree_depth, "address_bits");
digest_variable<FieldT> leaf_digest(pb, digest_len, "input_block");
digest_variable<FieldT> root_digest(pb, digest_len, "output_digest");
merkle_authentication_path_variable<FieldT, HashT> path_var(pb, tree_depth, "path_var");
merkle_tree_check_read_gadget<FieldT, HashT> ml(pb, tree_depth, address_bits_va, leaf_digest, root_digest, path_var, ONE, "ml");
path_var.generate_r1cs_constraints();
ml.generate_r1cs_constraints();
address_bits_va.fill_with_bits(pb, address_bits);
assert(address_bits_va.get_field_element_from_bits(pb).as_uint64() == address);
leaf_digest.generate_r1cs_witness(leaf);
path_var.generate_r1cs_witness(address, path);
ml.generate_r1cs_witness();
/* make sure that read checker didn't accidentally overwrite anything */
address_bits_va.fill_with_bits(pb, address_bits);
leaf_digest.generate_r1cs_witness(leaf);
root_digest.generate_r1cs_witness(root);
assert(pb.is_satisfied());
const size_t num_constraints = pb.num_constraints();
const size_t expected_constraints = merkle_tree_check_read_gadget<FieldT, HashT>::expected_constraints(tree_depth);
assert(num_constraints == expected_constraints);
}
} // libsnark
#endif // MERKLE_TREE_CHECK_READ_GADGET_TCC_

91
src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp

@ -1,91 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for the Merkle tree check read gadget.
The gadget checks the following: given two roots R1 and R2, address A, two
values V1 and V2, and authentication path P, check that
- P is a valid authentication path for the value V1 as the A-th leaf in a Merkle tree with root R1, and
- P is a valid authentication path for the value V2 as the A-th leaf in a Merkle tree with root R2.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_
#define MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_
#include "common/data_structures/merkle_tree.hpp"
#include "gadgetlib1/gadget.hpp"
#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp"
#include "gadgetlib1/gadgets/hashes/hash_io.hpp"
#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp"
#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp"
namespace libsnark {
template<typename FieldT, typename HashT>
class merkle_tree_check_update_gadget : public gadget<FieldT> {
private:
std::vector<HashT> prev_hashers;
std::vector<block_variable<FieldT> > prev_hasher_inputs;
std::vector<digest_selector_gadget<FieldT> > prev_propagators;
std::vector<digest_variable<FieldT> > prev_internal_output;
std::vector<HashT> next_hashers;
std::vector<block_variable<FieldT> > next_hasher_inputs;
std::vector<digest_selector_gadget<FieldT> > next_propagators;
std::vector<digest_variable<FieldT> > next_internal_output;
std::shared_ptr<digest_variable<FieldT> > computed_next_root;
std::shared_ptr<bit_vector_copy_gadget<FieldT> > check_next_root;
public:
const size_t digest_size;
const size_t tree_depth;
pb_variable_array<FieldT> address_bits;
digest_variable<FieldT> prev_leaf_digest;
digest_variable<FieldT> prev_root_digest;
merkle_authentication_path_variable<FieldT, HashT> prev_path;
digest_variable<FieldT> next_leaf_digest;
digest_variable<FieldT> next_root_digest;
merkle_authentication_path_variable<FieldT, HashT> next_path;
pb_linear_combination<FieldT> update_successful;
/* Note that while it is necessary to generate R1CS constraints
for prev_path, it is not necessary to do so for next_path. See
comment in the implementation of generate_r1cs_constraints() */
merkle_tree_check_update_gadget(protoboard<FieldT> &pb,
const size_t tree_depth,
const pb_variable_array<FieldT> &address_bits,
const digest_variable<FieldT> &prev_leaf_digest,
const digest_variable<FieldT> &prev_root_digest,
const merkle_authentication_path_variable<FieldT, HashT> &prev_path,
const digest_variable<FieldT> &next_leaf_digest,
const digest_variable<FieldT> &next_root_digest,
const merkle_authentication_path_variable<FieldT, HashT> &next_path,
const pb_linear_combination<FieldT> &update_successful,
const std::string &annotation_prefix);
void generate_r1cs_constraints();
void generate_r1cs_witness();
static size_t root_size_in_bits();
/* for debugging purposes */
static size_t expected_constraints(const size_t tree_depth);
};
template<typename FieldT, typename HashT>
void test_merkle_tree_check_update_gadget();
} // libsnark
#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc"
#endif // MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_

265
src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc

@ -1,265 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for the Merkle tree check update gadget.
See merkle_tree_check_update_gadget.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_
#define MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_
namespace libsnark {
template<typename FieldT, typename HashT>
merkle_tree_check_update_gadget<FieldT, HashT>::merkle_tree_check_update_gadget(protoboard<FieldT> &pb,
const size_t tree_depth,
const pb_variable_array<FieldT> &address_bits,
const digest_variable<FieldT> &prev_leaf_digest,
const digest_variable<FieldT> &prev_root_digest,
const merkle_authentication_path_variable<FieldT, HashT> &prev_path,
const digest_variable<FieldT> &next_leaf_digest,
const digest_variable<FieldT> &next_root_digest,
const merkle_authentication_path_variable<FieldT, HashT> &next_path,
const pb_linear_combination<FieldT> &update_successful,
const std::string &annotation_prefix) :
gadget<FieldT>(pb, annotation_prefix),
digest_size(HashT::get_digest_len()),
tree_depth(tree_depth),
address_bits(address_bits),
prev_leaf_digest(prev_leaf_digest),
prev_root_digest(prev_root_digest),
prev_path(prev_path),
next_leaf_digest(next_leaf_digest),
next_root_digest(next_root_digest),
next_path(next_path),
update_successful(update_successful)
{
assert(tree_depth > 0);
assert(tree_depth == address_bits.size());
for (size_t i = 0; i < tree_depth-1; ++i)
{
prev_internal_output.emplace_back(digest_variable<FieldT>(pb, digest_size, FMT(this->annotation_prefix, " prev_internal_output_%zu", i)));
next_internal_output.emplace_back(digest_variable<FieldT>(pb, digest_size, FMT(this->annotation_prefix, " next_internal_output_%zu", i)));
}
computed_next_root.reset(new digest_variable<FieldT>(pb, digest_size, FMT(this->annotation_prefix, " computed_root")));
for (size_t i = 0; i < tree_depth; ++i)
{
block_variable<FieldT> prev_inp(pb, prev_path.left_digests[i], prev_path.right_digests[i], FMT(this->annotation_prefix, " prev_inp_%zu", i));
prev_hasher_inputs.emplace_back(prev_inp);
prev_hashers.emplace_back(HashT(pb, 2*digest_size, prev_inp, (i == 0 ? prev_root_digest : prev_internal_output[i-1]),
FMT(this->annotation_prefix, " prev_hashers_%zu", i)));
block_variable<FieldT> next_inp(pb, next_path.left_digests[i], next_path.right_digests[i], FMT(this->annotation_prefix, " next_inp_%zu", i));
next_hasher_inputs.emplace_back(next_inp);
next_hashers.emplace_back(HashT(pb, 2*digest_size, next_inp, (i == 0 ? *computed_next_root : next_internal_output[i-1]),
FMT(this->annotation_prefix, " next_hashers_%zu", i)));
}
for (size_t i = 0; i < tree_depth; ++i)
{
prev_propagators.emplace_back(digest_selector_gadget<FieldT>(pb, digest_size, i < tree_depth -1 ? prev_internal_output[i] : prev_leaf_digest,
address_bits[tree_depth-1-i], prev_path.left_digests[i], prev_path.right_digests[i],
FMT(this->annotation_prefix, " prev_propagators_%zu", i)));
next_propagators.emplace_back(digest_selector_gadget<FieldT>(pb, digest_size, i < tree_depth -1 ? next_internal_output[i] : next_leaf_digest,
address_bits[tree_depth-1-i], next_path.left_digests[i], next_path.right_digests[i],
FMT(this->annotation_prefix, " next_propagators_%zu", i)));
}
check_next_root.reset(new bit_vector_copy_gadget<FieldT>(pb, computed_next_root->bits, next_root_digest.bits, update_successful, FieldT::capacity(), FMT(annotation_prefix, " check_next_root")));
}
template<typename FieldT, typename HashT>
void merkle_tree_check_update_gadget<FieldT, HashT>::generate_r1cs_constraints()
{
/* ensure correct hash computations */
for (size_t i = 0; i < tree_depth; ++i)
{
prev_hashers[i].generate_r1cs_constraints(false); // we check root outside and prev_left/prev_right above
next_hashers[i].generate_r1cs_constraints(true); // however we must check right side hashes
}
/* ensure consistency of internal_left/internal_right with internal_output */
for (size_t i = 0; i < tree_depth; ++i)
{
prev_propagators[i].generate_r1cs_constraints();
next_propagators[i].generate_r1cs_constraints();
}
/* ensure that prev auxiliary input and next auxiliary input match */
for (size_t i = 0; i < tree_depth; ++i)
{
for (size_t j = 0; j < digest_size; ++j)
{
/*
addr * (prev_left - next_left) + (1 - addr) * (prev_right - next_right) = 0
addr * (prev_left - next_left - prev_right + next_right) = next_right - prev_right
*/
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(address_bits[tree_depth-1-i],
prev_path.left_digests[i].bits[j] - next_path.left_digests[i].bits[j] - prev_path.right_digests[i].bits[j] + next_path.right_digests[i].bits[j],
next_path.right_digests[i].bits[j] - prev_path.right_digests[i].bits[j]),
FMT(this->annotation_prefix, " aux_check_%zu_%zu", i, j));
}
}
/* Note that while it is necessary to generate R1CS constraints
for prev_path, it is not necessary to do so for next_path.
This holds, because { next_path.left_inputs[i],
next_path.right_inputs[i] } is a pair { hash_output,
auxiliary_input }. The bitness for hash_output is enforced
above by next_hashers[i].generate_r1cs_constraints.
Because auxiliary input is the same for prev_path and next_path
(enforced above), we have that auxiliary_input part is also
constrained to be boolean, because prev_path is *all*
constrained to be all boolean. */
check_next_root->generate_r1cs_constraints(false, false);
}
template<typename FieldT, typename HashT>
void merkle_tree_check_update_gadget<FieldT, HashT>::generate_r1cs_witness()
{
/* do the hash computations bottom-up */
for (int i = tree_depth-1; i >= 0; --i)
{
/* ensure consistency of prev_path and next_path */
if (this->pb.val(address_bits[tree_depth-1-i]) == FieldT::one())
{
next_path.left_digests[i].generate_r1cs_witness(prev_path.left_digests[i].get_digest());
}
else
{
next_path.right_digests[i].generate_r1cs_witness(prev_path.right_digests[i].get_digest());
}
/* propagate previous input */
prev_propagators[i].generate_r1cs_witness();
next_propagators[i].generate_r1cs_witness();
/* compute hash */
prev_hashers[i].generate_r1cs_witness();
next_hashers[i].generate_r1cs_witness();
}
check_next_root->generate_r1cs_witness();
}
template<typename FieldT, typename HashT>
size_t merkle_tree_check_update_gadget<FieldT, HashT>::root_size_in_bits()
{
return HashT::get_digest_len();
}
template<typename FieldT, typename HashT>
size_t merkle_tree_check_update_gadget<FieldT, HashT>::expected_constraints(const size_t tree_depth)
{
/* NB: this includes path constraints */
const size_t prev_hasher_constraints = tree_depth * HashT::expected_constraints(false);
const size_t next_hasher_constraints = tree_depth * HashT::expected_constraints(true);
const size_t prev_authentication_path_constraints = 2 * tree_depth * HashT::get_digest_len();
const size_t prev_propagator_constraints = tree_depth * HashT::get_digest_len();
const size_t next_propagator_constraints = tree_depth * HashT::get_digest_len();
const size_t check_next_root_constraints = 3 * div_ceil(HashT::get_digest_len(), FieldT::capacity());
const size_t aux_equality_constraints = tree_depth * HashT::get_digest_len();
return (prev_hasher_constraints + next_hasher_constraints + prev_authentication_path_constraints +
prev_propagator_constraints + next_propagator_constraints + check_next_root_constraints +
aux_equality_constraints);
}
template<typename FieldT, typename HashT>
void test_merkle_tree_check_update_gadget()
{
/* prepare test */
const size_t digest_len = HashT::get_digest_len();
const size_t tree_depth = 16;
std::vector<merkle_authentication_node> prev_path(tree_depth);
bit_vector prev_load_hash(digest_len);
std::generate(prev_load_hash.begin(), prev_load_hash.end(), [&]() { return std::rand() % 2; });
bit_vector prev_store_hash(digest_len);
std::generate(prev_store_hash.begin(), prev_store_hash.end(), [&]() { return std::rand() % 2; });
bit_vector loaded_leaf = prev_load_hash;
bit_vector stored_leaf = prev_store_hash;
bit_vector address_bits;
size_t address = 0;
for (int64_t level = tree_depth-1; level >= 0; --level)
{
const bool computed_is_right = (std::rand() % 2);
address |= (computed_is_right ? UINT64_C(1) << (tree_depth-1-level) : 0);
address_bits.push_back(computed_is_right);
bit_vector other(digest_len);
std::generate(other.begin(), other.end(), [&]() { return std::rand() % 2; });
bit_vector load_block = prev_load_hash;
load_block.insert(computed_is_right ? load_block.begin() : load_block.end(), other.begin(), other.end());
bit_vector store_block = prev_store_hash;
store_block.insert(computed_is_right ? store_block.begin() : store_block.end(), other.begin(), other.end());
bit_vector load_h = HashT::get_hash(load_block);
bit_vector store_h = HashT::get_hash(store_block);
prev_path[level] = other;
prev_load_hash = load_h;
prev_store_hash = store_h;
}
bit_vector load_root = prev_load_hash;
bit_vector store_root = prev_store_hash;
/* execute the test */
protoboard<FieldT> pb;
pb_variable_array<FieldT> address_bits_va;
address_bits_va.allocate(pb, tree_depth, "address_bits");
digest_variable<FieldT> prev_leaf_digest(pb, digest_len, "prev_leaf_digest");
digest_variable<FieldT> prev_root_digest(pb, digest_len, "prev_root_digest");
merkle_authentication_path_variable<FieldT, HashT> prev_path_var(pb, tree_depth, "prev_path_var");
digest_variable<FieldT> next_leaf_digest(pb, digest_len, "next_leaf_digest");
digest_variable<FieldT> next_root_digest(pb, digest_len, "next_root_digest");
merkle_authentication_path_variable<FieldT, HashT> next_path_var(pb, tree_depth, "next_path_var");
merkle_tree_check_update_gadget<FieldT, HashT> mls(pb, tree_depth, address_bits_va,
prev_leaf_digest, prev_root_digest, prev_path_var,
next_leaf_digest, next_root_digest, next_path_var, ONE, "mls");
prev_path_var.generate_r1cs_constraints();
mls.generate_r1cs_constraints();
address_bits_va.fill_with_bits(pb, address_bits);
assert(address_bits_va.get_field_element_from_bits(pb).as_uint64() == address);
prev_leaf_digest.generate_r1cs_witness(loaded_leaf);
prev_path_var.generate_r1cs_witness(address, prev_path);
next_leaf_digest.generate_r1cs_witness(stored_leaf);
address_bits_va.fill_with_bits(pb, address_bits);
mls.generate_r1cs_witness();
/* make sure that update check will check for the right things */
prev_leaf_digest.generate_r1cs_witness(loaded_leaf);
next_leaf_digest.generate_r1cs_witness(stored_leaf);
prev_root_digest.generate_r1cs_witness(load_root);
next_root_digest.generate_r1cs_witness(store_root);
address_bits_va.fill_with_bits(pb, address_bits);
assert(pb.is_satisfied());
const size_t num_constraints = pb.num_constraints();
const size_t expected_constraints = merkle_tree_check_update_gadget<FieldT, HashT>::expected_constraints(tree_depth);
assert(num_constraints == expected_constraints);
}
} // libsnark
#endif // MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_

48
src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp

@ -1,48 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifdef CURVE_BN128
#include "algebra/curves/bn128/bn128_pp.hpp"
#endif
#include "algebra/curves/edwards/edwards_pp.hpp"
#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp"
#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp"
#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp"
#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp"
#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp"
using namespace libsnark;
template<typename ppT>
void test_all_merkle_tree_gadgets()
{
typedef Fr<ppT> FieldT;
test_merkle_tree_check_read_gadget<FieldT, CRH_with_bit_out_gadget<FieldT> >();
test_merkle_tree_check_read_gadget<FieldT, sha256_two_to_one_hash_gadget<FieldT> >();
test_merkle_tree_check_update_gadget<FieldT, CRH_with_bit_out_gadget<FieldT> >();
test_merkle_tree_check_update_gadget<FieldT, sha256_two_to_one_hash_gadget<FieldT> >();
}
int main(void)
{
start_profiling();
#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled
bn128_pp::init_public_params();
test_all_merkle_tree_gadgets<bn128_pp>();
#endif
edwards_pp::init_public_params();
test_all_merkle_tree_gadgets<edwards_pp>();
mnt4_pp::init_public_params();
test_all_merkle_tree_gadgets<mnt4_pp>();
mnt6_pp::init_public_params();
test_all_merkle_tree_gadgets<mnt6_pp>();
}

144
src/snark/libsnark/gadgetlib1/pb_variable.hpp

@ -1,144 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef PB_VARIABLE_HPP_
#define PB_VARIABLE_HPP_
#include <cstddef>
#include <string>
#include <vector>
#include "common/utils.hpp"
#include "relations/variable.hpp"
namespace libsnark {
typedef size_t lc_index_t;
template<typename FieldT>
class protoboard;
template<typename FieldT>
class pb_variable : public variable<FieldT> {
public:
pb_variable(const var_index_t index = 0) : variable<FieldT>(index) {};
void allocate(protoboard<FieldT> &pb, const std::string &annotation="");
};
template<typename FieldT>
class pb_variable_array : private std::vector<pb_variable<FieldT> >
{
typedef std::vector<pb_variable<FieldT> > contents;
public:
using typename contents::iterator;
using typename contents::const_iterator;
using typename contents::reverse_iterator;
using typename contents::const_reverse_iterator;
using contents::begin;
using contents::end;
using contents::rbegin;
using contents::rend;
using contents::emplace_back;
using contents::insert;
using contents::reserve;
using contents::size;
using contents::empty;
using contents::operator[];
using contents::resize;
pb_variable_array() : contents() {};
pb_variable_array(size_t count, const pb_variable<FieldT> &value) : contents(count, value) {};
pb_variable_array(typename contents::const_iterator first, typename contents::const_iterator last) : contents(first, last) {};
pb_variable_array(typename contents::const_reverse_iterator first, typename contents::const_reverse_iterator last) : contents(first, last) {};
void allocate(protoboard<FieldT> &pb, const size_t n, const std::string &annotation_prefix="");
void fill_with_field_elements(protoboard<FieldT> &pb, const std::vector<FieldT>& vals) const;
void fill_with_bits(protoboard<FieldT> &pb, const bit_vector& bits) const;
void fill_with_bits_of_uint64(protoboard<FieldT> &pb, const uint64_t i) const;
void fill_with_bits_of_field_element(protoboard<FieldT> &pb, const FieldT &r) const;
std::vector<FieldT> get_vals(const protoboard<FieldT> &pb) const;
bit_vector get_bits(const protoboard<FieldT> &pb) const;
FieldT get_field_element_from_bits(const protoboard<FieldT> &pb) const;
};
/* index 0 corresponds to the constant term (used in legacy code) */
#define ONE pb_variable<FieldT>(0)
template<typename FieldT>
class pb_linear_combination : public linear_combination<FieldT> {
public:
bool is_variable;
lc_index_t index;
pb_linear_combination();
pb_linear_combination(const pb_variable<FieldT> &var);
void assign(protoboard<FieldT> &pb, const linear_combination<FieldT> &lc);
void evaluate(protoboard<FieldT> &pb) const;
bool is_constant() const;
FieldT constant_term() const;
};
template<typename FieldT>
class pb_linear_combination_array : private std::vector<pb_linear_combination<FieldT> >
{
typedef std::vector<pb_linear_combination<FieldT> > contents;
public:
using typename contents::iterator;
using typename contents::const_iterator;
using typename contents::reverse_iterator;
using typename contents::const_reverse_iterator;
using contents::begin;
using contents::end;
using contents::rbegin;
using contents::rend;
using contents::emplace_back;
using contents::insert;
using contents::reserve;
using contents::size;
using contents::empty;
using contents::operator[];
using contents::resize;
pb_linear_combination_array() : contents() {};
pb_linear_combination_array(const pb_variable_array<FieldT> &arr) { for (auto &v : arr) this->emplace_back(pb_linear_combination<FieldT>(v)); };
pb_linear_combination_array(size_t count) : contents(count) {};
pb_linear_combination_array(size_t count, const pb_linear_combination<FieldT> &value) : contents(count, value) {};
pb_linear_combination_array(typename contents::const_iterator first, typename contents::const_iterator last) : contents(first, last) {};
pb_linear_combination_array(typename contents::const_reverse_iterator first, typename contents::const_reverse_iterator last) : contents(first, last) {};
void evaluate(protoboard<FieldT> &pb) const;
void fill_with_field_elements(protoboard<FieldT> &pb, const std::vector<FieldT>& vals) const;
void fill_with_bits(protoboard<FieldT> &pb, const bit_vector& bits) const;
void fill_with_bits_of_uint64(protoboard<FieldT> &pb, const uint64_t i) const;
void fill_with_bits_of_field_element(protoboard<FieldT> &pb, const FieldT &r) const;
std::vector<FieldT> get_vals(const protoboard<FieldT> &pb) const;
bit_vector get_bits(const protoboard<FieldT> &pb) const;
FieldT get_field_element_from_bits(const protoboard<FieldT> &pb) const;
};
template<typename FieldT>
linear_combination<FieldT> pb_sum(const pb_linear_combination_array<FieldT> &v);
template<typename FieldT>
linear_combination<FieldT> pb_packing_sum(const pb_linear_combination_array<FieldT> &v);
template<typename FieldT>
linear_combination<FieldT> pb_coeff_sum(const pb_linear_combination_array<FieldT> &v, const std::vector<FieldT> &coeffs);
} // libsnark
#include "gadgetlib1/pb_variable.tcc"
#endif // PB_VARIABLE_HPP_

330
src/snark/libsnark/gadgetlib1/pb_variable.tcc

@ -1,330 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef PB_VARIABLE_TCC_
#define PB_VARIABLE_TCC_
#include <cassert>
#include "gadgetlib1/protoboard.hpp"
#include "common/utils.hpp"
namespace libsnark {
template<typename FieldT>
void pb_variable<FieldT>::allocate(protoboard<FieldT> &pb, const std::string &annotation)
{
this->index = pb.allocate_var_index(annotation);
}
/* allocates pb_variable<FieldT> array in MSB->LSB order */
template<typename FieldT>
void pb_variable_array<FieldT>::allocate(protoboard<FieldT> &pb, const size_t n, const std::string &annotation_prefix)
{
#ifdef DEBUG
assert(annotation_prefix != "");
#endif
(*this).resize(n);
for (size_t i = 0; i < n; ++i)
{
(*this)[i].allocate(pb, FMT(annotation_prefix, "_%zu", i));
}
}
template<typename FieldT>
void pb_variable_array<FieldT>::fill_with_field_elements(protoboard<FieldT> &pb, const std::vector<FieldT>& vals) const
{
assert(this->size() == vals.size());
for (size_t i = 0; i < vals.size(); ++i)
{
pb.val((*this)[i]) = vals[i];
}
}
template<typename FieldT>
void pb_variable_array<FieldT>::fill_with_bits(protoboard<FieldT> &pb, const bit_vector& bits) const
{
assert(this->size() == bits.size());
for (size_t i = 0; i < bits.size(); ++i)
{
pb.val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero());
}
}
template<typename FieldT>
void pb_variable_array<FieldT>::fill_with_bits_of_field_element(protoboard<FieldT> &pb, const FieldT &r) const
{
const bigint<FieldT::num_limbs> rint = r.as_bigint();
for (size_t i = 0; i < this->size(); ++i)
{
pb.val((*this)[i]) = rint.test_bit(i) ? FieldT::one() : FieldT::zero();
}
}
template<typename FieldT>
void pb_variable_array<FieldT>::fill_with_bits_of_uint64(protoboard<FieldT> &pb, const uint64_t i) const
{
this->fill_with_bits_of_field_element(pb, FieldT(i, true));
}
template<typename FieldT>
std::vector<FieldT> pb_variable_array<FieldT>::get_vals(const protoboard<FieldT> &pb) const
{
std::vector<FieldT> result(this->size());
for (size_t i = 0; i < this->size(); ++i)
{
result[i] = pb.val((*this)[i]);
}
return result;
}
template<typename FieldT>
bit_vector pb_variable_array<FieldT>::get_bits(const protoboard<FieldT> &pb) const
{
bit_vector result;
for (size_t i = 0; i < this->size(); ++i)
{
const FieldT v = pb.val((*this)[i]);
assert(v == FieldT::zero() || v == FieldT::one());
result.push_back(v == FieldT::one());
}
return result;
}
template<typename FieldT>
FieldT pb_variable_array<FieldT>::get_field_element_from_bits(const protoboard<FieldT> &pb) const
{
FieldT result = FieldT::zero();
for (size_t i = 0; i < this->size(); ++i)
{
/* push in the new bit */
const FieldT v = pb.val((*this)[this->size()-1-i]);
assert(v == FieldT::zero() || v == FieldT::one());
result += result + v;
}
return result;
}
template<typename FieldT>
pb_linear_combination<FieldT>::pb_linear_combination()
{
this->is_variable = false;
this->index = 0;
}
template<typename FieldT>
pb_linear_combination<FieldT>::pb_linear_combination(const pb_variable<FieldT> &var)
{
this->is_variable = true;
this->index = var.index;
this->terms.emplace_back(linear_term<FieldT>(var));
}
template<typename FieldT>
void pb_linear_combination<FieldT>::assign(protoboard<FieldT> &pb, const linear_combination<FieldT> &lc)
{
assert(this->is_variable == false);
this->index = pb.allocate_lc_index();
this->terms = lc.terms;
}
template<typename FieldT>
void pb_linear_combination<FieldT>::evaluate(protoboard<FieldT> &pb) const
{
if (this->is_variable)
{
return; // do nothing
}
FieldT sum = 0;
for (auto term : this->terms)
{
sum += term.coeff * pb.val(pb_variable<FieldT>(term.index));
}
pb.lc_val(*this) = sum;
}
template<typename FieldT>
bool pb_linear_combination<FieldT>::is_constant() const
{
if (is_variable)
{
return (index == 0);
}
else
{
for (auto term : this->terms)
{
if (term.index != 0)
{
return false;
}
}
return true;
}
}
template<typename FieldT>
FieldT pb_linear_combination<FieldT>::constant_term() const
{
if (is_variable)
{
return (index == 0 ? FieldT::one() : FieldT::zero());
}
else
{
FieldT result = FieldT::zero();
for (auto term : this->terms)
{
if (term.index == 0)
{
result += term.coeff;
}
}
return result;
}
}
template<typename FieldT>
void pb_linear_combination_array<FieldT>::evaluate(protoboard<FieldT> &pb) const
{
for (size_t i = 0; i < this->size(); ++i)
{
(*this)[i].evaluate(pb);
}
}
template<typename FieldT>
void pb_linear_combination_array<FieldT>::fill_with_field_elements(protoboard<FieldT> &pb, const std::vector<FieldT>& vals) const
{
assert(this->size() == vals.size());
for (size_t i = 0; i < vals.size(); ++i)
{
pb.lc_val((*this)[i]) = vals[i];
}
}
template<typename FieldT>
void pb_linear_combination_array<FieldT>::fill_with_bits(protoboard<FieldT> &pb, const bit_vector& bits) const
{
assert(this->size() == bits.size());
for (size_t i = 0; i < bits.size(); ++i)
{
pb.lc_val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero());
}
}
template<typename FieldT>
void pb_linear_combination_array<FieldT>::fill_with_bits_of_field_element(protoboard<FieldT> &pb, const FieldT &r) const
{
const bigint<FieldT::num_limbs> rint = r.as_bigint();
for (size_t i = 0; i < this->size(); ++i)
{
pb.lc_val((*this)[i]) = rint.test_bit(i) ? FieldT::one() : FieldT::zero();
}
}
template<typename FieldT>
void pb_linear_combination_array<FieldT>::fill_with_bits_of_uint64(protoboard<FieldT> &pb, const uint64_t i) const
{
this->fill_with_bits_of_field_element(pb, FieldT(i));
}
template<typename FieldT>
std::vector<FieldT> pb_linear_combination_array<FieldT>::get_vals(const protoboard<FieldT> &pb) const
{
std::vector<FieldT> result(this->size());
for (size_t i = 0; i < this->size(); ++i)
{
result[i] = pb.lc_val((*this)[i]);
}
return result;
}
template<typename FieldT>
bit_vector pb_linear_combination_array<FieldT>::get_bits(const protoboard<FieldT> &pb) const
{
bit_vector result;
for (size_t i = 0; i < this->size(); ++i)
{
const FieldT v = pb.lc_val((*this)[i]);
assert(v == FieldT::zero() || v == FieldT::one());
result.push_back(v == FieldT::one());
}
return result;
}
template<typename FieldT>
FieldT pb_linear_combination_array<FieldT>::get_field_element_from_bits(const protoboard<FieldT> &pb) const
{
FieldT result = FieldT::zero();
for (size_t i = 0; i < this->size(); ++i)
{
/* push in the new bit */
const FieldT v = pb.lc_val((*this)[this->size()-1-i]);
assert(v == FieldT::zero() || v == FieldT::one());
result += result + v;
}
return result;
}
template<typename FieldT>
linear_combination<FieldT> pb_sum(const pb_linear_combination_array<FieldT> &v)
{
linear_combination<FieldT> result;
for (auto &term : v)
{
result = result + term;
}
return result;
}
template<typename FieldT>
linear_combination<FieldT> pb_packing_sum(const pb_linear_combination_array<FieldT> &v)
{
FieldT twoi = FieldT::one(); // will hold 2^i entering each iteration
std::vector<linear_term<FieldT> > all_terms;
for (auto &lc : v)
{
for (auto &term : lc.terms)
{
all_terms.emplace_back(twoi * term);
}
twoi += twoi;
}
return linear_combination<FieldT>(all_terms);
}
template<typename FieldT>
linear_combination<FieldT> pb_coeff_sum(const pb_linear_combination_array<FieldT> &v, const std::vector<FieldT> &coeffs)
{
assert(v.size() == coeffs.size());
std::vector<linear_term<FieldT> > all_terms;
auto coeff_it = coeffs.begin();
for (auto &lc : v)
{
for (auto &term : lc.terms)
{
all_terms.emplace_back((*coeff_it) * term);
}
++coeff_it;
}
return linear_combination<FieldT>(all_terms);
}
} // libsnark
#endif // PB_VARIABLE_TCC

75
src/snark/libsnark/gadgetlib1/protoboard.hpp

@ -1,75 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef PROTOBOARD_HPP_
#define PROTOBOARD_HPP_
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include "gadgetlib1/pb_variable.hpp"
#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp"
#include "common/utils.hpp"
namespace libsnark {
template<typename FieldT>
class r1cs_constraint;
template<typename FieldT>
class r1cs_constraint_system;
template<typename FieldT>
class protoboard {
private:
FieldT constant_term; /* only here, because pb.val() needs to be able to return reference to the constant 1 term */
r1cs_variable_assignment<FieldT> values; /* values[0] will hold the value of the first allocated variable of the protoboard, *NOT* constant 1 */
var_index_t next_free_var;
lc_index_t next_free_lc;
std::vector<FieldT> lc_values;
public:
r1cs_constraint_system<FieldT> constraint_system;
protoboard();
void clear_values();
FieldT& val(const pb_variable<FieldT> &var);
FieldT val(const pb_variable<FieldT> &var) const;
FieldT& lc_val(const pb_linear_combination<FieldT> &lc);
FieldT lc_val(const pb_linear_combination<FieldT> &lc) const;
void add_r1cs_constraint(const r1cs_constraint<FieldT> &constr, const std::string &annotation="");
void augment_variable_annotation(const pb_variable<FieldT> &v, const std::string &postfix);
bool is_satisfied() const;
void dump_variables() const;
size_t num_constraints() const;
size_t num_inputs() const;
size_t num_variables() const;
void set_input_sizes(const size_t primary_input_size);
r1cs_variable_assignment<FieldT> full_variable_assignment() const;
r1cs_primary_input<FieldT> primary_input() const;
r1cs_auxiliary_input<FieldT> auxiliary_input() const;
r1cs_constraint_system<FieldT> get_constraint_system() const;
friend class pb_variable<FieldT>;
friend class pb_linear_combination<FieldT>;
private:
var_index_t allocate_var_index(const std::string &annotation="");
lc_index_t allocate_lc_index();
};
} // libsnark
#include "gadgetlib1/protoboard.tcc"
#endif // PROTOBOARD_HPP_

189
src/snark/libsnark/gadgetlib1/protoboard.tcc

@ -1,189 +0,0 @@
/** @file
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef PROTOBOARD_TCC_
#define PROTOBOARD_TCC_
#include <cstdio>
#include <cstdarg>
#include "common/profiling.hpp"
namespace libsnark {
template<typename FieldT>
protoboard<FieldT>::protoboard()
{
constant_term = FieldT::one();
#ifdef DEBUG
constraint_system.variable_annotations[0] = "ONE";
#endif
next_free_var = 1; /* to account for constant 1 term */
next_free_lc = 0;
}
template<typename FieldT>
void protoboard<FieldT>::clear_values()
{
std::fill(values.begin(), values.end(), FieldT::zero());
}
template<typename FieldT>
var_index_t protoboard<FieldT>::allocate_var_index(const std::string &annotation)
{
#ifdef DEBUG
assert(annotation != "");
constraint_system.variable_annotations[next_free_var] = annotation;
#else
UNUSED(annotation);
#endif
++constraint_system.auxiliary_input_size;
values.emplace_back(FieldT::zero());
return next_free_var++;
}
template<typename FieldT>
lc_index_t protoboard<FieldT>::allocate_lc_index()
{
lc_values.emplace_back(FieldT::zero());
return next_free_lc++;
}
template<typename FieldT>
FieldT& protoboard<FieldT>::val(const pb_variable<FieldT> &var)
{
assert(var.index <= values.size());
return (var.index == 0 ? constant_term : values[var.index-1]);
}
template<typename FieldT>
FieldT protoboard<FieldT>::val(const pb_variable<FieldT> &var) const
{
assert(var.index <= values.size());
return (var.index == 0 ? constant_term : values[var.index-1]);
}
template<typename FieldT>
FieldT& protoboard<FieldT>::lc_val(const pb_linear_combination<FieldT> &lc)
{
if (lc.is_variable)
{
return this->val(pb_variable<FieldT>(lc.index));
}
else
{
assert(lc.index < lc_values.size());
return lc_values[lc.index];
}
}
template<typename FieldT>
FieldT protoboard<FieldT>::lc_val(const pb_linear_combination<FieldT> &lc) const
{
if (lc.is_variable)
{
return this->val(pb_variable<FieldT>(lc.index));
}
else
{
assert(lc.index < lc_values.size());
return lc_values[lc.index];
}
}
template<typename FieldT>
void protoboard<FieldT>::add_r1cs_constraint(const r1cs_constraint<FieldT> &constr, const std::string &annotation)
{
#ifdef DEBUG
assert(annotation != "");
constraint_system.constraint_annotations[constraint_system.constraints.size()] = annotation;
#else
UNUSED(annotation);
#endif
constraint_system.constraints.emplace_back(constr);
}
template<typename FieldT>
void protoboard<FieldT>::augment_variable_annotation(const pb_variable<FieldT> &v, const std::string &postfix)
{
#ifdef DEBUG
auto it = constraint_system.variable_annotations.find(v.index);
constraint_system.variable_annotations[v.index] = (it == constraint_system.variable_annotations.end() ? "" : it->second + " ") + postfix;
#endif
}
template<typename FieldT>
bool protoboard<FieldT>::is_satisfied() const
{
return constraint_system.is_satisfied(primary_input(), auxiliary_input());
}
template<typename FieldT>
void protoboard<FieldT>::dump_variables() const
{
#ifdef DEBUG
for (size_t i = 0; i < constraint_system.num_variables; ++i)
{
printf("%-40s --> ", constraint_system.variable_annotations[i].c_str());
values[i].as_bigint().print_hex();
}
#endif
}
template<typename FieldT>
size_t protoboard<FieldT>::num_constraints() const
{
return constraint_system.num_constraints();
}
template<typename FieldT>
size_t protoboard<FieldT>::num_inputs() const
{
return constraint_system.num_inputs();
}
template<typename FieldT>
size_t protoboard<FieldT>::num_variables() const
{
return next_free_var - 1;
}
template<typename FieldT>
void protoboard<FieldT>::set_input_sizes(const size_t primary_input_size)
{
assert(primary_input_size <= num_variables());
constraint_system.primary_input_size = primary_input_size;
constraint_system.auxiliary_input_size = num_variables() - primary_input_size;
}
template<typename FieldT>
r1cs_variable_assignment<FieldT> protoboard<FieldT>::full_variable_assignment() const
{
return values;
}
template<typename FieldT>
r1cs_primary_input<FieldT> protoboard<FieldT>::primary_input() const
{
return r1cs_primary_input<FieldT>(values.begin(), values.begin() + num_inputs());
}
template<typename FieldT>
r1cs_auxiliary_input<FieldT> protoboard<FieldT>::auxiliary_input() const
{
return r1cs_primary_input<FieldT>(values.begin() + num_inputs(), values.end());
}
template<typename FieldT>
r1cs_constraint_system<FieldT> protoboard<FieldT>::get_constraint_system() const
{
return constraint_system;
}
} // libsnark
#endif // PROTOBOARD_TCC_

12
src/snark/libsnark/gtests.cpp

@ -1,12 +0,0 @@
#include <gtest/gtest.h>
#include "common/profiling.hpp"
int main(int argc, char **argv) {
libsnark::inhibit_profiling_info = true;
libsnark::inhibit_profiling_counters = true;
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

70
src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.hpp

@ -1,70 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for a R1CS-to-QAP reduction, that is, constructing
a QAP ("Quadratic Arithmetic Program") from a R1CS ("Rank-1 Constraint System").
QAPs are defined in \[GGPR13], and construced for R1CS also in \[GGPR13].
The implementation of the reduction follows, extends, and optimizes
the efficient approach described in Appendix E of \[BCGTV13].
References:
\[BCGTV13]
"SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge",
Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza,
CRYPTO 2013,
<http://eprint.iacr.org/2013/507>
\[GGPR13]:
"Quadratic span programs and succinct NIZKs without PCPs",
Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova,
EUROCRYPT 2013,
<http://eprint.iacr.org/2012/215>
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef R1CS_TO_QAP_HPP_
#define R1CS_TO_QAP_HPP_
#include "relations/arithmetic_programs/qap/qap.hpp"
#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp"
namespace libsnark {
/**
* Instance map for the R1CS-to-QAP reduction.
*/
template<typename FieldT>
qap_instance<FieldT> r1cs_to_qap_instance_map(const r1cs_constraint_system<FieldT> &cs);
/**
* Instance map for the R1CS-to-QAP reduction followed by evaluation of the resulting QAP instance.
*/
template<typename FieldT>
qap_instance_evaluation<FieldT> r1cs_to_qap_instance_map_with_evaluation(const r1cs_constraint_system<FieldT> &cs,
const FieldT &t);
/**
* Witness map for the R1CS-to-QAP reduction.
*
* The witness map takes zero knowledge into account when d1,d2,d3 are random.
*/
template<typename FieldT>
qap_witness<FieldT> r1cs_to_qap_witness_map(const r1cs_constraint_system<FieldT> &cs,
const r1cs_primary_input<FieldT> &primary_input,
const r1cs_auxiliary_input<FieldT> &auxiliary_input,
const FieldT &d1,
const FieldT &d2,
const FieldT &d3);
} // libsnark
#include "reductions/r1cs_to_qap/r1cs_to_qap.tcc"
#endif // R1CS_TO_QAP_HPP_

338
src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.tcc

@ -1,338 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for a R1CS-to-QAP reduction.
See r1cs_to_qap.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef R1CS_TO_QAP_TCC_
#define R1CS_TO_QAP_TCC_
#include "common/profiling.hpp"
#include "common/utils.hpp"
#include "algebra/evaluation_domain/evaluation_domain.hpp"
namespace libsnark {
/**
* Instance map for the R1CS-to-QAP reduction.
*
* Namely, given a R1CS constraint system cs, construct a QAP instance for which:
* A := (A_0(z),A_1(z),...,A_m(z))
* B := (B_0(z),B_1(z),...,B_m(z))
* C := (C_0(z),C_1(z),...,C_m(z))
* where
* m = number of variables of the QAP
* and
* each A_i,B_i,C_i is expressed in the Lagrange basis.
*/
template<typename FieldT>
qap_instance<FieldT> r1cs_to_qap_instance_map(const r1cs_constraint_system<FieldT> &cs)
{
enter_block("Call to r1cs_to_qap_instance_map");
const std::shared_ptr<evaluation_domain<FieldT> > domain = get_evaluation_domain<FieldT>(cs.num_constraints() + cs.num_inputs() + 1);
std::vector<std::map<size_t, FieldT> > A_in_Lagrange_basis(cs.num_variables()+1);
std::vector<std::map<size_t, FieldT> > B_in_Lagrange_basis(cs.num_variables()+1);
std::vector<std::map<size_t, FieldT> > C_in_Lagrange_basis(cs.num_variables()+1);
enter_block("Compute polynomials A, B, C in Lagrange basis");
/**
* add and process the constraints
* input_i * 0 = 0
* to ensure soundness of input consistency
*/
for (size_t i = 0; i <= cs.num_inputs(); ++i)
{
A_in_Lagrange_basis[i][cs.num_constraints() + i] = FieldT::one();
}
/* process all other constraints */
for (size_t i = 0; i < cs.num_constraints(); ++i)
{
for (size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j)
{
A_in_Lagrange_basis[cs.constraints[i].a.terms[j].index][i] +=
cs.constraints[i].a.terms[j].coeff;
}
for (size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j)
{
B_in_Lagrange_basis[cs.constraints[i].b.terms[j].index][i] +=
cs.constraints[i].b.terms[j].coeff;
}
for (size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j)
{
C_in_Lagrange_basis[cs.constraints[i].c.terms[j].index][i] +=
cs.constraints[i].c.terms[j].coeff;
}
}
leave_block("Compute polynomials A, B, C in Lagrange basis");
leave_block("Call to r1cs_to_qap_instance_map");
return qap_instance<FieldT>(domain,
cs.num_variables(),
domain->m,
cs.num_inputs(),
std::move(A_in_Lagrange_basis),
std::move(B_in_Lagrange_basis),
std::move(C_in_Lagrange_basis));
}
/**
* Instance map for the R1CS-to-QAP reduction followed by evaluation of the resulting QAP instance.
*
* Namely, given a R1CS constraint system cs and a field element t, construct
* a QAP instance (evaluated at t) for which:
* At := (A_0(t),A_1(t),...,A_m(t))
* Bt := (B_0(t),B_1(t),...,B_m(t))
* Ct := (C_0(t),C_1(t),...,C_m(t))
* Ht := (1,t,t^2,...,t^n)
* Zt := Z(t) = "vanishing polynomial of a certain set S, evaluated at t"
* where
* m = number of variables of the QAP
* n = degree of the QAP
*/
template<typename FieldT>
qap_instance_evaluation<FieldT> r1cs_to_qap_instance_map_with_evaluation(const r1cs_constraint_system<FieldT> &cs,
const FieldT &t)
{
enter_block("Call to r1cs_to_qap_instance_map_with_evaluation");
const std::shared_ptr<evaluation_domain<FieldT> > domain = get_evaluation_domain<FieldT>(cs.num_constraints() + cs.num_inputs() + 1);
std::vector<FieldT> At, Bt, Ct, Ht;
At.resize(cs.num_variables()+1, FieldT::zero());
Bt.resize(cs.num_variables()+1, FieldT::zero());
Ct.resize(cs.num_variables()+1, FieldT::zero());
Ht.reserve(domain->m+1);
const FieldT Zt = domain->compute_Z(t);
enter_block("Compute evaluations of A, B, C, H at t");
const std::vector<FieldT> u = domain->lagrange_coeffs(t);
/**
* add and process the constraints
* input_i * 0 = 0
* to ensure soundness of input consistency
*/
for (size_t i = 0; i <= cs.num_inputs(); ++i)
{
At[i] = u[cs.num_constraints() + i];
}
/* process all other constraints */
for (size_t i = 0; i < cs.num_constraints(); ++i)
{
for (size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j)
{
At[cs.constraints[i].a.terms[j].index] +=
u[i]*cs.constraints[i].a.terms[j].coeff;
}
for (size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j)
{
Bt[cs.constraints[i].b.terms[j].index] +=
u[i]*cs.constraints[i].b.terms[j].coeff;
}
for (size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j)
{
Ct[cs.constraints[i].c.terms[j].index] +=
u[i]*cs.constraints[i].c.terms[j].coeff;
}
}
FieldT ti = FieldT::one();
for (size_t i = 0; i < domain->m+1; ++i)
{
Ht.emplace_back(ti);
ti *= t;
}
leave_block("Compute evaluations of A, B, C, H at t");
leave_block("Call to r1cs_to_qap_instance_map_with_evaluation");
return qap_instance_evaluation<FieldT>(domain,
cs.num_variables(),
domain->m,
cs.num_inputs(),
t,
std::move(At),
std::move(Bt),
std::move(Ct),
std::move(Ht),
Zt);
}
/**
* Witness map for the R1CS-to-QAP reduction.
*
* The witness map takes zero knowledge into account when d1,d2,d3 are random.
*
* More precisely, compute the coefficients
* h_0,h_1,...,h_n
* of the polynomial
* H(z) := (A(z)*B(z)-C(z))/Z(z)
* where
* A(z) := A_0(z) + \sum_{k=1}^{m} w_k A_k(z) + d1 * Z(z)
* B(z) := B_0(z) + \sum_{k=1}^{m} w_k B_k(z) + d2 * Z(z)
* C(z) := C_0(z) + \sum_{k=1}^{m} w_k C_k(z) + d3 * Z(z)
* Z(z) := "vanishing polynomial of set S"
* and
* m = number of variables of the QAP
* n = degree of the QAP
*
* This is done as follows:
* (1) compute evaluations of A,B,C on S = {sigma_1,...,sigma_n}
* (2) compute coefficients of A,B,C
* (3) compute evaluations of A,B,C on T = "coset of S"
* (4) compute evaluation of H on T
* (5) compute coefficients of H
* (6) patch H to account for d1,d2,d3 (i.e., add coefficients of the polynomial (A d2 + B d1 - d3) + d1*d2*Z )
*
* The code below is not as simple as the above high-level description due to
* some reshuffling to save space.
*/
template<typename FieldT>
qap_witness<FieldT> r1cs_to_qap_witness_map(const r1cs_constraint_system<FieldT> &cs,
const r1cs_primary_input<FieldT> &primary_input,
const r1cs_auxiliary_input<FieldT> &auxiliary_input,
const FieldT &d1,
const FieldT &d2,
const FieldT &d3)
{
enter_block("Call to r1cs_to_qap_witness_map");
/* sanity check */
assert(cs.is_satisfied(primary_input, auxiliary_input));
const std::shared_ptr<evaluation_domain<FieldT> > domain = get_evaluation_domain<FieldT>(cs.num_constraints() + cs.num_inputs() + 1);
r1cs_variable_assignment<FieldT> full_variable_assignment = primary_input;
full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end());
enter_block("Compute evaluation of polynomials A, B on set S");
std::vector<FieldT> aA(domain->m, FieldT::zero()), aB(domain->m, FieldT::zero());
/* account for the additional constraints input_i * 0 = 0 */
for (size_t i = 0; i <= cs.num_inputs(); ++i)
{
aA[i+cs.num_constraints()] = (i > 0 ? full_variable_assignment[i-1] : FieldT::one());
}
/* account for all other constraints */
for (size_t i = 0; i < cs.num_constraints(); ++i)
{
aA[i] += cs.constraints[i].a.evaluate(full_variable_assignment);
aB[i] += cs.constraints[i].b.evaluate(full_variable_assignment);
}
leave_block("Compute evaluation of polynomials A, B on set S");
enter_block("Compute coefficients of polynomial A");
domain->iFFT(aA);
leave_block("Compute coefficients of polynomial A");
enter_block("Compute coefficients of polynomial B");
domain->iFFT(aB);
leave_block("Compute coefficients of polynomial B");
enter_block("Compute ZK-patch");
std::vector<FieldT> coefficients_for_H(domain->m+1, FieldT::zero());
#ifdef MULTICORE
#pragma omp parallel for
#endif
/* add coefficients of the polynomial (d2*A + d1*B - d3) + d1*d2*Z */
for (size_t i = 0; i < domain->m; ++i)
{
coefficients_for_H[i] = d2*aA[i] + d1*aB[i];
}
coefficients_for_H[0] -= d3;
domain->add_poly_Z(d1*d2, coefficients_for_H);
leave_block("Compute ZK-patch");
enter_block("Compute evaluation of polynomial A on set T");
domain->cosetFFT(aA, FieldT::multiplicative_generator);
leave_block("Compute evaluation of polynomial A on set T");
enter_block("Compute evaluation of polynomial B on set T");
domain->cosetFFT(aB, FieldT::multiplicative_generator);
leave_block("Compute evaluation of polynomial B on set T");
enter_block("Compute evaluation of polynomial H on set T");
std::vector<FieldT> &H_tmp = aA; // can overwrite aA because it is not used later
#ifdef MULTICORE
#pragma omp parallel for
#endif
for (size_t i = 0; i < domain->m; ++i)
{
H_tmp[i] = aA[i]*aB[i];
}
std::vector<FieldT>().swap(aB); // destroy aB
enter_block("Compute evaluation of polynomial C on set S");
std::vector<FieldT> aC(domain->m, FieldT::zero());
for (size_t i = 0; i < cs.num_constraints(); ++i)
{
aC[i] += cs.constraints[i].c.evaluate(full_variable_assignment);
}
leave_block("Compute evaluation of polynomial C on set S");
enter_block("Compute coefficients of polynomial C");
domain->iFFT(aC);
leave_block("Compute coefficients of polynomial C");
enter_block("Compute evaluation of polynomial C on set T");
domain->cosetFFT(aC, FieldT::multiplicative_generator);
leave_block("Compute evaluation of polynomial C on set T");
#ifdef MULTICORE
#pragma omp parallel for
#endif
for (size_t i = 0; i < domain->m; ++i)
{
H_tmp[i] = (H_tmp[i]-aC[i]);
}
enter_block("Divide by Z on set T");
domain->divide_by_Z_on_coset(H_tmp);
leave_block("Divide by Z on set T");
leave_block("Compute evaluation of polynomial H on set T");
enter_block("Compute coefficients of polynomial H");
domain->icosetFFT(H_tmp, FieldT::multiplicative_generator);
leave_block("Compute coefficients of polynomial H");
enter_block("Compute sum of H and ZK-patch");
#ifdef MULTICORE
#pragma omp parallel for
#endif
for (size_t i = 0; i < domain->m; ++i)
{
coefficients_for_H[i] += H_tmp[i];
}
leave_block("Compute sum of H and ZK-patch");
leave_block("Call to r1cs_to_qap_witness_map");
return qap_witness<FieldT>(cs.num_variables(),
domain->m,
cs.num_inputs(),
d1,
d2,
d3,
full_variable_assignment,
std::move(coefficients_for_H));
}
} // libsnark
#endif // R1CS_TO_QAP_TCC_

193
src/snark/libsnark/relations/arithmetic_programs/qap/qap.hpp

@ -1,193 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for a QAP ("Quadratic Arithmetic Program").
QAPs are defined in \[GGPR13].
References:
\[GGPR13]:
"Quadratic span programs and succinct NIZKs without PCPs",
Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova,
EUROCRYPT 2013,
<http://eprint.iacr.org/2012/215>
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef QAP_HPP_
#define QAP_HPP_
#include "algebra/evaluation_domain/evaluation_domain.hpp"
namespace libsnark {
/* forward declaration */
template<typename FieldT>
class qap_witness;
/**
* A QAP instance.
*
* Specifically, the datastructure stores:
* - a choice of domain (corresponding to a certain subset of the field);
* - the number of variables, the degree, and the number of inputs; and
* - coefficients of the A,B,C polynomials in the Lagrange basis.
*
* There is no need to store the Z polynomial because it is uniquely
* determined by the domain (as Z is its vanishing polynomial).
*/
template<typename FieldT>
class qap_instance {
private:
size_t num_variables_;
size_t degree_;
size_t num_inputs_;
public:
std::shared_ptr<evaluation_domain<FieldT> > domain;
std::vector<std::map<size_t, FieldT> > A_in_Lagrange_basis;
std::vector<std::map<size_t, FieldT> > B_in_Lagrange_basis;
std::vector<std::map<size_t, FieldT> > C_in_Lagrange_basis;
qap_instance(const std::shared_ptr<evaluation_domain<FieldT> > &domain,
const size_t num_variables,
const size_t degree,
const size_t num_inputs,
const std::vector<std::map<size_t, FieldT> > &A_in_Lagrange_basis,
const std::vector<std::map<size_t, FieldT> > &B_in_Lagrange_basis,
const std::vector<std::map<size_t, FieldT> > &C_in_Lagrange_basis);
qap_instance(const std::shared_ptr<evaluation_domain<FieldT> > &domain,
const size_t num_variables,
const size_t degree,
const size_t num_inputs,
std::vector<std::map<size_t, FieldT> > &&A_in_Lagrange_basis,
std::vector<std::map<size_t, FieldT> > &&B_in_Lagrange_basis,
std::vector<std::map<size_t, FieldT> > &&C_in_Lagrange_basis);
qap_instance(const qap_instance<FieldT> &other) = default;
qap_instance(qap_instance<FieldT> &&other) = default;
qap_instance& operator=(const qap_instance<FieldT> &other) = default;
qap_instance& operator=(qap_instance<FieldT> &&other) = default;
size_t num_variables() const;
size_t degree() const;
size_t num_inputs() const;
bool is_satisfied(const qap_witness<FieldT> &witness) const;
};
/**
* A QAP instance evaluation is a QAP instance that is evaluated at a field element t.
*
* Specifically, the datastructure stores:
* - a choice of domain (corresponding to a certain subset of the field);
* - the number of variables, the degree, and the number of inputs;
* - a field element t;
* - evaluations of the A,B,C (and Z) polynomials at t;
* - evaluations of all monomials of t;
* - counts about how many of the above evaluations are in fact non-zero.
*/
template<typename FieldT>
class qap_instance_evaluation {
private:
size_t num_variables_;
size_t degree_;
size_t num_inputs_;
public:
std::shared_ptr<evaluation_domain<FieldT> > domain;
FieldT t;
std::vector<FieldT> At, Bt, Ct, Ht;
FieldT Zt;
qap_instance_evaluation(const std::shared_ptr<evaluation_domain<FieldT> > &domain,
const size_t num_variables,
const size_t degree,
const size_t num_inputs,
const FieldT &t,
const std::vector<FieldT> &At,
const std::vector<FieldT> &Bt,
const std::vector<FieldT> &Ct,
const std::vector<FieldT> &Ht,
const FieldT &Zt);
qap_instance_evaluation(const std::shared_ptr<evaluation_domain<FieldT> > &domain,
const size_t num_variables,
const size_t degree,
const size_t num_inputs,
const FieldT &t,
std::vector<FieldT> &&At,
std::vector<FieldT> &&Bt,
std::vector<FieldT> &&Ct,
std::vector<FieldT> &&Ht,
const FieldT &Zt);
qap_instance_evaluation(const qap_instance_evaluation<FieldT> &other) = default;
qap_instance_evaluation(qap_instance_evaluation<FieldT> &&other) = default;
qap_instance_evaluation& operator=(const qap_instance_evaluation<FieldT> &other) = default;
qap_instance_evaluation& operator=(qap_instance_evaluation<FieldT> &&other) = default;
size_t num_variables() const;
size_t degree() const;
size_t num_inputs() const;
bool is_satisfied(const qap_witness<FieldT> &witness) const;
};
/**
* A QAP witness.
*/
template<typename FieldT>
class qap_witness {
private:
size_t num_variables_;
size_t degree_;
size_t num_inputs_;
public:
FieldT d1, d2, d3;
std::vector<FieldT> coefficients_for_ABCs;
std::vector<FieldT> coefficients_for_H;
qap_witness(const size_t num_variables,
const size_t degree,
const size_t num_inputs,
const FieldT &d1,
const FieldT &d2,
const FieldT &d3,
const std::vector<FieldT> &coefficients_for_ABCs,
const std::vector<FieldT> &coefficients_for_H);
qap_witness(const size_t num_variables,
const size_t degree,
const size_t num_inputs,
const FieldT &d1,
const FieldT &d2,
const FieldT &d3,
const std::vector<FieldT> &coefficients_for_ABCs,
std::vector<FieldT> &&coefficients_for_H);
qap_witness(const qap_witness<FieldT> &other) = default;
qap_witness(qap_witness<FieldT> &&other) = default;
qap_witness& operator=(const qap_witness<FieldT> &other) = default;
qap_witness& operator=(qap_witness<FieldT> &&other) = default;
size_t num_variables() const;
size_t degree() const;
size_t num_inputs() const;
};
} // libsnark
#include "relations/arithmetic_programs/qap/qap.tcc"
#endif // QAP_HPP_

324
src/snark/libsnark/relations/arithmetic_programs/qap/qap.tcc

@ -1,324 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for a QAP ("Quadratic Arithmetic Program").
See qap.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef QAP_TCC_
#define QAP_TCC_
#include "common/profiling.hpp"
#include "common/utils.hpp"
#include "algebra/evaluation_domain/evaluation_domain.hpp"
#include "algebra/scalar_multiplication/multiexp.hpp"
namespace libsnark {
template<typename FieldT>
qap_instance<FieldT>::qap_instance(const std::shared_ptr<evaluation_domain<FieldT> > &domain,
const size_t num_variables,
const size_t degree,
const size_t num_inputs,
const std::vector<std::map<size_t, FieldT> > &A_in_Lagrange_basis,
const std::vector<std::map<size_t, FieldT> > &B_in_Lagrange_basis,
const std::vector<std::map<size_t, FieldT> > &C_in_Lagrange_basis) :
num_variables_(num_variables),
degree_(degree),
num_inputs_(num_inputs),
domain(domain),
A_in_Lagrange_basis(A_in_Lagrange_basis),
B_in_Lagrange_basis(B_in_Lagrange_basis),
C_in_Lagrange_basis(C_in_Lagrange_basis)
{
}
template<typename FieldT>
qap_instance<FieldT>::qap_instance(const std::shared_ptr<evaluation_domain<FieldT> > &domain,
const size_t num_variables,
const size_t degree,
const size_t num_inputs,
std::vector<std::map<size_t, FieldT> > &&A_in_Lagrange_basis,
std::vector<std::map<size_t, FieldT> > &&B_in_Lagrange_basis,
std::vector<std::map<size_t, FieldT> > &&C_in_Lagrange_basis) :
num_variables_(num_variables),
degree_(degree),
num_inputs_(num_inputs),
domain(domain),
A_in_Lagrange_basis(std::move(A_in_Lagrange_basis)),
B_in_Lagrange_basis(std::move(B_in_Lagrange_basis)),
C_in_Lagrange_basis(std::move(C_in_Lagrange_basis))
{
}
template<typename FieldT>
size_t qap_instance<FieldT>::num_variables() const
{
return num_variables_;
}
template<typename FieldT>
size_t qap_instance<FieldT>::degree() const
{
return degree_;
}
template<typename FieldT>
size_t qap_instance<FieldT>::num_inputs() const
{
return num_inputs_;
}
template<typename FieldT>
bool qap_instance<FieldT>::is_satisfied(const qap_witness<FieldT> &witness) const
{
const FieldT t = FieldT::random_element();
std::vector<FieldT> At(this->num_variables()+1, FieldT::zero());
std::vector<FieldT> Bt(this->num_variables()+1, FieldT::zero());
std::vector<FieldT> Ct(this->num_variables()+1, FieldT::zero());
std::vector<FieldT> Ht(this->degree()+1);
const FieldT Zt = this->domain->compute_Z(t);
const std::vector<FieldT> u = this->domain->lagrange_coeffs(t);
for (size_t i = 0; i < this->num_variables()+1; ++i)
{
for (auto &el : A_in_Lagrange_basis[i])
{
At[i] += u[el.first] * el.second;
}
for (auto &el : B_in_Lagrange_basis[i])
{
Bt[i] += u[el.first] * el.second;
}
for (auto &el : C_in_Lagrange_basis[i])
{
Ct[i] += u[el.first] * el.second;
}
}
FieldT ti = FieldT::one();
for (size_t i = 0; i < this->degree()+1; ++i)
{
Ht[i] = ti;
ti *= t;
}
const qap_instance_evaluation<FieldT> eval_qap_inst(this->domain,
this->num_variables(),
this->degree(),
this->num_inputs(),
t,
std::move(At),
std::move(Bt),
std::move(Ct),
std::move(Ht),
Zt);
return eval_qap_inst.is_satisfied(witness);
}
template<typename FieldT>
qap_instance_evaluation<FieldT>::qap_instance_evaluation(const std::shared_ptr<evaluation_domain<FieldT> > &domain,
const size_t num_variables,
const size_t degree,
const size_t num_inputs,
const FieldT &t,
const std::vector<FieldT> &At,
const std::vector<FieldT> &Bt,
const std::vector<FieldT> &Ct,
const std::vector<FieldT> &Ht,
const FieldT &Zt) :
num_variables_(num_variables),
degree_(degree),
num_inputs_(num_inputs),
domain(domain),
t(t),
At(At),
Bt(Bt),
Ct(Ct),
Ht(Ht),
Zt(Zt)
{
}
template<typename FieldT>
qap_instance_evaluation<FieldT>::qap_instance_evaluation(const std::shared_ptr<evaluation_domain<FieldT> > &domain,
const size_t num_variables,
const size_t degree,
const size_t num_inputs,
const FieldT &t,
std::vector<FieldT> &&At,
std::vector<FieldT> &&Bt,
std::vector<FieldT> &&Ct,
std::vector<FieldT> &&Ht,
const FieldT &Zt) :
num_variables_(num_variables),
degree_(degree),
num_inputs_(num_inputs),
domain(domain),
t(t),
At(std::move(At)),
Bt(std::move(Bt)),
Ct(std::move(Ct)),
Ht(std::move(Ht)),
Zt(Zt)
{
}
template<typename FieldT>
size_t qap_instance_evaluation<FieldT>::num_variables() const
{
return num_variables_;
}
template<typename FieldT>
size_t qap_instance_evaluation<FieldT>::degree() const
{
return degree_;
}
template<typename FieldT>
size_t qap_instance_evaluation<FieldT>::num_inputs() const
{
return num_inputs_;
}
template<typename FieldT>
bool qap_instance_evaluation<FieldT>::is_satisfied(const qap_witness<FieldT> &witness) const
{
if (this->num_variables() != witness.num_variables())
{
return false;
}
if (this->degree() != witness.degree())
{
return false;
}
if (this->num_inputs() != witness.num_inputs())
{
return false;
}
if (this->num_variables() != witness.coefficients_for_ABCs.size())
{
return false;
}
if (this->degree()+1 != witness.coefficients_for_H.size())
{
return false;
}
if (this->At.size() != this->num_variables()+1 || this->Bt.size() != this->num_variables()+1 || this->Ct.size() != this->num_variables()+1)
{
return false;
}
if (this->Ht.size() != this->degree()+1)
{
return false;
}
if (this->Zt != this->domain->compute_Z(this->t))
{
return false;
}
FieldT ans_A = this->At[0] + witness.d1*this->Zt;
FieldT ans_B = this->Bt[0] + witness.d2*this->Zt;
FieldT ans_C = this->Ct[0] + witness.d3*this->Zt;
FieldT ans_H = FieldT::zero();
ans_A = ans_A + naive_plain_exp<FieldT, FieldT>(this->At.begin()+1, this->At.begin()+1+this->num_variables(),
witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables());
ans_B = ans_B + naive_plain_exp<FieldT, FieldT>(this->Bt.begin()+1, this->Bt.begin()+1+this->num_variables(),
witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables());
ans_C = ans_C + naive_plain_exp<FieldT, FieldT>(this->Ct.begin()+1, this->Ct.begin()+1+this->num_variables(),
witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables());
ans_H = ans_H + naive_plain_exp<FieldT, FieldT>(this->Ht.begin(), this->Ht.begin()+this->degree()+1,
witness.coefficients_for_H.begin(), witness.coefficients_for_H.begin()+this->degree()+1);
if (ans_A * ans_B - ans_C != ans_H * this->Zt)
{
return false;
}
return true;
}
template<typename FieldT>
qap_witness<FieldT>::qap_witness(const size_t num_variables,
const size_t degree,
const size_t num_inputs,
const FieldT &d1,
const FieldT &d2,
const FieldT &d3,
const std::vector<FieldT> &coefficients_for_ABCs,
const std::vector<FieldT> &coefficients_for_H) :
num_variables_(num_variables),
degree_(degree),
num_inputs_(num_inputs),
d1(d1),
d2(d2),
d3(d3),
coefficients_for_ABCs(coefficients_for_ABCs),
coefficients_for_H(coefficients_for_H)
{
}
template<typename FieldT>
qap_witness<FieldT>::qap_witness(const size_t num_variables,
const size_t degree,
const size_t num_inputs,
const FieldT &d1,
const FieldT &d2,
const FieldT &d3,
const std::vector<FieldT> &coefficients_for_ABCs,
std::vector<FieldT> &&coefficients_for_H) :
num_variables_(num_variables),
degree_(degree),
num_inputs_(num_inputs),
d1(d1),
d2(d2),
d3(d3),
coefficients_for_ABCs(coefficients_for_ABCs),
coefficients_for_H(std::move(coefficients_for_H))
{
}
template<typename FieldT>
size_t qap_witness<FieldT>::num_variables() const
{
return num_variables_;
}
template<typename FieldT>
size_t qap_witness<FieldT>::degree() const
{
return degree_;
}
template<typename FieldT>
size_t qap_witness<FieldT>::num_inputs() const
{
return num_inputs_;
}
} // libsnark
#endif // QAP_TCC_

109
src/snark/libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp

@ -1,109 +0,0 @@
/**
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <vector>
#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp"
#include "algebra/fields/field_utils.hpp"
#include "common/profiling.hpp"
#include "common/utils.hpp"
#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp"
#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp"
using namespace libsnark;
template<typename FieldT>
void test_qap(const size_t qap_degree, const size_t num_inputs, const bool binary_input)
{
/*
We construct an instance where the QAP degree is qap_degree.
So we generate an instance of R1CS where the number of constraints qap_degree - num_inputs - 1.
See the transformation from R1CS to QAP for why this is the case.
So we need that qap_degree >= num_inputs + 1.
*/
assert(num_inputs + 1 <= qap_degree);
enter_block("Call to test_qap");
const size_t num_constraints = qap_degree - num_inputs - 1;
print_indent(); printf("* QAP degree: %zu\n", qap_degree);
print_indent(); printf("* Number of inputs: %zu\n", num_inputs);
print_indent(); printf("* Number of R1CS constraints: %zu\n", num_constraints);
print_indent(); printf("* Input type: %s\n", binary_input ? "binary" : "field");
enter_block("Generate constraint system and assignment");
r1cs_example<FieldT> example;
if (binary_input)
{
example = generate_r1cs_example_with_binary_input<FieldT>(num_constraints, num_inputs);
}
else
{
example = generate_r1cs_example_with_field_input<FieldT>(num_constraints, num_inputs);
}
leave_block("Generate constraint system and assignment");
enter_block("Check satisfiability of constraint system");
assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input));
leave_block("Check satisfiability of constraint system");
const FieldT t = FieldT::random_element(),
d1 = FieldT::random_element(),
d2 = FieldT::random_element(),
d3 = FieldT::random_element();
enter_block("Compute QAP instance 1");
qap_instance<FieldT> qap_inst_1 = r1cs_to_qap_instance_map(example.constraint_system);
leave_block("Compute QAP instance 1");
enter_block("Compute QAP instance 2");
qap_instance_evaluation<FieldT> qap_inst_2 = r1cs_to_qap_instance_map_with_evaluation(example.constraint_system, t);
leave_block("Compute QAP instance 2");
enter_block("Compute QAP witness");
qap_witness<FieldT> qap_wit = r1cs_to_qap_witness_map(example.constraint_system, example.primary_input, example.auxiliary_input, d1, d2, d3);
leave_block("Compute QAP witness");
enter_block("Check satisfiability of QAP instance 1");
assert(qap_inst_1.is_satisfied(qap_wit));
leave_block("Check satisfiability of QAP instance 1");
enter_block("Check satisfiability of QAP instance 2");
assert(qap_inst_2.is_satisfied(qap_wit));
leave_block("Check satisfiability of QAP instance 2");
leave_block("Call to test_qap");
}
int main()
{
start_profiling();
mnt6_pp::init_public_params();
const size_t num_inputs = 10;
const size_t basic_domain_size = UINT64_C(1)<<mnt6_Fr::s;
const size_t step_domain_size = (UINT64_C(1)<<10) + (UINT64_C(1)<<8);
const size_t extended_domain_size = UINT64_C(1)<<(mnt6_Fr::s+1);
const size_t extended_domain_size_special = extended_domain_size-1;
enter_block("Test QAP with binary input");
test_qap<Fr<alt_bn128_pp> >(UINT64_C(1) << 21, num_inputs, true);
leave_block("Test QAP with binary input");
enter_block("Test QAP with field input");
test_qap<Fr<alt_bn128_pp> >(UINT64_C(1) << 21, num_inputs, false);
leave_block("Test QAP with field input");
}

73
src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp

@ -1,73 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for a R1CS example, as well as functions to sample
R1CS examples with prescribed parameters (according to some distribution).
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef R1CS_EXAMPLES_HPP_
#define R1CS_EXAMPLES_HPP_
#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp"
namespace libsnark {
/**
* A R1CS example comprises a R1CS constraint system, R1CS input, and R1CS witness.
*/
template<typename FieldT>
struct r1cs_example {
r1cs_constraint_system<FieldT> constraint_system;
r1cs_primary_input<FieldT> primary_input;
r1cs_auxiliary_input<FieldT> auxiliary_input;
r1cs_example<FieldT>() = default;
r1cs_example<FieldT>(const r1cs_example<FieldT> &other) = default;
r1cs_example<FieldT>(const r1cs_constraint_system<FieldT> &constraint_system,
const r1cs_primary_input<FieldT> &primary_input,
const r1cs_auxiliary_input<FieldT> &auxiliary_input) :
constraint_system(constraint_system),
primary_input(primary_input),
auxiliary_input(auxiliary_input)
{};
r1cs_example<FieldT>(r1cs_constraint_system<FieldT> &&constraint_system,
r1cs_primary_input<FieldT> &&primary_input,
r1cs_auxiliary_input<FieldT> &&auxiliary_input) :
constraint_system(std::move(constraint_system)),
primary_input(std::move(primary_input)),
auxiliary_input(std::move(auxiliary_input))
{};
};
/**
* Generate a R1CS example such that:
* - the number of constraints of the R1CS constraint system is num_constraints;
* - the number of variables of the R1CS constraint system is (approximately) num_constraints;
* - the number of inputs of the R1CS constraint system is num_inputs;
* - the R1CS input consists of ``full'' field elements (typically require the whole log|Field| bits to represent).
*/
template<typename FieldT>
r1cs_example<FieldT> generate_r1cs_example_with_field_input(const size_t num_constraints,
const size_t num_inputs);
/**
* Generate a R1CS example such that:
* - the number of constraints of the R1CS constraint system is num_constraints;
* - the number of variables of the R1CS constraint system is (approximately) num_constraints;
* - the number of inputs of the R1CS constraint system is num_inputs;
* - the R1CS input consists of binary values (as opposed to ``full'' field elements).
*/
template<typename FieldT>
r1cs_example<FieldT> generate_r1cs_example_with_binary_input(const size_t num_constraints,
const size_t num_inputs);
} // libsnark
#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc"
#endif // R1CS_EXAMPLES_HPP_

164
src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc

@ -1,164 +0,0 @@
/** @file
*****************************************************************************
Implementation of functions to sample R1CS examples with prescribed parameters
(according to some distribution).
See r1cs_examples.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef R1CS_EXAMPLES_TCC_
#define R1CS_EXAMPLES_TCC_
#include <cassert>
#include "common/utils.hpp"
namespace libsnark {
template<typename FieldT>
r1cs_example<FieldT> generate_r1cs_example_with_field_input(const size_t num_constraints,
const size_t num_inputs)
{
enter_block("Call to generate_r1cs_example_with_field_input");
assert(num_inputs <= num_constraints + 2);
r1cs_constraint_system<FieldT> cs;
cs.primary_input_size = num_inputs;
cs.auxiliary_input_size = 2 + num_constraints - num_inputs; // TODO: explain this
r1cs_variable_assignment<FieldT> full_variable_assignment;
FieldT a = FieldT::random_element();
FieldT b = FieldT::random_element();
full_variable_assignment.push_back(a);
full_variable_assignment.push_back(b);
for (size_t i = 0; i < num_constraints-1; ++i)
{
linear_combination<FieldT> A, B, C;
if (i % 2)
{
// a * b = c
A.add_term(i+1, 1);
B.add_term(i+2, 1);
C.add_term(i+3, 1);
FieldT tmp = a*b;
full_variable_assignment.push_back(tmp);
a = b; b = tmp;
}
else
{
// a + b = c
B.add_term(0, 1);
A.add_term(i+1, 1);
A.add_term(i+2, 1);
C.add_term(i+3, 1);
FieldT tmp = a+b;
full_variable_assignment.push_back(tmp);
a = b; b = tmp;
}
cs.add_constraint(r1cs_constraint<FieldT>(A, B, C));
}
linear_combination<FieldT> A, B, C;
FieldT fin = FieldT::zero();
for (size_t i = 1; i < cs.num_variables(); ++i)
{
A.add_term(i, 1);
B.add_term(i, 1);
fin = fin + full_variable_assignment[i-1];
}
C.add_term(cs.num_variables(), 1);
cs.add_constraint(r1cs_constraint<FieldT>(A, B, C));
full_variable_assignment.push_back(fin.squared());
/* split variable assignment */
r1cs_primary_input<FieldT> primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs);
r1cs_primary_input<FieldT> auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end());
/* sanity checks */
assert(cs.num_variables() == full_variable_assignment.size());
assert(cs.num_variables() >= num_inputs);
assert(cs.num_inputs() == num_inputs);
assert(cs.num_constraints() == num_constraints);
assert(cs.is_satisfied(primary_input, auxiliary_input));
leave_block("Call to generate_r1cs_example_with_field_input");
return r1cs_example<FieldT>(std::move(cs), std::move(primary_input), std::move(auxiliary_input));
}
template<typename FieldT>
r1cs_example<FieldT> generate_r1cs_example_with_binary_input(const size_t num_constraints,
const size_t num_inputs)
{
enter_block("Call to generate_r1cs_example_with_binary_input");
assert(num_inputs >= 1);
r1cs_constraint_system<FieldT> cs;
cs.primary_input_size = num_inputs;
cs.auxiliary_input_size = num_constraints; /* we will add one auxiliary variable per constraint */
r1cs_variable_assignment<FieldT> full_variable_assignment;
for (size_t i = 0; i < num_inputs; ++i)
{
full_variable_assignment.push_back(FieldT(std::rand() % 2));
}
size_t lastvar = num_inputs-1;
for (size_t i = 0; i < num_constraints; ++i)
{
++lastvar;
const size_t u = (i == 0 ? std::rand() % num_inputs : std::rand() % i);
const size_t v = (i == 0 ? std::rand() % num_inputs : std::rand() % i);
/* chose two random bits and XOR them together:
res = u + v - 2 * u * v
2 * u * v = u + v - res
*/
linear_combination<FieldT> A, B, C;
A.add_term(u+1, 2);
B.add_term(v+1, 1);
if (u == v)
{
C.add_term(u+1, 2);
}
else
{
C.add_term(u+1, 1);
C.add_term(v+1, 1);
}
C.add_term(lastvar+1, -FieldT::one());
cs.add_constraint(r1cs_constraint<FieldT>(A, B, C));
full_variable_assignment.push_back(full_variable_assignment[u] + full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v]);
}
/* split variable assignment */
r1cs_primary_input<FieldT> primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs);
r1cs_primary_input<FieldT> auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end());
/* sanity checks */
assert(cs.num_variables() == full_variable_assignment.size());
assert(cs.num_variables() >= num_inputs);
assert(cs.num_inputs() == num_inputs);
assert(cs.num_constraints() == num_constraints);
assert(cs.is_satisfied(primary_input, auxiliary_input));
leave_block("Call to generate_r1cs_example_with_binary_input");
return r1cs_example<FieldT>(std::move(cs), std::move(primary_input), std::move(auxiliary_input));
}
} // libsnark
#endif // R1CS_EXAMPLES_TCC

153
src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp

@ -1,153 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for:
- a R1CS constraint,
- a R1CS variable assignment, and
- a R1CS constraint system.
Above, R1CS stands for "Rank-1 Constraint System".
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef R1CS_HPP_
#define R1CS_HPP_
#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "relations/variable.hpp"
namespace libsnark {
/************************* R1CS constraint ***********************************/
template<typename FieldT>
class r1cs_constraint;
template<typename FieldT>
std::ostream& operator<<(std::ostream &out, const r1cs_constraint<FieldT> &c);
template<typename FieldT>
std::istream& operator>>(std::istream &in, r1cs_constraint<FieldT> &c);
/**
* A R1CS constraint is a formal expression of the form
*
* < A , X > * < B , X > = < C , X > ,
*
* where X = (x_0,x_1,...,x_m) is a vector of formal variables and A,B,C each
* consist of 1+m elements in <FieldT>.
*
* A R1CS constraint is used to construct a R1CS constraint system (see below).
*/
template<typename FieldT>
class r1cs_constraint {
public:
linear_combination<FieldT> a, b, c;
r1cs_constraint() {};
r1cs_constraint(const linear_combination<FieldT> &a,
const linear_combination<FieldT> &b,
const linear_combination<FieldT> &c);
r1cs_constraint(const std::initializer_list<linear_combination<FieldT> > &A,
const std::initializer_list<linear_combination<FieldT> > &B,
const std::initializer_list<linear_combination<FieldT> > &C);
bool operator==(const r1cs_constraint<FieldT> &other) const;
friend std::ostream& operator<< <FieldT>(std::ostream &out, const r1cs_constraint<FieldT> &c);
friend std::istream& operator>> <FieldT>(std::istream &in, r1cs_constraint<FieldT> &c);
};
/************************* R1CS variable assignment **************************/
/**
* A R1CS variable assignment is a vector of <FieldT> elements that represents
* a candidate solution to a R1CS constraint system (see below).
*/
/* TODO: specify that it does *NOT* include the constant 1 */
template<typename FieldT>
using r1cs_primary_input = std::vector<FieldT>;
template<typename FieldT>
using r1cs_auxiliary_input = std::vector<FieldT>;
template<typename FieldT>
using r1cs_variable_assignment = std::vector<FieldT>; /* note the changed name! (TODO: remove this comment after primary_input transition is complete) */
/************************* R1CS constraint system ****************************/
template<typename FieldT>
class r1cs_constraint_system;
template<typename FieldT>
std::ostream& operator<<(std::ostream &out, const r1cs_constraint_system<FieldT> &cs);
template<typename FieldT>
std::istream& operator>>(std::istream &in, r1cs_constraint_system<FieldT> &cs);
/**
* A system of R1CS constraints looks like
*
* { < A_k , X > * < B_k , X > = < C_k , X > }_{k=1}^{n} .
*
* In other words, the system is satisfied if and only if there exist a
* USCS variable assignment for which each R1CS constraint is satisfied.
*
* NOTE:
* The 0-th variable (i.e., "x_{0}") always represents the constant 1.
* Thus, the 0-th variable is not included in num_variables.
*/
template<typename FieldT>
class r1cs_constraint_system {
public:
size_t primary_input_size;
size_t auxiliary_input_size;
std::vector<r1cs_constraint<FieldT> > constraints;
r1cs_constraint_system() : primary_input_size(0), auxiliary_input_size(0) {}
size_t num_inputs() const;
size_t num_variables() const;
size_t num_constraints() const;
#ifdef DEBUG
std::map<size_t, std::string> constraint_annotations;
std::map<size_t, std::string> variable_annotations;
#endif
bool is_valid() const;
bool is_satisfied(const r1cs_primary_input<FieldT> &primary_input,
const r1cs_auxiliary_input<FieldT> &auxiliary_input) const;
void add_constraint(const r1cs_constraint<FieldT> &c);
void add_constraint(const r1cs_constraint<FieldT> &c, const std::string &annotation);
void swap_AB_if_beneficial();
bool operator==(const r1cs_constraint_system<FieldT> &other) const;
friend std::ostream& operator<< <FieldT>(std::ostream &out, const r1cs_constraint_system<FieldT> &cs);
friend std::istream& operator>> <FieldT>(std::istream &in, r1cs_constraint_system<FieldT> &cs);
void report_linear_constraint_statistics() const;
};
} // libsnark
#include "relations/constraint_satisfaction_problems/r1cs/r1cs.tcc"
#endif // R1CS_HPP_

310
src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc

@ -1,310 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for:
- a R1CS constraint,
- a R1CS variable assignment, and
- a R1CS constraint system.
See r1cs.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef R1CS_TCC_
#define R1CS_TCC_
#include <algorithm>
#include <cassert>
#include <set>
#include "common/utils.hpp"
#include "common/profiling.hpp"
#include "algebra/fields/bigint.hpp"
namespace libsnark {
template<typename FieldT>
r1cs_constraint<FieldT>::r1cs_constraint(const linear_combination<FieldT> &a,
const linear_combination<FieldT> &b,
const linear_combination<FieldT> &c) :
a(a), b(b), c(c)
{
}
template<typename FieldT>
r1cs_constraint<FieldT>::r1cs_constraint(const std::initializer_list<linear_combination<FieldT> > &A,
const std::initializer_list<linear_combination<FieldT> > &B,
const std::initializer_list<linear_combination<FieldT> > &C)
{
for (auto lc_A : A)
{
a.terms.insert(a.terms.end(), lc_A.terms.begin(), lc_A.terms.end());
}
for (auto lc_B : B)
{
b.terms.insert(b.terms.end(), lc_B.terms.begin(), lc_B.terms.end());
}
for (auto lc_C : C)
{
c.terms.insert(c.terms.end(), lc_C.terms.begin(), lc_C.terms.end());
}
}
template<typename FieldT>
bool r1cs_constraint<FieldT>::operator==(const r1cs_constraint<FieldT> &other) const
{
return (this->a == other.a &&
this->b == other.b &&
this->c == other.c);
}
template<typename FieldT>
std::ostream& operator<<(std::ostream &out, const r1cs_constraint<FieldT> &c)
{
out << c.a;
out << c.b;
out << c.c;
return out;
}
template<typename FieldT>
std::istream& operator>>(std::istream &in, r1cs_constraint<FieldT> &c)
{
in >> c.a;
in >> c.b;
in >> c.c;
return in;
}
template<typename FieldT>
size_t r1cs_constraint_system<FieldT>::num_inputs() const
{
return primary_input_size;
}
template<typename FieldT>
size_t r1cs_constraint_system<FieldT>::num_variables() const
{
return primary_input_size + auxiliary_input_size;
}
template<typename FieldT>
size_t r1cs_constraint_system<FieldT>::num_constraints() const
{
return constraints.size();
}
template<typename FieldT>
bool r1cs_constraint_system<FieldT>::is_valid() const
{
if (this->num_inputs() > this->num_variables()) return false;
for (size_t c = 0; c < constraints.size(); ++c)
{
if (!(constraints[c].a.is_valid(this->num_variables()) &&
constraints[c].b.is_valid(this->num_variables()) &&
constraints[c].c.is_valid(this->num_variables())))
{
return false;
}
}
return true;
}
template<typename FieldT>
void dump_r1cs_constraint(const r1cs_constraint<FieldT> &constraint,
const r1cs_variable_assignment<FieldT> &full_variable_assignment,
const std::map<size_t, std::string> &variable_annotations)
{
printf("terms for a:\n"); constraint.a.print_with_assignment(full_variable_assignment, variable_annotations);
printf("terms for b:\n"); constraint.b.print_with_assignment(full_variable_assignment, variable_annotations);
printf("terms for c:\n"); constraint.c.print_with_assignment(full_variable_assignment, variable_annotations);
}
template<typename FieldT>
bool r1cs_constraint_system<FieldT>::is_satisfied(const r1cs_primary_input<FieldT> &primary_input,
const r1cs_auxiliary_input<FieldT> &auxiliary_input) const
{
assert(primary_input.size() == num_inputs());
assert(primary_input.size() + auxiliary_input.size() == num_variables());
r1cs_variable_assignment<FieldT> full_variable_assignment = primary_input;
full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end());
for (size_t c = 0; c < constraints.size(); ++c)
{
const FieldT ares = constraints[c].a.evaluate(full_variable_assignment);
const FieldT bres = constraints[c].b.evaluate(full_variable_assignment);
const FieldT cres = constraints[c].c.evaluate(full_variable_assignment);
if (!(ares*bres == cres))
{
#ifdef DEBUG
auto it = constraint_annotations.find(c);
printf("constraint %zu (%s) unsatisfied\n", c, (it == constraint_annotations.end() ? "no annotation" : it->second.c_str()));
printf("<a,(1,x)> = "); ares.print();
printf("<b,(1,x)> = "); bres.print();
printf("<c,(1,x)> = "); cres.print();
printf("constraint was:\n");
dump_r1cs_constraint(constraints[c], full_variable_assignment, variable_annotations);
#endif // DEBUG
return false;
}
}
return true;
}
template<typename FieldT>
void r1cs_constraint_system<FieldT>::add_constraint(const r1cs_constraint<FieldT> &c)
{
constraints.emplace_back(c);
}
template<typename FieldT>
void r1cs_constraint_system<FieldT>::add_constraint(const r1cs_constraint<FieldT> &c, const std::string &annotation)
{
#ifdef DEBUG
constraint_annotations[constraints.size()] = annotation;
#endif
constraints.emplace_back(c);
}
template<typename FieldT>
void r1cs_constraint_system<FieldT>::swap_AB_if_beneficial()
{
enter_block("Call to r1cs_constraint_system::swap_AB_if_beneficial");
enter_block("Estimate densities");
bit_vector touched_by_A(this->num_variables() + 1, false), touched_by_B(this->num_variables() + 1, false);
for (size_t i = 0; i < this->constraints.size(); ++i)
{
for (size_t j = 0; j < this->constraints[i].a.terms.size(); ++j)
{
touched_by_A[this->constraints[i].a.terms[j].index] = true;
}
for (size_t j = 0; j < this->constraints[i].b.terms.size(); ++j)
{
touched_by_B[this->constraints[i].b.terms[j].index] = true;
}
}
size_t non_zero_A_count = 0, non_zero_B_count = 0;
for (size_t i = 0; i < this->num_variables() + 1; ++i)
{
non_zero_A_count += touched_by_A[i] ? 1 : 0;
non_zero_B_count += touched_by_B[i] ? 1 : 0;
}
if (!inhibit_profiling_info)
{
print_indent(); printf("* Non-zero A-count (estimate): %zu\n", non_zero_A_count);
print_indent(); printf("* Non-zero B-count (estimate): %zu\n", non_zero_B_count);
}
leave_block("Estimate densities");
if (non_zero_B_count > non_zero_A_count)
{
enter_block("Perform the swap");
for (size_t i = 0; i < this->constraints.size(); ++i)
{
std::swap(this->constraints[i].a, this->constraints[i].b);
}
leave_block("Perform the swap");
}
else
{
print_indent(); printf("Swap is not beneficial, not performing\n");
}
leave_block("Call to r1cs_constraint_system::swap_AB_if_beneficial");
}
template<typename FieldT>
bool r1cs_constraint_system<FieldT>::operator==(const r1cs_constraint_system<FieldT> &other) const
{
return (this->constraints == other.constraints &&
this->primary_input_size == other.primary_input_size &&
this->auxiliary_input_size == other.auxiliary_input_size);
}
template<typename FieldT>
std::ostream& operator<<(std::ostream &out, const r1cs_constraint_system<FieldT> &cs)
{
out << cs.primary_input_size << "\n";
out << cs.auxiliary_input_size << "\n";
out << cs.num_constraints() << "\n";
for (const r1cs_constraint<FieldT>& c : cs.constraints)
{
out << c;
}
return out;
}
template<typename FieldT>
std::istream& operator>>(std::istream &in, r1cs_constraint_system<FieldT> &cs)
{
in >> cs.primary_input_size;
in >> cs.auxiliary_input_size;
cs.constraints.clear();
size_t s;
in >> s;
char b;
in.read(&b, 1);
cs.constraints.reserve(s);
for (size_t i = 0; i < s; ++i)
{
r1cs_constraint<FieldT> c;
in >> c;
cs.constraints.emplace_back(c);
}
return in;
}
template<typename FieldT>
void r1cs_constraint_system<FieldT>::report_linear_constraint_statistics() const
{
#ifdef DEBUG
for (size_t i = 0; i < constraints.size(); ++i)
{
auto &constr = constraints[i];
bool a_is_const = true;
for (auto &t : constr.a.terms)
{
a_is_const = a_is_const && (t.index == 0);
}
bool b_is_const = true;
for (auto &t : constr.b.terms)
{
b_is_const = b_is_const && (t.index == 0);
}
if (a_is_const || b_is_const)
{
auto it = constraint_annotations.find(i);
printf("%s\n", (it == constraint_annotations.end() ? FORMAT("", "constraint_%zu", i) : it->second).c_str());
}
}
#endif
}
} // libsnark
#endif // R1CS_TCC_

213
src/snark/libsnark/relations/variable.hpp

@ -1,213 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for:
- a variable (i.e., x_i),
- a linear term (i.e., a_i * x_i), and
- a linear combination (i.e., sum_i a_i * x_i).
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef VARIABLE_HPP_
#define VARIABLE_HPP_
#include <cstddef>
#include <map>
#include <string>
#include <vector>
namespace libsnark {
/**
* Mnemonic typedefs.
*/
typedef size_t var_index_t;
typedef int64_t integer_coeff_t;
/**
* Forward declaration.
*/
template<typename FieldT>
class linear_term;
/**
* Forward declaration.
*/
template<typename FieldT>
class linear_combination;
/********************************* Variable **********************************/
/**
* A variable represents a formal expresison of the form "x_{index}".
*/
template<typename FieldT>
class variable {
public:
var_index_t index;
variable(const var_index_t index = 0) : index(index) {};
linear_term<FieldT> operator*(const integer_coeff_t int_coeff) const;
linear_term<FieldT> operator*(const FieldT &field_coeff) const;
linear_combination<FieldT> operator+(const linear_combination<FieldT> &other) const;
linear_combination<FieldT> operator-(const linear_combination<FieldT> &other) const;
linear_term<FieldT> operator-() const;
bool operator==(const variable<FieldT> &other) const;
};
template<typename FieldT>
linear_term<FieldT> operator*(const integer_coeff_t int_coeff, const variable<FieldT> &var);
template<typename FieldT>
linear_term<FieldT> operator*(const FieldT &field_coeff, const variable<FieldT> &var);
template<typename FieldT>
linear_combination<FieldT> operator+(const integer_coeff_t int_coeff, const variable<FieldT> &var);
template<typename FieldT>
linear_combination<FieldT> operator+(const FieldT &field_coeff, const variable<FieldT> &var);
template<typename FieldT>
linear_combination<FieldT> operator-(const integer_coeff_t int_coeff, const variable<FieldT> &var);
template<typename FieldT>
linear_combination<FieldT> operator-(const FieldT &field_coeff, const variable<FieldT> &var);
/****************************** Linear term **********************************/
/**
* A linear term represents a formal expression of the form "coeff * x_{index}".
*/
template<typename FieldT>
class linear_term {
public:
var_index_t index = 0;
FieldT coeff;
linear_term() {};
linear_term(const variable<FieldT> &var);
linear_term(const variable<FieldT> &var, const integer_coeff_t int_coeff);
linear_term(const variable<FieldT> &var, const FieldT &field_coeff);
linear_term<FieldT> operator*(const integer_coeff_t int_coeff) const;
linear_term<FieldT> operator*(const FieldT &field_coeff) const;
linear_combination<FieldT> operator+(const linear_combination<FieldT> &other) const;
linear_combination<FieldT> operator-(const linear_combination<FieldT> &other) const;
linear_term<FieldT> operator-() const;
bool operator==(const linear_term<FieldT> &other) const;
};
template<typename FieldT>
linear_term<FieldT> operator*(const integer_coeff_t int_coeff, const linear_term<FieldT> &lt);
template<typename FieldT>
linear_term<FieldT> operator*(const FieldT &field_coeff, const linear_term<FieldT> &lt);
template<typename FieldT>
linear_combination<FieldT> operator+(const integer_coeff_t int_coeff, const linear_term<FieldT> &lt);
template<typename FieldT>
linear_combination<FieldT> operator+(const FieldT &field_coeff, const linear_term<FieldT> &lt);
template<typename FieldT>
linear_combination<FieldT> operator-(const integer_coeff_t int_coeff, const linear_term<FieldT> &lt);
template<typename FieldT>
linear_combination<FieldT> operator-(const FieldT &field_coeff, const linear_term<FieldT> &lt);
/***************************** Linear combination ****************************/
template<typename FieldT>
class linear_combination;
template<typename FieldT>
std::ostream& operator<<(std::ostream &out, const linear_combination<FieldT> &lc);
template<typename FieldT>
std::istream& operator>>(std::istream &in, linear_combination<FieldT> &lc);
/**
* A linear combination represents a formal expression of the form "sum_i coeff_i * x_{index_i}".
*/
template<typename FieldT>
class linear_combination {
public:
std::vector<linear_term<FieldT> > terms;
linear_combination() {};
linear_combination(const integer_coeff_t int_coeff);
linear_combination(const FieldT &field_coeff);
linear_combination(const variable<FieldT> &var);
linear_combination(const linear_term<FieldT> &lt);
linear_combination(const std::vector<linear_term<FieldT> > &all_terms);
/* for supporting range-based for loops over linear_combination */
typename std::vector<linear_term<FieldT> >::const_iterator begin() const;
typename std::vector<linear_term<FieldT> >::const_iterator end() const;
void add_term(const variable<FieldT> &var);
void add_term(const variable<FieldT> &var, const integer_coeff_t int_coeff);
void add_term(const variable<FieldT> &var, const FieldT &field_coeff);
void add_term(const linear_term<FieldT> &lt);
FieldT evaluate(const std::vector<FieldT> &assignment) const;
linear_combination<FieldT> operator*(const integer_coeff_t int_coeff) const;
linear_combination<FieldT> operator*(const FieldT &field_coeff) const;
linear_combination<FieldT> operator+(const linear_combination<FieldT> &other) const;
linear_combination<FieldT> operator-(const linear_combination<FieldT> &other) const;
linear_combination<FieldT> operator-() const;
bool operator==(const linear_combination<FieldT> &other) const;
bool is_valid(const size_t num_variables) const;
void print(const std::map<size_t, std::string> &variable_annotations = std::map<size_t, std::string>()) const;
void print_with_assignment(const std::vector<FieldT> &full_assignment, const std::map<size_t, std::string> &variable_annotations = std::map<size_t, std::string>()) const;
friend std::ostream& operator<< <FieldT>(std::ostream &out, const linear_combination<FieldT> &lc);
friend std::istream& operator>> <FieldT>(std::istream &in, linear_combination<FieldT> &lc);
};
template<typename FieldT>
linear_combination<FieldT> operator*(const integer_coeff_t int_coeff, const linear_combination<FieldT> &lc);
template<typename FieldT>
linear_combination<FieldT> operator*(const FieldT &field_coeff, const linear_combination<FieldT> &lc);
template<typename FieldT>
linear_combination<FieldT> operator+(const integer_coeff_t int_coeff, const linear_combination<FieldT> &lc);
template<typename FieldT>
linear_combination<FieldT> operator+(const FieldT &field_coeff, const linear_combination<FieldT> &lc);
template<typename FieldT>
linear_combination<FieldT> operator-(const integer_coeff_t int_coeff, const linear_combination<FieldT> &lc);
template<typename FieldT>
linear_combination<FieldT> operator-(const FieldT &field_coeff, const linear_combination<FieldT> &lc);
} // libsnark
#include "relations/variable.tcc"
#endif // VARIABLE_HPP_

512
src/snark/libsnark/relations/variable.tcc

@ -1,512 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for:
- a variable (i.e., x_i),
- a linear term (i.e., a_i * x_i), and
- a linear combination (i.e., sum_i a_i * x_i).
See variabe.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef VARIABLE_TCC_
#define VARIABLE_TCC_
#include <algorithm>
#include <cassert>
#include "algebra/fields/bigint.hpp"
namespace libsnark {
template<typename FieldT>
linear_term<FieldT> variable<FieldT>::operator*(const integer_coeff_t int_coeff) const
{
return linear_term<FieldT>(*this, int_coeff);
}
template<typename FieldT>
linear_term<FieldT> variable<FieldT>::operator*(const FieldT &field_coeff) const
{
return linear_term<FieldT>(*this, field_coeff);
}
template<typename FieldT>
linear_combination<FieldT> variable<FieldT>::operator+(const linear_combination<FieldT> &other) const
{
linear_combination<FieldT> result;
result.add_term(*this);
result.terms.insert(result.terms.begin(), other.terms.begin(), other.terms.end());
return result;
}
template<typename FieldT>
linear_combination<FieldT> variable<FieldT>::operator-(const linear_combination<FieldT> &other) const
{
return (*this) + (-other);
}
template<typename FieldT>
linear_term<FieldT> variable<FieldT>::operator-() const
{
return linear_term<FieldT>(*this, -FieldT::one());
}
template<typename FieldT>
bool variable<FieldT>::operator==(const variable<FieldT> &other) const
{
return (this->index == other.index);
}
template<typename FieldT>
linear_term<FieldT> operator*(const integer_coeff_t int_coeff, const variable<FieldT> &var)
{
return linear_term<FieldT>(var, int_coeff);
}
template<typename FieldT>
linear_term<FieldT> operator*(const FieldT &field_coeff, const variable<FieldT> &var)
{
return linear_term<FieldT>(var, field_coeff);
}
template<typename FieldT>
linear_combination<FieldT> operator+(const integer_coeff_t int_coeff, const variable<FieldT> &var)
{
return linear_combination<FieldT>(int_coeff) + var;
}
template<typename FieldT>
linear_combination<FieldT> operator+(const FieldT &field_coeff, const variable<FieldT> &var)
{
return linear_combination<FieldT>(field_coeff) + var;
}
template<typename FieldT>
linear_combination<FieldT> operator-(const integer_coeff_t int_coeff, const variable<FieldT> &var)
{
return linear_combination<FieldT>(int_coeff) - var;
}
template<typename FieldT>
linear_combination<FieldT> operator-(const FieldT &field_coeff, const variable<FieldT> &var)
{
return linear_combination<FieldT>(field_coeff) - var;
}
template<typename FieldT>
linear_term<FieldT>::linear_term(const variable<FieldT> &var) :
index(var.index), coeff(FieldT::one())
{
}
template<typename FieldT>
linear_term<FieldT>::linear_term(const variable<FieldT> &var, const integer_coeff_t int_coeff) :
index(var.index), coeff(FieldT(int_coeff))
{
}
template<typename FieldT>
linear_term<FieldT>::linear_term(const variable<FieldT> &var, const FieldT &coeff) :
index(var.index), coeff(coeff)
{
}
template<typename FieldT>
linear_term<FieldT> linear_term<FieldT>::operator*(const integer_coeff_t int_coeff) const
{
return (this->operator*(FieldT(int_coeff)));
}
template<typename FieldT>
linear_term<FieldT> linear_term<FieldT>::operator*(const FieldT &field_coeff) const
{
return linear_term<FieldT>(this->index, field_coeff * this->coeff);
}
template<typename FieldT>
linear_combination<FieldT> operator+(const integer_coeff_t int_coeff, const linear_term<FieldT> &lt)
{
return linear_combination<FieldT>(int_coeff) + lt;
}
template<typename FieldT>
linear_combination<FieldT> operator+(const FieldT &field_coeff, const linear_term<FieldT> &lt)
{
return linear_combination<FieldT>(field_coeff) + lt;
}
template<typename FieldT>
linear_combination<FieldT> operator-(const integer_coeff_t int_coeff, const linear_term<FieldT> &lt)
{
return linear_combination<FieldT>(int_coeff) - lt;
}
template<typename FieldT>
linear_combination<FieldT> operator-(const FieldT &field_coeff, const linear_term<FieldT> &lt)
{
return linear_combination<FieldT>(field_coeff) - lt;
}
template<typename FieldT>
linear_combination<FieldT> linear_term<FieldT>::operator+(const linear_combination<FieldT> &other) const
{
return linear_combination<FieldT>(*this) + other;
}
template<typename FieldT>
linear_combination<FieldT> linear_term<FieldT>::operator-(const linear_combination<FieldT> &other) const
{
return (*this) + (-other);
}
template<typename FieldT>
linear_term<FieldT> linear_term<FieldT>::operator-() const
{
return linear_term<FieldT>(this->index, -this->coeff);
}
template<typename FieldT>
bool linear_term<FieldT>::operator==(const linear_term<FieldT> &other) const
{
return (this->index == other.index &&
this->coeff == other.coeff);
}
template<typename FieldT>
linear_term<FieldT> operator*(const integer_coeff_t int_coeff, const linear_term<FieldT> &lt)
{
return FieldT(int_coeff) * lt;
}
template<typename FieldT>
linear_term<FieldT> operator*(const FieldT &field_coeff, const linear_term<FieldT> &lt)
{
return linear_term<FieldT>(lt.index, field_coeff * lt.coeff);
}
template<typename FieldT>
linear_combination<FieldT>::linear_combination(const integer_coeff_t int_coeff)
{
this->add_term(linear_term<FieldT>(0, int_coeff));
}
template<typename FieldT>
linear_combination<FieldT>::linear_combination(const FieldT &field_coeff)
{
this->add_term(linear_term<FieldT>(0, field_coeff));
}
template<typename FieldT>
linear_combination<FieldT>::linear_combination(const variable<FieldT> &var)
{
this->add_term(var);
}
template<typename FieldT>
linear_combination<FieldT>::linear_combination(const linear_term<FieldT> &lt)
{
this->add_term(lt);
}
template<typename FieldT>
typename std::vector<linear_term<FieldT> >::const_iterator linear_combination<FieldT>::begin() const
{
return terms.begin();
}
template<typename FieldT>
typename std::vector<linear_term<FieldT> >::const_iterator linear_combination<FieldT>::end() const
{
return terms.end();
}
template<typename FieldT>
void linear_combination<FieldT>::add_term(const variable<FieldT> &var)
{
this->terms.emplace_back(linear_term<FieldT>(var.index, FieldT::one()));
}
template<typename FieldT>
void linear_combination<FieldT>::add_term(const variable<FieldT> &var, const integer_coeff_t int_coeff)
{
this->terms.emplace_back(linear_term<FieldT>(var.index, int_coeff));
}
template<typename FieldT>
void linear_combination<FieldT>::add_term(const variable<FieldT> &var, const FieldT &coeff)
{
this->terms.emplace_back(linear_term<FieldT>(var.index, coeff));
}
template<typename FieldT>
void linear_combination<FieldT>::add_term(const linear_term<FieldT> &other)
{
this->terms.emplace_back(other);
}
template<typename FieldT>
linear_combination<FieldT> linear_combination<FieldT>::operator*(const integer_coeff_t int_coeff) const
{
return (*this) * FieldT(int_coeff);
}
template<typename FieldT>
FieldT linear_combination<FieldT>::evaluate(const std::vector<FieldT> &assignment) const
{
FieldT acc = FieldT::zero();
for (auto &lt : terms)
{
acc += (lt.index == 0 ? FieldT::one() : assignment[lt.index-1]) * lt.coeff;
}
return acc;
}
template<typename FieldT>
linear_combination<FieldT> linear_combination<FieldT>::operator*(const FieldT &field_coeff) const
{
linear_combination<FieldT> result;
result.terms.reserve(this->terms.size());
for (const linear_term<FieldT> &lt : this->terms)
{
result.terms.emplace_back(lt * field_coeff);
}
return result;
}
template<typename FieldT>
linear_combination<FieldT> linear_combination<FieldT>::operator+(const linear_combination<FieldT> &other) const
{
linear_combination<FieldT> result;
auto it1 = this->terms.begin();
auto it2 = other.terms.begin();
/* invariant: it1 and it2 always point to unprocessed items in the corresponding linear combinations */
while (it1 != this->terms.end() && it2 != other.terms.end())
{
if (it1->index < it2->index)
{
result.terms.emplace_back(*it1);
++it1;
}
else if (it1->index > it2->index)
{
result.terms.emplace_back(*it2);
++it2;
}
else
{
/* it1->index == it2->index */
result.terms.emplace_back(linear_term<FieldT>(variable<FieldT>(it1->index), it1->coeff + it2->coeff));
++it1;
++it2;
}
}
if (it1 != this->terms.end())
{
result.terms.insert(result.terms.end(), it1, this->terms.end());
}
else
{
result.terms.insert(result.terms.end(), it2, other.terms.end());
}
return result;
}
template<typename FieldT>
linear_combination<FieldT> linear_combination<FieldT>::operator-(const linear_combination<FieldT> &other) const
{
return (*this) + (-other);
}
template<typename FieldT>
linear_combination<FieldT> linear_combination<FieldT>::operator-() const
{
return (*this) * (-FieldT::one());
}
template<typename FieldT>
bool linear_combination<FieldT>::operator==(const linear_combination<FieldT> &other) const
{
return (this->terms == other.terms);
}
template<typename FieldT>
bool linear_combination<FieldT>::is_valid(const size_t num_variables) const
{
/* check that all terms in linear combination are sorted */
for (size_t i = 1; i < terms.size(); ++i)
{
if (terms[i-1].index >= terms[i].index)
{
return false;
}
}
/* check that the variables are in proper range. as the variables
are sorted, it suffices to check the last term */
if ((--terms.end())->index >= num_variables)
{
return false;
}
return true;
}
template<typename FieldT>
void linear_combination<FieldT>::print(const std::map<size_t, std::string> &variable_annotations) const
{
for (auto &lt : terms)
{
if (lt.index == 0)
{
printf(" 1 * ");
lt.coeff.print();
}
else
{
auto it = variable_annotations.find(lt.index);
printf(" x_%zu (%s) * ", lt.index, (it == variable_annotations.end() ? "no annotation" : it->second.c_str()));
lt.coeff.print();
}
}
}
template<typename FieldT>
void linear_combination<FieldT>::print_with_assignment(const std::vector<FieldT> &full_assignment, const std::map<size_t, std::string> &variable_annotations) const
{
for (auto &lt : terms)
{
if (lt.index == 0)
{
printf(" 1 * ");
lt.coeff.print();
}
else
{
printf(" x_%zu * ", lt.index);
lt.coeff.print();
auto it = variable_annotations.find(lt.index);
printf(" where x_%zu (%s) was assigned value ", lt.index,
(it == variable_annotations.end() ? "no annotation" : it->second.c_str()));
full_assignment[lt.index-1].print();
printf(" i.e. negative of ");
(-full_assignment[lt.index-1]).print();
}
}
}
template<typename FieldT>
std::ostream& operator<<(std::ostream &out, const linear_combination<FieldT> &lc)
{
out << lc.terms.size() << "\n";
for (const linear_term<FieldT>& lt : lc.terms)
{
out << lt.index << "\n";
out << lt.coeff << OUTPUT_NEWLINE;
}
return out;
}
template<typename FieldT>
std::istream& operator>>(std::istream &in, linear_combination<FieldT> &lc)
{
lc.terms.clear();
size_t s;
in >> s;
consume_newline(in);
lc.terms.reserve(s);
for (size_t i = 0; i < s; ++i)
{
linear_term<FieldT> lt;
in >> lt.index;
consume_newline(in);
in >> lt.coeff;
consume_OUTPUT_NEWLINE(in);
lc.terms.emplace_back(lt);
}
return in;
}
template<typename FieldT>
linear_combination<FieldT> operator*(const integer_coeff_t int_coeff, const linear_combination<FieldT> &lc)
{
return lc * int_coeff;
}
template<typename FieldT>
linear_combination<FieldT> operator*(const FieldT &field_coeff, const linear_combination<FieldT> &lc)
{
return lc * field_coeff;
}
template<typename FieldT>
linear_combination<FieldT> operator+(const integer_coeff_t int_coeff, const linear_combination<FieldT> &lc)
{
return linear_combination<FieldT>(int_coeff) + lc;
}
template<typename FieldT>
linear_combination<FieldT> operator+(const FieldT &field_coeff, const linear_combination<FieldT> &lc)
{
return linear_combination<FieldT>(field_coeff) + lc;
}
template<typename FieldT>
linear_combination<FieldT> operator-(const integer_coeff_t int_coeff, const linear_combination<FieldT> &lc)
{
return linear_combination<FieldT>(int_coeff) - lc;
}
template<typename FieldT>
linear_combination<FieldT> operator-(const FieldT &field_coeff, const linear_combination<FieldT> &lc)
{
return linear_combination<FieldT>(field_coeff) - lc;
}
template<typename FieldT>
linear_combination<FieldT>::linear_combination(const std::vector<linear_term<FieldT> > &all_terms)
{
if (all_terms.empty())
{
return;
}
terms = all_terms;
std::sort(terms.begin(), terms.end(), [](linear_term<FieldT> a, linear_term<FieldT> b) { return a.index < b.index; });
auto result_it = terms.begin();
for (auto it = ++terms.begin(); it != terms.end(); ++it)
{
if (it->index == result_it->index)
{
result_it->coeff += it->coeff;
}
else
{
*(++result_it) = *it;
}
}
terms.resize((result_it - terms.begin()) + 1);
}
} // libsnark
#endif // VARIABLE_TCC

35
src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp

@ -1,35 +0,0 @@
/** @file
*****************************************************************************
Declaration of functionality that runs the R1CS ppzkSNARK for
a given R1CS example.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef RUN_R1CS_PPZKSNARK_HPP_
#define RUN_R1CS_PPZKSNARK_HPP_
#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp"
namespace libsnark {
/**
* Runs the ppzkSNARK (generator, prover, and verifier) for a given
* R1CS example (specified by a constraint system, input, and witness).
*
* Optionally, also test the serialization routines for keys and proofs.
* (This takes additional time.)
*/
template<typename ppT>
bool run_r1cs_ppzksnark(const r1cs_example<Fr<ppT> > &example,
const bool test_serialization);
} // libsnark
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc"
#endif // RUN_R1CS_PPZKSNARK_HPP_

114
src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc

@ -1,114 +0,0 @@
/** @file
*****************************************************************************
Implementation of functionality that runs the R1CS ppzkSNARK for
a given R1CS example.
See run_r1cs_ppzksnark.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef RUN_R1CS_PPZKSNARK_TCC_
#define RUN_R1CS_PPZKSNARK_TCC_
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
#include <sstream>
#include <type_traits>
#include "common/profiling.hpp"
namespace libsnark {
template<typename ppT>
typename std::enable_if<ppT::has_affine_pairing, void>::type
test_affine_verifier(const r1cs_ppzksnark_verification_key<ppT> &vk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_proof<ppT> &proof,
const bool expected_answer)
{
print_header("R1CS ppzkSNARK Affine Verifier");
const bool answer = r1cs_ppzksnark_affine_verifier_weak_IC<ppT>(vk, primary_input, proof);
assert(answer == expected_answer);
}
template<typename ppT>
typename std::enable_if<!ppT::has_affine_pairing, void>::type
test_affine_verifier(const r1cs_ppzksnark_verification_key<ppT> &vk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_proof<ppT> &proof,
const bool expected_answer)
{
UNUSED(vk, primary_input, proof, expected_answer);
print_header("R1CS ppzkSNARK Affine Verifier");
printf("Affine verifier is not supported; not testing anything.\n");
}
/**
* The code below provides an example of all stages of running a R1CS ppzkSNARK.
*
* Of course, in a real-life scenario, we would have three distinct entities,
* mangled into one in the demonstration below. The three entities are as follows.
* (1) The "generator", which runs the ppzkSNARK generator on input a given
* constraint system CS to create a proving and a verification key for CS.
* (2) The "prover", which runs the ppzkSNARK prover on input the proving key,
* a primary input for CS, and an auxiliary input for CS.
* (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key,
* a primary input for CS, and a proof.
*/
template<typename ppT>
bool run_r1cs_ppzksnark(const r1cs_example<Fr<ppT> > &example,
const bool test_serialization)
{
enter_block("Call to run_r1cs_ppzksnark");
print_header("R1CS ppzkSNARK Generator");
r1cs_ppzksnark_keypair<ppT> keypair = r1cs_ppzksnark_generator<ppT>(example.constraint_system);
printf("\n"); print_indent(); print_mem("after generator");
print_header("Preprocess verification key");
r1cs_ppzksnark_processed_verification_key<ppT> pvk = r1cs_ppzksnark_verifier_process_vk<ppT>(keypair.vk);
if (test_serialization)
{
enter_block("Test serialization of keys");
keypair.pk = reserialize<r1cs_ppzksnark_proving_key<ppT> >(keypair.pk);
keypair.vk = reserialize<r1cs_ppzksnark_verification_key<ppT> >(keypair.vk);
pvk = reserialize<r1cs_ppzksnark_processed_verification_key<ppT> >(pvk);
leave_block("Test serialization of keys");
}
print_header("R1CS ppzkSNARK Prover");
r1cs_ppzksnark_proof<ppT> proof = r1cs_ppzksnark_prover<ppT>(keypair.pk, example.primary_input, example.auxiliary_input);
printf("\n"); print_indent(); print_mem("after prover");
if (test_serialization)
{
enter_block("Test serialization of proof");
proof = reserialize<r1cs_ppzksnark_proof<ppT> >(proof);
leave_block("Test serialization of proof");
}
print_header("R1CS ppzkSNARK Verifier");
const bool ans = r1cs_ppzksnark_verifier_strong_IC<ppT>(keypair.vk, example.primary_input, proof);
printf("\n"); print_indent(); print_mem("after verifier");
printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL"));
print_header("R1CS ppzkSNARK Online Verifier");
const bool ans2 = r1cs_ppzksnark_online_verifier_strong_IC<ppT>(pvk, example.primary_input, proof);
assert(ans == ans2);
test_affine_verifier<ppT>(keypair.vk, example.primary_input, proof, ans);
leave_block("Call to run_r1cs_ppzksnark");
return ans;
}
} // libsnark
#endif // RUN_R1CS_PPZKSNARK_TCC_

71
src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp

@ -1,71 +0,0 @@
/** @file
*****************************************************************************
Profiling program that exercises the ppzkSNARK (first generator, then prover,
then verifier) on a synthetic R1CS instance.
The command
$ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 Fr
exercises the ppzkSNARK (first generator, then prover, then verifier) on an R1CS instance with 1000 equations and an input consisting of 10 field elements.
(If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).)
The command
$ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 bytes
does the same but now the input consists of 10 bytes.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include <cassert>
#include <cstdio>
#include "common/default_types/r1cs_ppzksnark_pp.hpp"
#include "common/profiling.hpp"
#include "common/utils.hpp"
#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp"
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp"
using namespace libsnark;
int main(int argc, const char * argv[])
{
default_r1cs_ppzksnark_pp::init_public_params();
start_profiling();
if (argc == 2 && strcmp(argv[1], "-v") == 0)
{
print_compilation_info();
return 0;
}
if (argc != 3 && argc != 4)
{
printf("usage: %s num_constraints input_size [Fr|bytes]\n", argv[0]);
return 1;
}
const int num_constraints = atoi(argv[1]);
int input_size = atoi(argv[2]);
if (argc == 4)
{
assert(strcmp(argv[3], "Fr") == 0 || strcmp(argv[3], "bytes") == 0);
if (strcmp(argv[3], "bytes") == 0)
{
input_size = div_ceil(8 * input_size, Fr<default_ec_pp>::capacity());
}
}
enter_block("Generate R1CS example");
r1cs_example<Fr<default_r1cs_ppzksnark_pp> > example = generate_r1cs_example_with_field_input<Fr<default_r1cs_ppzksnark_pp> >(num_constraints, input_size);
leave_block("Generate R1CS example");
print_header("(enter) Profile R1CS ppzkSNARK");
const bool test_serialization = true;
run_r1cs_ppzksnark<default_r1cs_ppzksnark_pp>(example, test_serialization);
print_header("(leave) Profile R1CS ppzkSNARK");
}

485
src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp

@ -1,485 +0,0 @@
/** @file
*****************************************************************************
Declaration of interfaces for a ppzkSNARK for R1CS.
This includes:
- class for proving key
- class for verification key
- class for processed verification key
- class for key pair (proving key & verification key)
- class for proof
- generator algorithm
- prover algorithm
- verifier algorithm (with strong or weak input consistency)
- online verifier algorithm (with strong or weak input consistency)
The implementation instantiates (a modification of) the protocol of \[PGHR13],
by following extending, and optimizing the approach described in \[BCTV14].
Acronyms:
- R1CS = "Rank-1 Constraint Systems"
- ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge"
References:
\[BCTV14]:
"Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture",
Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza,
USENIX Security 2014,
<http://eprint.iacr.org/2013/879>
\[PGHR13]:
"Pinocchio: Nearly practical verifiable computation",
Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova,
IEEE S&P 2013,
<https://eprint.iacr.org/2013/279>
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef R1CS_PPZKSNARK_HPP_
#define R1CS_PPZKSNARK_HPP_
#include <memory>
#include "algebra/curves/public_params.hpp"
#include "common/data_structures/accumulation_vector.hpp"
#include "algebra/knowledge_commitment/knowledge_commitment.hpp"
#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp"
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp"
namespace libsnark {
/******************************** Proving key ********************************/
template<typename ppT>
class r1cs_ppzksnark_proving_key;
template<typename ppT>
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key<ppT> &pk);
template<typename ppT>
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key<ppT> &pk);
/**
* A proving key for the R1CS ppzkSNARK.
*/
template<typename ppT>
class r1cs_ppzksnark_proving_key {
public:
knowledge_commitment_vector<G1<ppT>, G1<ppT> > A_query;
knowledge_commitment_vector<G2<ppT>, G1<ppT> > B_query;
knowledge_commitment_vector<G1<ppT>, G1<ppT> > C_query;
G1_vector<ppT> H_query;
G1_vector<ppT> K_query;
r1cs_ppzksnark_proving_key() {};
r1cs_ppzksnark_proving_key<ppT>& operator=(const r1cs_ppzksnark_proving_key<ppT> &other) = default;
r1cs_ppzksnark_proving_key(const r1cs_ppzksnark_proving_key<ppT> &other) = default;
r1cs_ppzksnark_proving_key(r1cs_ppzksnark_proving_key<ppT> &&other) = default;
r1cs_ppzksnark_proving_key(knowledge_commitment_vector<G1<ppT>, G1<ppT> > &&A_query,
knowledge_commitment_vector<G2<ppT>, G1<ppT> > &&B_query,
knowledge_commitment_vector<G1<ppT>, G1<ppT> > &&C_query,
G1_vector<ppT> &&H_query,
G1_vector<ppT> &&K_query) :
A_query(std::move(A_query)),
B_query(std::move(B_query)),
C_query(std::move(C_query)),
H_query(std::move(H_query)),
K_query(std::move(K_query))
{};
size_t G1_size() const
{
return 2*(A_query.domain_size() + C_query.domain_size()) + B_query.domain_size() + H_query.size() + K_query.size();
}
size_t G2_size() const
{
return B_query.domain_size();
}
size_t G1_sparse_size() const
{
return 2*(A_query.size() + C_query.size()) + B_query.size() + H_query.size() + K_query.size();
}
size_t G2_sparse_size() const
{
return B_query.size();
}
size_t size_in_bits() const
{
return A_query.size_in_bits() + B_query.size_in_bits() + C_query.size_in_bits() + libsnark::size_in_bits(H_query) + libsnark::size_in_bits(K_query);
}
void print_size() const
{
print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size());
print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size());
print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size());
print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size());
print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits());
}
bool operator==(const r1cs_ppzksnark_proving_key<ppT> &other) const;
friend std::ostream& operator<< <ppT>(std::ostream &out, const r1cs_ppzksnark_proving_key<ppT> &pk);
friend std::istream& operator>> <ppT>(std::istream &in, r1cs_ppzksnark_proving_key<ppT> &pk);
};
/******************************* Verification key ****************************/
template<typename ppT>
class r1cs_ppzksnark_verification_key;
template<typename ppT>
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key<ppT> &vk);
template<typename ppT>
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key<ppT> &vk);
/**
* A verification key for the R1CS ppzkSNARK.
*/
template<typename ppT>
class r1cs_ppzksnark_verification_key {
public:
G2<ppT> alphaA_g2;
G1<ppT> alphaB_g1;
G2<ppT> alphaC_g2;
G2<ppT> gamma_g2;
G1<ppT> gamma_beta_g1;
G2<ppT> gamma_beta_g2;
G2<ppT> rC_Z_g2;
accumulation_vector<G1<ppT> > encoded_IC_query;
r1cs_ppzksnark_verification_key() = default;
r1cs_ppzksnark_verification_key(const G2<ppT> &alphaA_g2,
const G1<ppT> &alphaB_g1,
const G2<ppT> &alphaC_g2,
const G2<ppT> &gamma_g2,
const G1<ppT> &gamma_beta_g1,
const G2<ppT> &gamma_beta_g2,
const G2<ppT> &rC_Z_g2,
const accumulation_vector<G1<ppT> > &eIC) :
alphaA_g2(alphaA_g2),
alphaB_g1(alphaB_g1),
alphaC_g2(alphaC_g2),
gamma_g2(gamma_g2),
gamma_beta_g1(gamma_beta_g1),
gamma_beta_g2(gamma_beta_g2),
rC_Z_g2(rC_Z_g2),
encoded_IC_query(eIC)
{};
size_t G1_size() const
{
return 2 + encoded_IC_query.size();
}
size_t G2_size() const
{
return 5;
}
size_t size_in_bits() const
{
return (2 * G1<ppT>::size_in_bits() + encoded_IC_query.size_in_bits() + 5 * G2<ppT>::size_in_bits());
}
void print_size() const
{
print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size());
print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size());
print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits());
}
bool operator==(const r1cs_ppzksnark_verification_key<ppT> &other) const;
friend std::ostream& operator<< <ppT>(std::ostream &out, const r1cs_ppzksnark_verification_key<ppT> &vk);
friend std::istream& operator>> <ppT>(std::istream &in, r1cs_ppzksnark_verification_key<ppT> &vk);
static r1cs_ppzksnark_verification_key<ppT> dummy_verification_key(const size_t input_size);
};
/************************ Processed verification key *************************/
template<typename ppT>
class r1cs_ppzksnark_processed_verification_key;
template<typename ppT>
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key<ppT> &pvk);
template<typename ppT>
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key<ppT> &pvk);
/**
* A processed verification key for the R1CS ppzkSNARK.
*
* Compared to a (non-processed) verification key, a processed verification key
* contains a small constant amount of additional pre-computed information that
* enables a faster verification time.
*/
template<typename ppT>
class r1cs_ppzksnark_processed_verification_key {
public:
G2_precomp<ppT> pp_G2_one_precomp;
G2_precomp<ppT> vk_alphaA_g2_precomp;
G1_precomp<ppT> vk_alphaB_g1_precomp;
G2_precomp<ppT> vk_alphaC_g2_precomp;
G2_precomp<ppT> vk_rC_Z_g2_precomp;
G2_precomp<ppT> vk_gamma_g2_precomp;
G1_precomp<ppT> vk_gamma_beta_g1_precomp;
G2_precomp<ppT> vk_gamma_beta_g2_precomp;
accumulation_vector<G1<ppT> > encoded_IC_query;
bool operator==(const r1cs_ppzksnark_processed_verification_key &other) const;
friend std::ostream& operator<< <ppT>(std::ostream &out, const r1cs_ppzksnark_processed_verification_key<ppT> &pvk);
friend std::istream& operator>> <ppT>(std::istream &in, r1cs_ppzksnark_processed_verification_key<ppT> &pvk);
};
/********************************** Key pair *********************************/
/**
* A key pair for the R1CS ppzkSNARK, which consists of a proving key and a verification key.
*/
template<typename ppT>
class r1cs_ppzksnark_keypair {
public:
r1cs_ppzksnark_proving_key<ppT> pk;
r1cs_ppzksnark_verification_key<ppT> vk;
r1cs_ppzksnark_keypair() = default;
r1cs_ppzksnark_keypair(const r1cs_ppzksnark_keypair<ppT> &other) = default;
r1cs_ppzksnark_keypair(r1cs_ppzksnark_proving_key<ppT> &&pk,
r1cs_ppzksnark_verification_key<ppT> &&vk) :
pk(std::move(pk)),
vk(std::move(vk))
{}
r1cs_ppzksnark_keypair(r1cs_ppzksnark_keypair<ppT> &&other) = default;
};
/*********************************** Proof ***********************************/
template<typename ppT>
class r1cs_ppzksnark_proof;
template<typename ppT>
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof<ppT> &proof);
template<typename ppT>
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof<ppT> &proof);
/**
* A proof for the R1CS ppzkSNARK.
*
* While the proof has a structure, externally one merely opaquely produces,
* seralizes/deserializes, and verifies proofs. We only expose some information
* about the structure for statistics purposes.
*/
template<typename ppT>
class r1cs_ppzksnark_proof {
public:
knowledge_commitment<G1<ppT>, G1<ppT> > g_A;
knowledge_commitment<G2<ppT>, G1<ppT> > g_B;
knowledge_commitment<G1<ppT>, G1<ppT> > g_C;
G1<ppT> g_H;
G1<ppT> g_K;
r1cs_ppzksnark_proof()
{
// invalid proof with valid curve points
this->g_A.g = G1<ppT> ::one();
this->g_A.h = G1<ppT>::one();
this->g_B.g = G2<ppT> ::one();
this->g_B.h = G1<ppT>::one();
this->g_C.g = G1<ppT> ::one();
this->g_C.h = G1<ppT>::one();
this->g_H = G1<ppT>::one();
this->g_K = G1<ppT>::one();
}
r1cs_ppzksnark_proof(knowledge_commitment<G1<ppT>, G1<ppT> > &&g_A,
knowledge_commitment<G2<ppT>, G1<ppT> > &&g_B,
knowledge_commitment<G1<ppT>, G1<ppT> > &&g_C,
G1<ppT> &&g_H,
G1<ppT> &&g_K) :
g_A(std::move(g_A)),
g_B(std::move(g_B)),
g_C(std::move(g_C)),
g_H(std::move(g_H)),
g_K(std::move(g_K))
{};
size_t G1_size() const
{
return 7;
}
size_t G2_size() const
{
return 1;
}
size_t size_in_bits() const
{
return G1_size() * G1<ppT>::size_in_bits() + G2_size() * G2<ppT>::size_in_bits();
}
void print_size() const
{
print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size());
print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size());
print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits());
}
bool is_well_formed() const
{
return (g_A.g.is_well_formed() && g_A.h.is_well_formed() &&
g_B.g.is_well_formed() && g_B.h.is_well_formed() &&
g_C.g.is_well_formed() && g_C.h.is_well_formed() &&
g_H.is_well_formed() &&
g_K.is_well_formed());
}
bool operator==(const r1cs_ppzksnark_proof<ppT> &other) const;
friend std::ostream& operator<< <ppT>(std::ostream &out, const r1cs_ppzksnark_proof<ppT> &proof);
friend std::istream& operator>> <ppT>(std::istream &in, r1cs_ppzksnark_proof<ppT> &proof);
};
/***************************** Main algorithms *******************************/
/**
* A generator algorithm for the R1CS ppzkSNARK.
*
* Given a R1CS constraint system CS, this algorithm produces proving and verification keys for CS.
*/
template<typename ppT>
r1cs_ppzksnark_keypair<ppT> r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system<ppT> &cs);
template<typename ppT>
r1cs_ppzksnark_keypair<ppT> r1cs_ppzksnark_generator(
const r1cs_ppzksnark_constraint_system<ppT> &cs,
const Fr<ppT>& t,
const Fr<ppT>& alphaA,
const Fr<ppT>& alphaB,
const Fr<ppT>& alphaC,
const Fr<ppT>& rA,
const Fr<ppT>& rB,
const Fr<ppT>& beta,
const Fr<ppT>& gamma
);
/**
* A prover algorithm for the R1CS ppzkSNARK.
*
* Given a R1CS primary input X and a R1CS auxiliary input Y, this algorithm
* produces a proof (of knowledge) that attests to the following statement:
* ``there exists Y such that CS(X,Y)=0''.
* Above, CS is the R1CS constraint system that was given as input to the generator algorithm.
*/
template<typename ppT>
r1cs_ppzksnark_proof<ppT> r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key<ppT> &pk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_auxiliary_input<ppT> &auxiliary_input);
template<typename ppT>
r1cs_ppzksnark_proof<ppT> r1cs_ppzksnark_prover_streaming(std::ifstream &proving_key_file,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_auxiliary_input<ppT> &auxiliary_input,
const r1cs_ppzksnark_constraint_system<ppT> &constraint_system);
/*
Below are four variants of verifier algorithm for the R1CS ppzkSNARK.
These are the four cases that arise from the following two choices:
(1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key.
In the latter case, we call the algorithm an "online verifier".
(2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency.
Strong input consistency requires that |primary_input| = CS.num_inputs, whereas
weak input consistency requires that |primary_input| <= CS.num_inputs (and
the primary input is implicitly padded with zeros up to length CS.num_inputs).
*/
/**
* A verifier algorithm for the R1CS ppzkSNARK that:
* (1) accepts a non-processed verification key, and
* (2) has weak input consistency.
*/
template<typename ppT>
bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_proof<ppT> &proof);
/**
* A verifier algorithm for the R1CS ppzkSNARK that:
* (1) accepts a non-processed verification key, and
* (2) has strong input consistency.
*/
template<typename ppT>
bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_proof<ppT> &proof);
/**
* Convert a (non-processed) verification key into a processed verification key.
*/
template<typename ppT>
r1cs_ppzksnark_processed_verification_key<ppT> r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key<ppT> &vk);
/**
* A verifier algorithm for the R1CS ppzkSNARK that:
* (1) accepts a processed verification key, and
* (2) has weak input consistency.
*/
template<typename ppT>
bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key<ppT> &pvk,
const r1cs_ppzksnark_primary_input<ppT> &input,
const r1cs_ppzksnark_proof<ppT> &proof);
/**
* A verifier algorithm for the R1CS ppzkSNARK that:
* (1) accepts a processed verification key, and
* (2) has strong input consistency.
*/
template<typename ppT>
bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key<ppT> &pvk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_proof<ppT> &proof);
/****************************** Miscellaneous ********************************/
/**
* For debugging purposes (of r1cs_ppzksnark_r1cs_ppzksnark_verifier_gadget):
*
* A verifier algorithm for the R1CS ppzkSNARK that:
* (1) accepts a non-processed verification key,
* (2) has weak input consistency, and
* (3) uses affine coordinates for elliptic-curve computations.
*/
template<typename ppT>
bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_proof<ppT> &proof);
} // libsnark
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc"
#endif // R1CS_PPZKSNARK_HPP_

886
src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc

@ -1,886 +0,0 @@
/** @file
*****************************************************************************
Implementation of interfaces for a ppzkSNARK for R1CS.
See r1cs_ppzksnark.hpp .
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef R1CS_PPZKSNARK_TCC_
#define R1CS_PPZKSNARK_TCC_
#include <algorithm>
#include <cassert>
#include <functional>
#include <iostream>
#include <sstream>
#include "common/profiling.hpp"
#include "common/utils.hpp"
#include "algebra/scalar_multiplication/multiexp.hpp"
#include "algebra/scalar_multiplication/kc_multiexp.hpp"
#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp"
namespace libsnark {
template<typename ppT>
bool r1cs_ppzksnark_proving_key<ppT>::operator==(const r1cs_ppzksnark_proving_key<ppT> &other) const
{
return (this->A_query == other.A_query &&
this->B_query == other.B_query &&
this->C_query == other.C_query &&
this->H_query == other.H_query &&
this->K_query == other.K_query);
}
template<typename ppT>
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key<ppT> &pk)
{
out << pk.A_query;
out << pk.B_query;
out << pk.C_query;
out << pk.H_query;
out << pk.K_query;
return out;
}
template<typename ppT>
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key<ppT> &pk)
{
in >> pk.A_query;
in >> pk.B_query;
in >> pk.C_query;
in >> pk.H_query;
in >> pk.K_query;
return in;
}
template<typename ppT>
bool r1cs_ppzksnark_verification_key<ppT>::operator==(const r1cs_ppzksnark_verification_key<ppT> &other) const
{
return (this->alphaA_g2 == other.alphaA_g2 &&
this->alphaB_g1 == other.alphaB_g1 &&
this->alphaC_g2 == other.alphaC_g2 &&
this->gamma_g2 == other.gamma_g2 &&
this->gamma_beta_g1 == other.gamma_beta_g1 &&
this->gamma_beta_g2 == other.gamma_beta_g2 &&
this->rC_Z_g2 == other.rC_Z_g2 &&
this->encoded_IC_query == other.encoded_IC_query);
}
template<typename ppT>
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key<ppT> &vk)
{
out << vk.alphaA_g2 << OUTPUT_NEWLINE;
out << vk.alphaB_g1 << OUTPUT_NEWLINE;
out << vk.alphaC_g2 << OUTPUT_NEWLINE;
out << vk.gamma_g2 << OUTPUT_NEWLINE;
out << vk.gamma_beta_g1 << OUTPUT_NEWLINE;
out << vk.gamma_beta_g2 << OUTPUT_NEWLINE;
out << vk.rC_Z_g2 << OUTPUT_NEWLINE;
out << vk.encoded_IC_query << OUTPUT_NEWLINE;
return out;
}
template<typename ppT>
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key<ppT> &vk)
{
in >> vk.alphaA_g2;
consume_OUTPUT_NEWLINE(in);
in >> vk.alphaB_g1;
consume_OUTPUT_NEWLINE(in);
in >> vk.alphaC_g2;
consume_OUTPUT_NEWLINE(in);
in >> vk.gamma_g2;
consume_OUTPUT_NEWLINE(in);
in >> vk.gamma_beta_g1;
consume_OUTPUT_NEWLINE(in);
in >> vk.gamma_beta_g2;
consume_OUTPUT_NEWLINE(in);
in >> vk.rC_Z_g2;
consume_OUTPUT_NEWLINE(in);
in >> vk.encoded_IC_query;
consume_OUTPUT_NEWLINE(in);
return in;
}
template<typename ppT>
bool r1cs_ppzksnark_processed_verification_key<ppT>::operator==(const r1cs_ppzksnark_processed_verification_key<ppT> &other) const
{
return (this->pp_G2_one_precomp == other.pp_G2_one_precomp &&
this->vk_alphaA_g2_precomp == other.vk_alphaA_g2_precomp &&
this->vk_alphaB_g1_precomp == other.vk_alphaB_g1_precomp &&
this->vk_alphaC_g2_precomp == other.vk_alphaC_g2_precomp &&
this->vk_rC_Z_g2_precomp == other.vk_rC_Z_g2_precomp &&
this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp &&
this->vk_gamma_beta_g1_precomp == other.vk_gamma_beta_g1_precomp &&
this->vk_gamma_beta_g2_precomp == other.vk_gamma_beta_g2_precomp &&
this->encoded_IC_query == other.encoded_IC_query);
}
template<typename ppT>
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key<ppT> &pvk)
{
out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE;
out << pvk.vk_alphaA_g2_precomp << OUTPUT_NEWLINE;
out << pvk.vk_alphaB_g1_precomp << OUTPUT_NEWLINE;
out << pvk.vk_alphaC_g2_precomp << OUTPUT_NEWLINE;
out << pvk.vk_rC_Z_g2_precomp << OUTPUT_NEWLINE;
out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE;
out << pvk.vk_gamma_beta_g1_precomp << OUTPUT_NEWLINE;
out << pvk.vk_gamma_beta_g2_precomp << OUTPUT_NEWLINE;
out << pvk.encoded_IC_query << OUTPUT_NEWLINE;
return out;
}
template<typename ppT>
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key<ppT> &pvk)
{
in >> pvk.pp_G2_one_precomp;
consume_OUTPUT_NEWLINE(in);
in >> pvk.vk_alphaA_g2_precomp;
consume_OUTPUT_NEWLINE(in);
in >> pvk.vk_alphaB_g1_precomp;
consume_OUTPUT_NEWLINE(in);
in >> pvk.vk_alphaC_g2_precomp;
consume_OUTPUT_NEWLINE(in);
in >> pvk.vk_rC_Z_g2_precomp;
consume_OUTPUT_NEWLINE(in);
in >> pvk.vk_gamma_g2_precomp;
consume_OUTPUT_NEWLINE(in);
in >> pvk.vk_gamma_beta_g1_precomp;
consume_OUTPUT_NEWLINE(in);
in >> pvk.vk_gamma_beta_g2_precomp;
consume_OUTPUT_NEWLINE(in);
in >> pvk.encoded_IC_query;
consume_OUTPUT_NEWLINE(in);
return in;
}
template<typename ppT>
bool r1cs_ppzksnark_proof<ppT>::operator==(const r1cs_ppzksnark_proof<ppT> &other) const
{
return (this->g_A == other.g_A &&
this->g_B == other.g_B &&
this->g_C == other.g_C &&
this->g_H == other.g_H &&
this->g_K == other.g_K);
}
template<typename ppT>
std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof<ppT> &proof)
{
out << proof.g_A << OUTPUT_NEWLINE;
out << proof.g_B << OUTPUT_NEWLINE;
out << proof.g_C << OUTPUT_NEWLINE;
out << proof.g_H << OUTPUT_NEWLINE;
out << proof.g_K << OUTPUT_NEWLINE;
return out;
}
template<typename ppT>
std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof<ppT> &proof)
{
in >> proof.g_A;
consume_OUTPUT_NEWLINE(in);
in >> proof.g_B;
consume_OUTPUT_NEWLINE(in);
in >> proof.g_C;
consume_OUTPUT_NEWLINE(in);
in >> proof.g_H;
consume_OUTPUT_NEWLINE(in);
in >> proof.g_K;
consume_OUTPUT_NEWLINE(in);
return in;
}
template<typename ppT>
r1cs_ppzksnark_verification_key<ppT> r1cs_ppzksnark_verification_key<ppT>::dummy_verification_key(const size_t input_size)
{
r1cs_ppzksnark_verification_key<ppT> result;
result.alphaA_g2 = Fr<ppT>::random_element() * G2<ppT>::one();
result.alphaB_g1 = Fr<ppT>::random_element() * G1<ppT>::one();
result.alphaC_g2 = Fr<ppT>::random_element() * G2<ppT>::one();
result.gamma_g2 = Fr<ppT>::random_element() * G2<ppT>::one();
result.gamma_beta_g1 = Fr<ppT>::random_element() * G1<ppT>::one();
result.gamma_beta_g2 = Fr<ppT>::random_element() * G2<ppT>::one();
result.rC_Z_g2 = Fr<ppT>::random_element() * G2<ppT>::one();
G1<ppT> base = Fr<ppT>::random_element() * G1<ppT>::one();
G1_vector<ppT> v;
for (size_t i = 0; i < input_size; ++i)
{
v.emplace_back(Fr<ppT>::random_element() * G1<ppT>::one());
}
result.encoded_IC_query = accumulation_vector<G1<ppT> >(std::move(base), std::move(v));
return result;
}
template <typename ppT>
r1cs_ppzksnark_keypair<ppT> r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system<ppT> &cs)
{
/* draw random element at which the QAP is evaluated */
const Fr<ppT> t = Fr<ppT>::random_element();
const Fr<ppT> alphaA = Fr<ppT>::random_element(),
alphaB = Fr<ppT>::random_element(),
alphaC = Fr<ppT>::random_element(),
rA = Fr<ppT>::random_element(),
rB = Fr<ppT>::random_element(),
beta = Fr<ppT>::random_element(),
gamma = Fr<ppT>::random_element();
return r1cs_ppzksnark_generator<ppT>(cs, t, alphaA, alphaB, alphaC, rA, rB, beta, gamma);
}
template <typename ppT>
r1cs_ppzksnark_keypair<ppT> r1cs_ppzksnark_generator(
const r1cs_ppzksnark_constraint_system<ppT> &cs,
const Fr<ppT>& t,
const Fr<ppT>& alphaA,
const Fr<ppT>& alphaB,
const Fr<ppT>& alphaC,
const Fr<ppT>& rA,
const Fr<ppT>& rB,
const Fr<ppT>& beta,
const Fr<ppT>& gamma
)
{
enter_block("Call to r1cs_ppzksnark_generator");
/* make the B_query "lighter" if possible */
r1cs_ppzksnark_constraint_system<ppT> cs_copy(cs);
cs_copy.swap_AB_if_beneficial();
qap_instance_evaluation<Fr<ppT> > qap_inst = r1cs_to_qap_instance_map_with_evaluation(cs_copy, t);
print_indent(); printf("* QAP number of variables: %zu\n", qap_inst.num_variables());
print_indent(); printf("* QAP pre degree: %zu\n", cs_copy.constraints.size());
print_indent(); printf("* QAP degree: %zu\n", qap_inst.degree());
print_indent(); printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs());
enter_block("Compute query densities");
size_t non_zero_At = 0, non_zero_Bt = 0, non_zero_Ct = 0, non_zero_Ht = 0;
for (size_t i = 0; i < qap_inst.num_variables()+1; ++i)
{
if (!qap_inst.At[i].is_zero())
{
++non_zero_At;
}
if (!qap_inst.Bt[i].is_zero())
{
++non_zero_Bt;
}
if (!qap_inst.Ct[i].is_zero())
{
++non_zero_Ct;
}
}
for (size_t i = 0; i < qap_inst.degree()+1; ++i)
{
if (!qap_inst.Ht[i].is_zero())
{
++non_zero_Ht;
}
}
leave_block("Compute query densities");
Fr_vector<ppT> At = std::move(qap_inst.At); // qap_inst.At is now in unspecified state, but we do not use it later
Fr_vector<ppT> Bt = std::move(qap_inst.Bt); // qap_inst.Bt is now in unspecified state, but we do not use it later
Fr_vector<ppT> Ct = std::move(qap_inst.Ct); // qap_inst.Ct is now in unspecified state, but we do not use it later
Fr_vector<ppT> Ht = std::move(qap_inst.Ht); // qap_inst.Ht is now in unspecified state, but we do not use it later
/* append Zt to At,Bt,Ct with */
At.emplace_back(qap_inst.Zt);
Bt.emplace_back(qap_inst.Zt);
Ct.emplace_back(qap_inst.Zt);
const Fr<ppT> rC = rA * rB;
// consrtuct the same-coefficient-check query (must happen before zeroing out the prefix of At)
Fr_vector<ppT> Kt;
Kt.reserve(qap_inst.num_variables()+4);
for (size_t i = 0; i < qap_inst.num_variables()+1; ++i)
{
Kt.emplace_back( beta * (rA * At[i] + rB * Bt[i] + rC * Ct[i] ) );
}
Kt.emplace_back(beta * rA * qap_inst.Zt);
Kt.emplace_back(beta * rB * qap_inst.Zt);
Kt.emplace_back(beta * rC * qap_inst.Zt);
/* zero out prefix of At and stick it into IC coefficients */
Fr_vector<ppT> IC_coefficients;
IC_coefficients.reserve(qap_inst.num_inputs() + 1);
for (size_t i = 0; i < qap_inst.num_inputs() + 1; ++i)
{
IC_coefficients.emplace_back(At[i]);
assert(!IC_coefficients[i].is_zero());
At[i] = Fr<ppT>::zero();
}
const size_t g1_exp_count = 2*(non_zero_At - qap_inst.num_inputs() + non_zero_Ct) + non_zero_Bt + non_zero_Ht + Kt.size();
const size_t g2_exp_count = non_zero_Bt;
size_t g1_window = get_exp_window_size<G1<ppT> >(g1_exp_count);
size_t g2_window = get_exp_window_size<G2<ppT> >(g2_exp_count);
print_indent(); printf("* G1 window: %zu\n", g1_window);
print_indent(); printf("* G2 window: %zu\n", g2_window);
#ifdef MULTICORE
const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads()
#else
const size_t chunks = 1;
#endif
enter_block("Generating G1 multiexp table");
window_table<G1<ppT> > g1_table = get_window_table(Fr<ppT>::size_in_bits(), g1_window, G1<ppT>::one());
leave_block("Generating G1 multiexp table");
enter_block("Generating G2 multiexp table");
window_table<G2<ppT> > g2_table = get_window_table(Fr<ppT>::size_in_bits(), g2_window, G2<ppT>::one());
leave_block("Generating G2 multiexp table");
enter_block("Generate R1CS proving key");
enter_block("Generate knowledge commitments");
enter_block("Compute the A-query", false);
knowledge_commitment_vector<G1<ppT>, G1<ppT> > A_query = kc_batch_exp(Fr<ppT>::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rA, rA*alphaA, At, chunks);
leave_block("Compute the A-query", false);
enter_block("Compute the B-query", false);
knowledge_commitment_vector<G2<ppT>, G1<ppT> > B_query = kc_batch_exp(Fr<ppT>::size_in_bits(), g2_window, g1_window, g2_table, g1_table, rB, rB*alphaB, Bt, chunks);
leave_block("Compute the B-query", false);
enter_block("Compute the C-query", false);
knowledge_commitment_vector<G1<ppT>, G1<ppT> > C_query = kc_batch_exp(Fr<ppT>::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rC, rC*alphaC, Ct, chunks);
leave_block("Compute the C-query", false);
enter_block("Compute the H-query", false);
G1_vector<ppT> H_query = batch_exp(Fr<ppT>::size_in_bits(), g1_window, g1_table, Ht);
leave_block("Compute the H-query", false);
enter_block("Compute the K-query", false);
G1_vector<ppT> K_query = batch_exp(Fr<ppT>::size_in_bits(), g1_window, g1_table, Kt);
#ifdef USE_MIXED_ADDITION
batch_to_special<G1<ppT> >(K_query);
#endif
leave_block("Compute the K-query", false);
leave_block("Generate knowledge commitments");
leave_block("Generate R1CS proving key");
enter_block("Generate R1CS verification key");
G2<ppT> alphaA_g2 = alphaA * G2<ppT>::one();
G1<ppT> alphaB_g1 = alphaB * G1<ppT>::one();
G2<ppT> alphaC_g2 = alphaC * G2<ppT>::one();
G2<ppT> gamma_g2 = gamma * G2<ppT>::one();
G1<ppT> gamma_beta_g1 = (gamma * beta) * G1<ppT>::one();
G2<ppT> gamma_beta_g2 = (gamma * beta) * G2<ppT>::one();
G2<ppT> rC_Z_g2 = (rC * qap_inst.Zt) * G2<ppT>::one();
enter_block("Encode IC query for R1CS verification key");
G1<ppT> encoded_IC_base = (rA * IC_coefficients[0]) * G1<ppT>::one();
Fr_vector<ppT> multiplied_IC_coefficients;
multiplied_IC_coefficients.reserve(qap_inst.num_inputs());
for (size_t i = 1; i < qap_inst.num_inputs() + 1; ++i)
{
multiplied_IC_coefficients.emplace_back(rA * IC_coefficients[i]);
}
G1_vector<ppT> encoded_IC_values = batch_exp(Fr<ppT>::size_in_bits(), g1_window, g1_table, multiplied_IC_coefficients);
leave_block("Encode IC query for R1CS verification key");
leave_block("Generate R1CS verification key");
leave_block("Call to r1cs_ppzksnark_generator");
accumulation_vector<G1<ppT> > encoded_IC_query(std::move(encoded_IC_base), std::move(encoded_IC_values));
r1cs_ppzksnark_verification_key<ppT> vk = r1cs_ppzksnark_verification_key<ppT>(alphaA_g2,
alphaB_g1,
alphaC_g2,
gamma_g2,
gamma_beta_g1,
gamma_beta_g2,
rC_Z_g2,
encoded_IC_query);
r1cs_ppzksnark_proving_key<ppT> pk = r1cs_ppzksnark_proving_key<ppT>(std::move(A_query),
std::move(B_query),
std::move(C_query),
std::move(H_query),
std::move(K_query));
pk.print_size();
vk.print_size();
return r1cs_ppzksnark_keypair<ppT>(std::move(pk), std::move(vk));
}
template <typename ppT, typename T1, typename T2>
knowledge_commitment<T1, T2> r1cs_compute_proof_kc(const qap_witness<Fr<ppT> > &qap_wit,
const knowledge_commitment_vector<T1, T2> &kcv,
const Fr<ppT> &zk_shift)
{
knowledge_commitment<T1, T2> returnval = kcv[0] + (zk_shift * kcv[qap_wit.num_variables()+1]);
#ifdef DEBUG
assert(kcv.domain_size() == qap_wit.num_variables()+2);
#endif
#ifdef MULTICORE
const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads()
#else
const size_t chunks = 1;
#endif
returnval = returnval + kc_multi_exp_with_mixed_addition<T1, T2, Fr<ppT> >(
kcv,
1,
1 + qap_wit.num_variables(),
qap_wit.coefficients_for_ABCs.begin(),
qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(),
chunks,
true
);
return returnval;
}
template <typename ppT>
G1<ppT> r1cs_compute_proof_K(const qap_witness<Fr<ppT>> &qap_wit, const G1_vector<ppT> &K_query, const G1<ppT> &zk_shift)
{
#ifdef DEBUG
assert(K_query.size() == qap_wit.num_variables()+4);
#endif
#ifdef MULTICORE
const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads()
#else
const size_t chunks = 1;
#endif
G1<ppT> g_K = K_query[0] + zk_shift;
g_K = g_K + multi_exp_with_mixed_addition<G1<ppT>, Fr<ppT> >(
K_query.begin()+1,
K_query.begin()+1+qap_wit.num_variables(),
qap_wit.coefficients_for_ABCs.begin(),
qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(),
chunks,
true
);
return g_K;
}
template <typename ppT>
G1<ppT> r1cs_compute_proof_H(const qap_witness<Fr<ppT> > &qap_wit, const G1_vector<ppT> &H_query)
{
G1<ppT> g_H = G1<ppT>::zero();
#ifdef DEBUG
assert(H_query.size() == qap_wit.degree()+1);
#endif
#ifdef MULTICORE
const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads()
#else
const size_t chunks = 1;
#endif
g_H = g_H + multi_exp<G1<ppT>, Fr<ppT> >(
H_query.begin(),
H_query.begin()+qap_wit.degree()+1,
qap_wit.coefficients_for_H.begin(),
qap_wit.coefficients_for_H.begin()+qap_wit.degree()+1,
chunks,
true
);
return g_H;
}
template <typename ppT>
r1cs_ppzksnark_proof<ppT> r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key<ppT> &pk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_auxiliary_input<ppT> &auxiliary_input,
const r1cs_ppzksnark_constraint_system<ppT> &constraint_system)
{
enter_block("Call to r1cs_ppzksnark_prover");
#ifdef DEBUG
assert(constraint_system.is_satisfied(primary_input, auxiliary_input));
#endif
const Fr<ppT> d1 = Fr<ppT>::random_element(),
d2 = Fr<ppT>::random_element(),
d3 = Fr<ppT>::random_element();
enter_block("Compute the polynomial H");
const qap_witness<Fr<ppT> > qap_wit = r1cs_to_qap_witness_map(constraint_system, primary_input, auxiliary_input, d1, d2, d3);
leave_block("Compute the polynomial H");
#ifdef DEBUG
const Fr<ppT> t = Fr<ppT>::random_element();
qap_instance_evaluation<Fr<ppT> > qap_inst = r1cs_to_qap_instance_map_with_evaluation(constraint_system, t);
assert(qap_inst.is_satisfied(qap_wit));
#endif
#ifdef DEBUG
for (size_t i = 0; i < qap_wit.num_inputs() + 1; ++i)
{
assert(pk.A_query[i].g == G1<ppT>::zero());
}
#endif
enter_block("Compute the proof");
enter_block("Compute answer to A-query", false);
auto g_A = r1cs_compute_proof_kc<ppT, G1<ppT>, G1<ppT> >(qap_wit, pk.A_query, qap_wit.d1);
leave_block("Compute answer to A-query", false);
enter_block("Compute answer to B-query", false);
auto g_B = r1cs_compute_proof_kc<ppT, G2<ppT>, G1<ppT> >(qap_wit, pk.B_query, qap_wit.d2);
leave_block("Compute answer to B-query", false);
enter_block("Compute answer to C-query", false);
auto g_C = r1cs_compute_proof_kc<ppT, G1<ppT>, G1<ppT> >(qap_wit, pk.C_query, qap_wit.d3);
leave_block("Compute answer to C-query", false);
enter_block("Compute answer to H-query", false);
auto g_H = r1cs_compute_proof_H<ppT>(qap_wit, pk.H_query);
leave_block("Compute answer to H-query", false);
enter_block("Compute answer to K-query", false);
G1<ppT> zk_shift = qap_wit.d1*pk.K_query[qap_wit.num_variables()+1] +
qap_wit.d2*pk.K_query[qap_wit.num_variables()+2] +
qap_wit.d3*pk.K_query[qap_wit.num_variables()+3];
G1<ppT> g_K = r1cs_compute_proof_K<ppT>(qap_wit, pk.K_query, zk_shift);
leave_block("Compute answer to K-query", false);
leave_block("Compute the proof");
leave_block("Call to r1cs_ppzksnark_prover");
r1cs_ppzksnark_proof<ppT> proof = r1cs_ppzksnark_proof<ppT>(std::move(g_A), std::move(g_B), std::move(g_C), std::move(g_H), std::move(g_K));
return proof;
}
template <typename ppT>
r1cs_ppzksnark_proof<ppT> r1cs_ppzksnark_prover_streaming(std::ifstream &proving_key_file,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_auxiliary_input<ppT> &auxiliary_input,
const r1cs_ppzksnark_constraint_system<ppT> &constraint_system)
{
enter_block("Call to r1cs_ppzksnark_prover_streaming");
const Fr<ppT> d1 = Fr<ppT>::random_element(),
d2 = Fr<ppT>::random_element(),
d3 = Fr<ppT>::random_element();
enter_block("Compute the polynomial H");
const qap_witness<Fr<ppT> > qap_wit = r1cs_to_qap_witness_map(constraint_system, primary_input, auxiliary_input, d1, d2, d3);
leave_block("Compute the polynomial H");
enter_block("Compute the proof");
r1cs_ppzksnark_proof<ppT> proof;
enter_block("Compute answer to A-query", false);
{
knowledge_commitment_vector<G1<ppT>, G1<ppT> > A_query;
proving_key_file >> A_query;
proof.g_A = r1cs_compute_proof_kc<ppT, G1<ppT>, G1<ppT> >(qap_wit, A_query, qap_wit.d1);
}
leave_block("Compute answer to A-query", false);
enter_block("Compute answer to B-query", false);
{
knowledge_commitment_vector<G2<ppT>, G1<ppT> > B_query;
proving_key_file >> B_query;
proof.g_B = r1cs_compute_proof_kc<ppT, G2<ppT>, G1<ppT> >(qap_wit, B_query, qap_wit.d2);
}
leave_block("Compute answer to B-query", false);
enter_block("Compute answer to C-query", false);
{
knowledge_commitment_vector<G1<ppT>, G1<ppT> > C_query;
proving_key_file >> C_query;
proof.g_C = r1cs_compute_proof_kc<ppT, G1<ppT>, G1<ppT> >(qap_wit, C_query, qap_wit.d3);
}
leave_block("Compute answer to C-query", false);
enter_block("Compute answer to H-query", false);
{
G1_vector<ppT> H_query;
proving_key_file >> H_query;
proof.g_H = r1cs_compute_proof_H<ppT>(qap_wit, H_query);
}
leave_block("Compute answer to H-query", false);
enter_block("Compute answer to K-query", false);
{
G1_vector<ppT> K_query;
proving_key_file >> K_query;
G1<ppT> zk_shift = qap_wit.d1*K_query[qap_wit.num_variables()+1] +
qap_wit.d2*K_query[qap_wit.num_variables()+2] +
qap_wit.d3*K_query[qap_wit.num_variables()+3];
proof.g_K = r1cs_compute_proof_K<ppT>(qap_wit, K_query, zk_shift);
}
leave_block("Compute answer to K-query", false);
leave_block("Compute the proof");
leave_block("Call to r1cs_ppzksnark_prover_streaming");
return proof;
}
template <typename ppT>
r1cs_ppzksnark_processed_verification_key<ppT> r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key<ppT> &vk)
{
enter_block("Call to r1cs_ppzksnark_verifier_process_vk");
r1cs_ppzksnark_processed_verification_key<ppT> pvk;
pvk.pp_G2_one_precomp = ppT::precompute_G2(G2<ppT>::one());
pvk.vk_alphaA_g2_precomp = ppT::precompute_G2(vk.alphaA_g2);
pvk.vk_alphaB_g1_precomp = ppT::precompute_G1(vk.alphaB_g1);
pvk.vk_alphaC_g2_precomp = ppT::precompute_G2(vk.alphaC_g2);
pvk.vk_rC_Z_g2_precomp = ppT::precompute_G2(vk.rC_Z_g2);
pvk.vk_gamma_g2_precomp = ppT::precompute_G2(vk.gamma_g2);
pvk.vk_gamma_beta_g1_precomp = ppT::precompute_G1(vk.gamma_beta_g1);
pvk.vk_gamma_beta_g2_precomp = ppT::precompute_G2(vk.gamma_beta_g2);
pvk.encoded_IC_query = vk.encoded_IC_query;
leave_block("Call to r1cs_ppzksnark_verifier_process_vk");
return pvk;
}
template <typename ppT>
bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key<ppT> &pvk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_proof<ppT> &proof)
{
assert(pvk.encoded_IC_query.domain_size() >= primary_input.size());
const accumulation_vector<G1<ppT> > accumulated_IC = pvk.encoded_IC_query.template accumulate_chunk<Fr<ppT> >(primary_input.begin(), primary_input.end(), 0);
const G1<ppT> &acc = accumulated_IC.first;
if (!proof.is_well_formed())
{
return false;
}
G1_precomp<ppT> proof_g_A_g_precomp = ppT::precompute_G1(proof.g_A.g);
G1_precomp<ppT> proof_g_A_h_precomp = ppT::precompute_G1(proof.g_A.h);
Fqk<ppT> kc_A_1 = ppT::miller_loop(proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp);
Fqk<ppT> kc_A_2 = ppT::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp);
GT<ppT> kc_A = ppT::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse());
if (kc_A != GT<ppT>::one())
{
return false;
}
G2_precomp<ppT> proof_g_B_g_precomp = ppT::precompute_G2(proof.g_B.g);
G1_precomp<ppT> proof_g_B_h_precomp = ppT::precompute_G1(proof.g_B.h);
Fqk<ppT> kc_B_1 = ppT::miller_loop(pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp);
Fqk<ppT> kc_B_2 = ppT::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp);
GT<ppT> kc_B = ppT::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse());
if (kc_B != GT<ppT>::one())
{
return false;
}
G1_precomp<ppT> proof_g_C_g_precomp = ppT::precompute_G1(proof.g_C.g);
G1_precomp<ppT> proof_g_C_h_precomp = ppT::precompute_G1(proof.g_C.h);
Fqk<ppT> kc_C_1 = ppT::miller_loop(proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp);
Fqk<ppT> kc_C_2 = ppT::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp);
GT<ppT> kc_C = ppT::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse());
if (kc_C != GT<ppT>::one())
{
return false;
}
// check that g^((A+acc)*B)=g^(H*\Prod(t-\sigma)+C)
// equivalently, via pairings, that e(g^(A+acc), g^B) = e(g^H, g^Z) + e(g^C, g^1)
G1_precomp<ppT> proof_g_A_g_acc_precomp = ppT::precompute_G1(proof.g_A.g + acc);
G1_precomp<ppT> proof_g_H_precomp = ppT::precompute_G1(proof.g_H);
Fqk<ppT> QAP_1 = ppT::miller_loop(proof_g_A_g_acc_precomp, proof_g_B_g_precomp);
Fqk<ppT> QAP_23 = ppT::double_miller_loop(proof_g_H_precomp, pvk.vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk.pp_G2_one_precomp);
GT<ppT> QAP = ppT::final_exponentiation(QAP_1 * QAP_23.unitary_inverse());
if (QAP != GT<ppT>::one())
{
return false;
}
G1_precomp<ppT> proof_g_K_precomp = ppT::precompute_G1(proof.g_K);
G1_precomp<ppT> proof_g_A_g_acc_C_precomp = ppT::precompute_G1((proof.g_A.g + acc) + proof.g_C.g);
Fqk<ppT> K_1 = ppT::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp);
Fqk<ppT> K_23 = ppT::double_miller_loop(proof_g_A_g_acc_C_precomp, pvk.vk_gamma_beta_g2_precomp, pvk.vk_gamma_beta_g1_precomp, proof_g_B_g_precomp);
GT<ppT> K = ppT::final_exponentiation(K_1 * K_23.unitary_inverse());
if (K != GT<ppT>::one())
{
return false;
}
return true;
}
template<typename ppT>
bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_proof<ppT> &proof)
{
enter_block("Call to r1cs_ppzksnark_verifier_weak_IC");
r1cs_ppzksnark_processed_verification_key<ppT> pvk = r1cs_ppzksnark_verifier_process_vk<ppT>(vk);
bool result = r1cs_ppzksnark_online_verifier_weak_IC<ppT>(pvk, primary_input, proof);
leave_block("Call to r1cs_ppzksnark_verifier_weak_IC");
return result;
}
template<typename ppT>
bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key<ppT> &pvk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_proof<ppT> &proof)
{
bool result = true;
enter_block("Call to r1cs_ppzksnark_online_verifier_strong_IC");
if (pvk.encoded_IC_query.domain_size() != primary_input.size())
{
print_indent(); printf("Input length differs from expected (got %zu, expected %zu).\n", primary_input.size(), pvk.encoded_IC_query.domain_size());
result = false;
}
else
{
result = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof);
}
leave_block("Call to r1cs_ppzksnark_online_verifier_strong_IC");
return result;
}
template<typename ppT>
bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_proof<ppT> &proof)
{
enter_block("Call to r1cs_ppzksnark_verifier_strong_IC");
r1cs_ppzksnark_processed_verification_key<ppT> pvk = r1cs_ppzksnark_verifier_process_vk<ppT>(vk);
bool result = r1cs_ppzksnark_online_verifier_strong_IC<ppT>(pvk, primary_input, proof);
leave_block("Call to r1cs_ppzksnark_verifier_strong_IC");
return result;
}
template<typename ppT>
bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key<ppT> &vk,
const r1cs_ppzksnark_primary_input<ppT> &primary_input,
const r1cs_ppzksnark_proof<ppT> &proof)
{
enter_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC");
assert(vk.encoded_IC_query.domain_size() >= primary_input.size());
affine_ate_G2_precomp<ppT> pvk_pp_G2_one_precomp = ppT::affine_ate_precompute_G2(G2<ppT>::one());
affine_ate_G2_precomp<ppT> pvk_vk_alphaA_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaA_g2);
affine_ate_G1_precomp<ppT> pvk_vk_alphaB_g1_precomp = ppT::affine_ate_precompute_G1(vk.alphaB_g1);
affine_ate_G2_precomp<ppT> pvk_vk_alphaC_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaC_g2);
affine_ate_G2_precomp<ppT> pvk_vk_rC_Z_g2_precomp = ppT::affine_ate_precompute_G2(vk.rC_Z_g2);
affine_ate_G2_precomp<ppT> pvk_vk_gamma_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_g2);
affine_ate_G1_precomp<ppT> pvk_vk_gamma_beta_g1_precomp = ppT::affine_ate_precompute_G1(vk.gamma_beta_g1);
affine_ate_G2_precomp<ppT> pvk_vk_gamma_beta_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_beta_g2);
enter_block("Compute input-dependent part of A");
const accumulation_vector<G1<ppT> > accumulated_IC = vk.encoded_IC_query.template accumulate_chunk<Fr<ppT> >(primary_input.begin(), primary_input.end(), 0);
assert(accumulated_IC.is_fully_accumulated());
const G1<ppT> &acc = accumulated_IC.first;
leave_block("Compute input-dependent part of A");
bool result = true;
enter_block("Check knowledge commitment for A is valid");
affine_ate_G1_precomp<ppT> proof_g_A_g_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g);
affine_ate_G1_precomp<ppT> proof_g_A_h_precomp = ppT::affine_ate_precompute_G1(proof.g_A.h);
Fqk<ppT> kc_A_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_A_g_precomp, pvk_vk_alphaA_g2_precomp, proof_g_A_h_precomp, pvk_pp_G2_one_precomp);
GT<ppT> kc_A = ppT::final_exponentiation(kc_A_miller);
if (kc_A != GT<ppT>::one())
{
print_indent(); printf("Knowledge commitment for A query incorrect.\n");
result = false;
}
leave_block("Check knowledge commitment for A is valid");
enter_block("Check knowledge commitment for B is valid");
affine_ate_G2_precomp<ppT> proof_g_B_g_precomp = ppT::affine_ate_precompute_G2(proof.g_B.g);
affine_ate_G1_precomp<ppT> proof_g_B_h_precomp = ppT::affine_ate_precompute_G1(proof.g_B.h);
Fqk<ppT> kc_B_miller = ppT::affine_ate_e_over_e_miller_loop(pvk_vk_alphaB_g1_precomp, proof_g_B_g_precomp, proof_g_B_h_precomp, pvk_pp_G2_one_precomp);
GT<ppT> kc_B = ppT::final_exponentiation(kc_B_miller);
if (kc_B != GT<ppT>::one())
{
print_indent(); printf("Knowledge commitment for B query incorrect.\n");
result = false;
}
leave_block("Check knowledge commitment for B is valid");
enter_block("Check knowledge commitment for C is valid");
affine_ate_G1_precomp<ppT> proof_g_C_g_precomp = ppT::affine_ate_precompute_G1(proof.g_C.g);
affine_ate_G1_precomp<ppT> proof_g_C_h_precomp = ppT::affine_ate_precompute_G1(proof.g_C.h);
Fqk<ppT> kc_C_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_C_g_precomp, pvk_vk_alphaC_g2_precomp, proof_g_C_h_precomp, pvk_pp_G2_one_precomp);
GT<ppT> kc_C = ppT::final_exponentiation(kc_C_miller);
if (kc_C != GT<ppT>::one())
{
print_indent(); printf("Knowledge commitment for C query incorrect.\n");
result = false;
}
leave_block("Check knowledge commitment for C is valid");
enter_block("Check QAP divisibility");
affine_ate_G1_precomp<ppT> proof_g_A_g_acc_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g + acc);
affine_ate_G1_precomp<ppT> proof_g_H_precomp = ppT::affine_ate_precompute_G1(proof.g_H);
Fqk<ppT> QAP_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_H_precomp, pvk_vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk_pp_G2_one_precomp, proof_g_A_g_acc_precomp, proof_g_B_g_precomp);
GT<ppT> QAP = ppT::final_exponentiation(QAP_miller);
if (QAP != GT<ppT>::one())
{
print_indent(); printf("QAP divisibility check failed.\n");
result = false;
}
leave_block("Check QAP divisibility");
enter_block("Check same coefficients were used");
affine_ate_G1_precomp<ppT> proof_g_K_precomp = ppT::affine_ate_precompute_G1(proof.g_K);
affine_ate_G1_precomp<ppT> proof_g_A_g_acc_C_precomp = ppT::affine_ate_precompute_G1((proof.g_A.g + acc) + proof.g_C.g);
Fqk<ppT> K_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_A_g_acc_C_precomp, pvk_vk_gamma_beta_g2_precomp, pvk_vk_gamma_beta_g1_precomp, proof_g_B_g_precomp, proof_g_K_precomp, pvk_vk_gamma_g2_precomp);
GT<ppT> K = ppT::final_exponentiation(K_miller);
if (K != GT<ppT>::one())
{
print_indent(); printf("Same-coefficient check failed.\n");
result = false;
}
leave_block("Check same coefficients were used");
leave_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC");
return result;
}
} // libsnark
#endif // R1CS_PPZKSNARK_TCC_

34
src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp

@ -1,34 +0,0 @@
/** @file
*****************************************************************************
Declaration of public-parameter selector for the R1CS ppzkSNARK.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#ifndef R1CS_PPZKSNARK_PARAMS_HPP_
#define R1CS_PPZKSNARK_PARAMS_HPP_
#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp"
namespace libsnark {
/**
* Below are various template aliases (used for convenience).
*/
template<typename ppT>
using r1cs_ppzksnark_constraint_system = r1cs_constraint_system<Fr<ppT> >;
template<typename ppT>
using r1cs_ppzksnark_primary_input = r1cs_primary_input<Fr<ppT> >;
template<typename ppT>
using r1cs_ppzksnark_auxiliary_input = r1cs_auxiliary_input<Fr<ppT> >;
} // libsnark
#endif // R1CS_PPZKSNARK_PARAMS_HPP_

42
src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp

@ -1,42 +0,0 @@
/** @file
*****************************************************************************
Test program that exercises the ppzkSNARK (first generator, then
prover, then verifier) on a synthetic R1CS instance.
*****************************************************************************
* @author This file is part of libsnark, developed by SCIPR Lab
* and contributors (see AUTHORS).
* @copyright MIT license (see LICENSE file)
*****************************************************************************/
#include <cassert>
#include <cstdio>
#include "common/default_types/r1cs_ppzksnark_pp.hpp"
#include "common/profiling.hpp"
#include "common/utils.hpp"
#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp"
#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp"
using namespace libsnark;
template<typename ppT>
void test_r1cs_ppzksnark(size_t num_constraints,
size_t input_size)
{
print_header("(enter) Test R1CS ppzkSNARK");
const bool test_serialization = true;
r1cs_example<Fr<ppT> > example = generate_r1cs_example_with_binary_input<Fr<ppT> >(num_constraints, input_size);
const bool bit = run_r1cs_ppzksnark<ppT>(example, test_serialization);
assert(bit);
print_header("(leave) Test R1CS ppzkSNARK");
}
int main()
{
default_r1cs_ppzksnark_pp::init_public_params();
start_profiling();
test_r1cs_ppzksnark<default_r1cs_ppzksnark_pp>(1000, 100);
}
Loading…
Cancel
Save