longfellow 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +10 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +152 -0
  5. data/ext/longfellow/CMakeLists.txt +76 -0
  6. data/ext/longfellow/extconf.rb +77 -0
  7. data/lib/longfellow/attribute.rb +65 -0
  8. data/lib/longfellow/c.rb +105 -0
  9. data/lib/longfellow/errors.rb +78 -0
  10. data/lib/longfellow/version.rb +5 -0
  11. data/lib/longfellow/zk_spec.rb +40 -0
  12. data/lib/longfellow.rb +162 -0
  13. data/sig/longfellow.rbs +74 -0
  14. data/vendor/longfellow-zk/LICENSE +203 -0
  15. data/vendor/longfellow-zk/lib/algebra/blas.h +121 -0
  16. data/vendor/longfellow-zk/lib/algebra/bogorng.h +68 -0
  17. data/vendor/longfellow-zk/lib/algebra/compare.h +40 -0
  18. data/vendor/longfellow-zk/lib/algebra/convolution.h +219 -0
  19. data/vendor/longfellow-zk/lib/algebra/crt.cc +42 -0
  20. data/vendor/longfellow-zk/lib/algebra/crt.h +299 -0
  21. data/vendor/longfellow-zk/lib/algebra/crt_convolution.h +114 -0
  22. data/vendor/longfellow-zk/lib/algebra/crt_test.cc +371 -0
  23. data/vendor/longfellow-zk/lib/algebra/fft.h +104 -0
  24. data/vendor/longfellow-zk/lib/algebra/fft_interpolation.h +304 -0
  25. data/vendor/longfellow-zk/lib/algebra/fft_interpolation_test.cc +168 -0
  26. data/vendor/longfellow-zk/lib/algebra/fft_test.cc +257 -0
  27. data/vendor/longfellow-zk/lib/algebra/fp.h +59 -0
  28. data/vendor/longfellow-zk/lib/algebra/fp2.h +240 -0
  29. data/vendor/longfellow-zk/lib/algebra/fp24.h +342 -0
  30. data/vendor/longfellow-zk/lib/algebra/fp24_6.h +305 -0
  31. data/vendor/longfellow-zk/lib/algebra/fp24_6_test.cc +197 -0
  32. data/vendor/longfellow-zk/lib/algebra/fp2_test.cc +280 -0
  33. data/vendor/longfellow-zk/lib/algebra/fp_generic.h +533 -0
  34. data/vendor/longfellow-zk/lib/algebra/fp_p128.h +91 -0
  35. data/vendor/longfellow-zk/lib/algebra/fp_p256.h +68 -0
  36. data/vendor/longfellow-zk/lib/algebra/fp_p256k1.h +123 -0
  37. data/vendor/longfellow-zk/lib/algebra/fp_p384.h +65 -0
  38. data/vendor/longfellow-zk/lib/algebra/fp_p521.h +62 -0
  39. data/vendor/longfellow-zk/lib/algebra/fp_test.cc +522 -0
  40. data/vendor/longfellow-zk/lib/algebra/hash.h +39 -0
  41. data/vendor/longfellow-zk/lib/algebra/interpolation.h +117 -0
  42. data/vendor/longfellow-zk/lib/algebra/interpolation_test.cc +74 -0
  43. data/vendor/longfellow-zk/lib/algebra/limb.h +153 -0
  44. data/vendor/longfellow-zk/lib/algebra/limb_test.cc +75 -0
  45. data/vendor/longfellow-zk/lib/algebra/nat.cc +32 -0
  46. data/vendor/longfellow-zk/lib/algebra/nat.h +212 -0
  47. data/vendor/longfellow-zk/lib/algebra/nat_test.cc +183 -0
  48. data/vendor/longfellow-zk/lib/algebra/nussbaumer.h +400 -0
  49. data/vendor/longfellow-zk/lib/algebra/nussbaumer_test.cc +138 -0
  50. data/vendor/longfellow-zk/lib/algebra/nussbaumerfp2_test.cc +139 -0
  51. data/vendor/longfellow-zk/lib/algebra/permutations.h +79 -0
  52. data/vendor/longfellow-zk/lib/algebra/poly.h +240 -0
  53. data/vendor/longfellow-zk/lib/algebra/poly_test.cc +123 -0
  54. data/vendor/longfellow-zk/lib/algebra/reed_solomon.h +150 -0
  55. data/vendor/longfellow-zk/lib/algebra/reed_solomon_extension.h +108 -0
  56. data/vendor/longfellow-zk/lib/algebra/reed_solomon_extension_test.cc +76 -0
  57. data/vendor/longfellow-zk/lib/algebra/reed_solomon_test.cc +473 -0
  58. data/vendor/longfellow-zk/lib/algebra/rfft.h +400 -0
  59. data/vendor/longfellow-zk/lib/algebra/rfft_test.cc +102 -0
  60. data/vendor/longfellow-zk/lib/algebra/static_string.h +29 -0
  61. data/vendor/longfellow-zk/lib/algebra/sysdep.h +495 -0
  62. data/vendor/longfellow-zk/lib/algebra/sysdep_test.cc +41 -0
  63. data/vendor/longfellow-zk/lib/algebra/twiddle.h +59 -0
  64. data/vendor/longfellow-zk/lib/algebra/utility.h +86 -0
  65. data/vendor/longfellow-zk/lib/algebra/utility_test.cc +86 -0
  66. data/vendor/longfellow-zk/lib/arrays/affine.h +56 -0
  67. data/vendor/longfellow-zk/lib/arrays/affine_test.cc +220 -0
  68. data/vendor/longfellow-zk/lib/arrays/dense.h +210 -0
  69. data/vendor/longfellow-zk/lib/arrays/eq.h +75 -0
  70. data/vendor/longfellow-zk/lib/arrays/eqs.h +137 -0
  71. data/vendor/longfellow-zk/lib/arrays/eqs_test.cc +151 -0
  72. data/vendor/longfellow-zk/lib/arrays/sparse.h +192 -0
  73. data/vendor/longfellow-zk/lib/cbor/host_decoder.h +323 -0
  74. data/vendor/longfellow-zk/lib/cbor/host_decoder_test.cc +541 -0
  75. data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor.h +594 -0
  76. data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_byte_decoder.h +150 -0
  77. data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_byte_decoder_test.cc +147 -0
  78. data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_constants.h +27 -0
  79. data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_pluck.h +110 -0
  80. data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_pluck_test.cc +55 -0
  81. data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_test.cc +174 -0
  82. data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_testing.h +98 -0
  83. data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_witness.h +312 -0
  84. data/vendor/longfellow-zk/lib/circuits/cbor_parser/mso2_test.cc +662 -0
  85. data/vendor/longfellow-zk/lib/circuits/cbor_parser/mso_test.cc +485 -0
  86. data/vendor/longfellow-zk/lib/circuits/cbor_parser/scan.h +104 -0
  87. data/vendor/longfellow-zk/lib/circuits/cbor_parser/scan_test.cc +137 -0
  88. data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor.h +640 -0
  89. data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor_byte_decoder.h +150 -0
  90. data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor_byte_decoder_test.cc +147 -0
  91. data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor_constants.h +27 -0
  92. data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor_testing.h +99 -0
  93. data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor_witness.h +319 -0
  94. data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/lexer_test.cc +120 -0
  95. data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/mdoc_examples_test.cc +89 -0
  96. data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/parser_circuit_test.cc +506 -0
  97. data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/parser_size_test.cc +79 -0
  98. data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/parser_test.cc +473 -0
  99. data/vendor/longfellow-zk/lib/circuits/compiler/canonicalization_test.cc +185 -0
  100. data/vendor/longfellow-zk/lib/circuits/compiler/circuit_dump.h +65 -0
  101. data/vendor/longfellow-zk/lib/circuits/compiler/compiler.h +471 -0
  102. data/vendor/longfellow-zk/lib/circuits/compiler/compiler_test.cc +110 -0
  103. data/vendor/longfellow-zk/lib/circuits/compiler/node.h +176 -0
  104. data/vendor/longfellow-zk/lib/circuits/compiler/pdqhash.h +127 -0
  105. data/vendor/longfellow-zk/lib/circuits/compiler/schedule.h +435 -0
  106. data/vendor/longfellow-zk/lib/circuits/ecdsa/verify_circuit.h +371 -0
  107. data/vendor/longfellow-zk/lib/circuits/ecdsa/verify_external_test.cc +246 -0
  108. data/vendor/longfellow-zk/lib/circuits/ecdsa/verify_test.cc +587 -0
  109. data/vendor/longfellow-zk/lib/circuits/ecdsa/verify_witness.h +201 -0
  110. data/vendor/longfellow-zk/lib/circuits/logic/bit_adder.h +140 -0
  111. data/vendor/longfellow-zk/lib/circuits/logic/bit_adder_test.cc +64 -0
  112. data/vendor/longfellow-zk/lib/circuits/logic/bit_plucker.h +247 -0
  113. data/vendor/longfellow-zk/lib/circuits/logic/bit_plucker_constants.h +35 -0
  114. data/vendor/longfellow-zk/lib/circuits/logic/bit_plucker_encoder.h +72 -0
  115. data/vendor/longfellow-zk/lib/circuits/logic/bit_plucker_test.cc +183 -0
  116. data/vendor/longfellow-zk/lib/circuits/logic/compiler_backend.h +62 -0
  117. data/vendor/longfellow-zk/lib/circuits/logic/counter.h +171 -0
  118. data/vendor/longfellow-zk/lib/circuits/logic/counter_test.cc +102 -0
  119. data/vendor/longfellow-zk/lib/circuits/logic/evaluation_backend.h +94 -0
  120. data/vendor/longfellow-zk/lib/circuits/logic/logic.h +1232 -0
  121. data/vendor/longfellow-zk/lib/circuits/logic/logic_circuit_test.cc +310 -0
  122. data/vendor/longfellow-zk/lib/circuits/logic/logic_test.cc +521 -0
  123. data/vendor/longfellow-zk/lib/circuits/logic/memcmp.h +68 -0
  124. data/vendor/longfellow-zk/lib/circuits/logic/memcmp_test.cc +148 -0
  125. data/vendor/longfellow-zk/lib/circuits/logic/polynomial.h +94 -0
  126. data/vendor/longfellow-zk/lib/circuits/logic/polynomial_test.cc +62 -0
  127. data/vendor/longfellow-zk/lib/circuits/logic/routing.h +445 -0
  128. data/vendor/longfellow-zk/lib/circuits/logic/routing_test.cc +241 -0
  129. data/vendor/longfellow-zk/lib/circuits/logic/unary.h +55 -0
  130. data/vendor/longfellow-zk/lib/circuits/logic/unary_plucker.h +77 -0
  131. data/vendor/longfellow-zk/lib/circuits/logic/unary_plucker_constants.h +37 -0
  132. data/vendor/longfellow-zk/lib/circuits/logic/unary_plucker_test.cc +53 -0
  133. data/vendor/longfellow-zk/lib/circuits/logic/unary_size_test.cc +69 -0
  134. data/vendor/longfellow-zk/lib/circuits/logic/unary_test.cc +62 -0
  135. data/vendor/longfellow-zk/lib/circuits/mac/mac_circuit.h +193 -0
  136. data/vendor/longfellow-zk/lib/circuits/mac/mac_circuit_test.cc +223 -0
  137. data/vendor/longfellow-zk/lib/circuits/mac/mac_reference.h +72 -0
  138. data/vendor/longfellow-zk/lib/circuits/mac/mac_witness.h +94 -0
  139. data/vendor/longfellow-zk/lib/circuits/mdoc/circuit_maker.cc +242 -0
  140. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_attribute_ids.h +311 -0
  141. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_attribute_test.cc +64 -0
  142. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_circuit_id.cc +85 -0
  143. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_constants.h +85 -0
  144. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_decompress.cc +41 -0
  145. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_decompress.h +27 -0
  146. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_examples.h +5232 -0
  147. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_generate_circuit.cc +199 -0
  148. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_hash.h +554 -0
  149. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_signature.h +143 -0
  150. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_signature_test.cc +444 -0
  151. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_test_attributes.h +157 -0
  152. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_witness.h +863 -0
  153. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_zk.cc +693 -0
  154. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_zk.h +216 -0
  155. data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_zk_test.cc +724 -0
  156. data/vendor/longfellow-zk/lib/circuits/mdoc/zk_spec.cc +100 -0
  157. data/vendor/longfellow-zk/lib/circuits/mdoc/zk_spec_test.cc +155 -0
  158. data/vendor/longfellow-zk/lib/circuits/sha/flatsha256_circuit.h +330 -0
  159. data/vendor/longfellow-zk/lib/circuits/sha/flatsha256_circuit_test.cc +607 -0
  160. data/vendor/longfellow-zk/lib/circuits/sha/flatsha256_io.h +26 -0
  161. data/vendor/longfellow-zk/lib/circuits/sha/flatsha256_witness.cc +163 -0
  162. data/vendor/longfellow-zk/lib/circuits/sha/flatsha256_witness.h +47 -0
  163. data/vendor/longfellow-zk/lib/circuits/sha/sha256_constants.cc +34 -0
  164. data/vendor/longfellow-zk/lib/circuits/sha/sha256_constants.h +27 -0
  165. data/vendor/longfellow-zk/lib/circuits/sha/sha256_test_values.h +389 -0
  166. data/vendor/longfellow-zk/lib/circuits/tests/anoncred/ptrcred.h +171 -0
  167. data/vendor/longfellow-zk/lib/circuits/tests/anoncred/small.h +218 -0
  168. data/vendor/longfellow-zk/lib/circuits/tests/anoncred/small_examples.h +118 -0
  169. data/vendor/longfellow-zk/lib/circuits/tests/anoncred/small_io.h +25 -0
  170. data/vendor/longfellow-zk/lib/circuits/tests/anoncred/small_test.cc +208 -0
  171. data/vendor/longfellow-zk/lib/circuits/tests/anoncred/small_witness.h +130 -0
  172. data/vendor/longfellow-zk/lib/circuits/tests/base64/decode.h +508 -0
  173. data/vendor/longfellow-zk/lib/circuits/tests/base64/decode_circuit_test.cc +95 -0
  174. data/vendor/longfellow-zk/lib/circuits/tests/base64/decode_test.cc +119 -0
  175. data/vendor/longfellow-zk/lib/circuits/tests/base64/decode_util.cc +47 -0
  176. data/vendor/longfellow-zk/lib/circuits/tests/base64/decode_util.h +29 -0
  177. data/vendor/longfellow-zk/lib/circuits/tests/ec/pk_circuit.h +231 -0
  178. data/vendor/longfellow-zk/lib/circuits/tests/ec/pk_circuit_test.cc +428 -0
  179. data/vendor/longfellow-zk/lib/circuits/tests/ec/pk_witness.h +102 -0
  180. data/vendor/longfellow-zk/lib/circuits/tests/jwt/jwt.h +190 -0
  181. data/vendor/longfellow-zk/lib/circuits/tests/jwt/jwt_constants.h +26 -0
  182. data/vendor/longfellow-zk/lib/circuits/tests/jwt/jwt_test.cc +559 -0
  183. data/vendor/longfellow-zk/lib/circuits/tests/jwt/jwt_witness.h +315 -0
  184. data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_1f.h +411 -0
  185. data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_1f_io.h +32 -0
  186. data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_1f_test.cc +364 -0
  187. data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_1f_witness.h +278 -0
  188. data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_revocation.h +146 -0
  189. data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_revocation_constants.h +25 -0
  190. data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_revocation_test.cc +315 -0
  191. data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_revocation_witness.h +136 -0
  192. data/vendor/longfellow-zk/lib/circuits/tests/pq/bitaddr/bitaddr.h +250 -0
  193. data/vendor/longfellow-zk/lib/circuits/tests/pq/bitaddr/bitaddr_test.cc +333 -0
  194. data/vendor/longfellow-zk/lib/circuits/tests/pq/bitaddr/bitaddr_witness.h +152 -0
  195. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44.h +903 -0
  196. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_circuit_test.cc +274 -0
  197. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_eval_test.cc +440 -0
  198. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_examples.cc +8851 -0
  199. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_examples.h +93 -0
  200. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_types.cc +24 -0
  201. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_types.h +118 -0
  202. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_witness.h +453 -0
  203. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_witness_test.cc +49 -0
  204. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref.cc +458 -0
  205. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref.h +150 -0
  206. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref_test.cc +398 -0
  207. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref_test_vectors.inc +3618 -0
  208. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref_test_vectors_pkdecode.inc +689 -0
  209. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref_test_vectors_sigdecode.inc +1501 -0
  210. data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/sigdecode_test_vectors.inc +540 -0
  211. data/vendor/longfellow-zk/lib/circuits/tests/ripemd/ripemd_circuit.h +394 -0
  212. data/vendor/longfellow-zk/lib/circuits/tests/ripemd/ripemd_circuit_test.cc +577 -0
  213. data/vendor/longfellow-zk/lib/circuits/tests/ripemd/ripemd_constants.h +90 -0
  214. data/vendor/longfellow-zk/lib/circuits/tests/ripemd/ripemd_witness.cc +174 -0
  215. data/vendor/longfellow-zk/lib/circuits/tests/ripemd/ripemd_witness.h +140 -0
  216. data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_circuit.h +351 -0
  217. data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_circuit_test.cc +466 -0
  218. data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_reference.cc +207 -0
  219. data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_reference.h +59 -0
  220. data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_reference_test.cc +153 -0
  221. data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_round_constants.cc +39 -0
  222. data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_round_constants.h +29 -0
  223. data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_slicing.h +31 -0
  224. data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_witness.cc +83 -0
  225. data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_witness.h +72 -0
  226. data/vendor/longfellow-zk/lib/circuits/tests/sha3/shake_test_vectors.h +477 -0
  227. data/vendor/longfellow-zk/lib/ec/elliptic_curve.h +596 -0
  228. data/vendor/longfellow-zk/lib/ec/elliptic_curve_test.cc +548 -0
  229. data/vendor/longfellow-zk/lib/ec/p256.cc +36 -0
  230. data/vendor/longfellow-zk/lib/ec/p256.h +60 -0
  231. data/vendor/longfellow-zk/lib/ec/p256k1.cc +34 -0
  232. data/vendor/longfellow-zk/lib/ec/p256k1.h +60 -0
  233. data/vendor/longfellow-zk/lib/gf2k/gf2_128.h +503 -0
  234. data/vendor/longfellow-zk/lib/gf2k/gf2_128_bench.cc +48 -0
  235. data/vendor/longfellow-zk/lib/gf2k/gf2_128_test.cc +416 -0
  236. data/vendor/longfellow-zk/lib/gf2k/gf2poly.h +74 -0
  237. data/vendor/longfellow-zk/lib/gf2k/lch14.h +242 -0
  238. data/vendor/longfellow-zk/lib/gf2k/lch14_bench.cc +75 -0
  239. data/vendor/longfellow-zk/lib/gf2k/lch14_reed_solomon.h +127 -0
  240. data/vendor/longfellow-zk/lib/gf2k/lch14_reed_solomon_test.cc +110 -0
  241. data/vendor/longfellow-zk/lib/gf2k/lch14_test.cc +246 -0
  242. data/vendor/longfellow-zk/lib/gf2k/sysdep.h +329 -0
  243. data/vendor/longfellow-zk/lib/ligero/ligero_param.h +449 -0
  244. data/vendor/longfellow-zk/lib/ligero/ligero_prover.h +354 -0
  245. data/vendor/longfellow-zk/lib/ligero/ligero_test.cc +136 -0
  246. data/vendor/longfellow-zk/lib/ligero/ligero_transcript.h +67 -0
  247. data/vendor/longfellow-zk/lib/ligero/ligero_verifier.h +272 -0
  248. data/vendor/longfellow-zk/lib/merkle/merkle_commitment.h +104 -0
  249. data/vendor/longfellow-zk/lib/merkle/merkle_tree.h +216 -0
  250. data/vendor/longfellow-zk/lib/merkle/merkle_tree_test.cc +240 -0
  251. data/vendor/longfellow-zk/lib/proto/circuit.h +354 -0
  252. data/vendor/longfellow-zk/lib/proto/circuit_test.cc +202 -0
  253. data/vendor/longfellow-zk/lib/random/random.h +119 -0
  254. data/vendor/longfellow-zk/lib/random/random_test.cc +189 -0
  255. data/vendor/longfellow-zk/lib/random/secure_random_engine.h +37 -0
  256. data/vendor/longfellow-zk/lib/random/transcript.h +193 -0
  257. data/vendor/longfellow-zk/lib/random/transcript_test.cc +344 -0
  258. data/vendor/longfellow-zk/lib/sumcheck/circuit.h +148 -0
  259. data/vendor/longfellow-zk/lib/sumcheck/circuit_id.h +71 -0
  260. data/vendor/longfellow-zk/lib/sumcheck/equad.h +126 -0
  261. data/vendor/longfellow-zk/lib/sumcheck/hquad.h +115 -0
  262. data/vendor/longfellow-zk/lib/sumcheck/prover.h +59 -0
  263. data/vendor/longfellow-zk/lib/sumcheck/prover_layers.h +362 -0
  264. data/vendor/longfellow-zk/lib/sumcheck/quad.h +227 -0
  265. data/vendor/longfellow-zk/lib/sumcheck/quad_builder.h +211 -0
  266. data/vendor/longfellow-zk/lib/sumcheck/quad_test.cc +169 -0
  267. data/vendor/longfellow-zk/lib/sumcheck/sumcheck_test.cc +324 -0
  268. data/vendor/longfellow-zk/lib/sumcheck/testing.h +69 -0
  269. data/vendor/longfellow-zk/lib/sumcheck/transcript_sumcheck.h +85 -0
  270. data/vendor/longfellow-zk/lib/sumcheck/verifier.h +84 -0
  271. data/vendor/longfellow-zk/lib/sumcheck/verifier_layers.h +221 -0
  272. data/vendor/longfellow-zk/lib/testing/test_main.cc +50 -0
  273. data/vendor/longfellow-zk/lib/util/ceildiv.h +164 -0
  274. data/vendor/longfellow-zk/lib/util/ceildiv_test.cc +152 -0
  275. data/vendor/longfellow-zk/lib/util/crc64.h +45 -0
  276. data/vendor/longfellow-zk/lib/util/crypto.cc +39 -0
  277. data/vendor/longfellow-zk/lib/util/crypto.h +108 -0
  278. data/vendor/longfellow-zk/lib/util/log.cc +110 -0
  279. data/vendor/longfellow-zk/lib/util/log.h +33 -0
  280. data/vendor/longfellow-zk/lib/util/panic.h +40 -0
  281. data/vendor/longfellow-zk/lib/util/readbuffer.h +67 -0
  282. data/vendor/longfellow-zk/lib/util/serialization.h +54 -0
  283. data/vendor/longfellow-zk/lib/zk/zk_common.h +455 -0
  284. data/vendor/longfellow-zk/lib/zk/zk_proof.h +378 -0
  285. data/vendor/longfellow-zk/lib/zk/zk_prover.h +202 -0
  286. data/vendor/longfellow-zk/lib/zk/zk_test.cc +340 -0
  287. data/vendor/longfellow-zk/lib/zk/zk_testing.h +154 -0
  288. data/vendor/longfellow-zk/lib/zk/zk_verifier.h +109 -0
  289. metadata +347 -0
@@ -0,0 +1,903 @@
1
+ // Copyright 2026 Google LLC.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #ifndef PRIVACY_PROOFS_ZK_LIB_CIRCUITS_TESTS_PQ_ML_DSA_ML_DSA_44_H_
16
+ #define PRIVACY_PROOFS_ZK_LIB_CIRCUITS_TESTS_PQ_ML_DSA_ML_DSA_44_H_
17
+
18
+ #include <array>
19
+ #include <cstddef>
20
+ #include <cstdint>
21
+ #include <vector>
22
+
23
+ #include "circuits/logic/memcmp.h"
24
+ #include "circuits/tests/pq/ml_dsa/ml_dsa_44_types.h"
25
+ #include "circuits/tests/sha3/sha3_circuit.h"
26
+
27
+ namespace proofs {
28
+
29
+ // ----------------------------------------------------------------------------
30
+ //
31
+ // !!!!! DO NOT USE IN PRODUCTION !!!!!
32
+ //
33
+ // This ML-DSA circuit is an experimental implementation for research purposes.
34
+ // It has not been fully vetted and is not recommended for production use cases
35
+ // at this time.
36
+ //
37
+ // ML-DSA is specified in
38
+ //
39
+ // FIPS 204
40
+ // Federal Information Processing Standards Publication
41
+ // Module-Lattice-Based Digital
42
+ // Signature Standard
43
+ // https://csrc.nist.gov/pubs/fips/204/final
44
+ //
45
+ // A public key in the system is a pair (rho, t1).
46
+ //
47
+ // The value rho is used to derive the pk matrix A \in R_q^{k x l}.
48
+ // The matrix T = A.s_1 + s_2 in R_q^k, and t1 is a rounded version of T.
49
+ // The hint h \in R_2^k.
50
+ //
51
+ // These operations are performed outside of the circuit and
52
+ // used as inputs for the Verifier.
53
+ // rho, t1 = _unpack_pk(pk)
54
+ // A_hat = _expand_matrix_from_seed(rho)
55
+ // tr = _h(pk, 64) # 64-byte hash of the public key
56
+ // t1 = t1.scale(1 << self.d)
57
+ // t1 = t1.to_ntt()
58
+ // 1. (rho, t1) = pkDecode(pk)
59
+ // Decode public key bytes.
60
+ // rho: 32-byte seed for generating matrix A.
61
+ // t1: Vector of 4 polynomials in R_q (k=4).
62
+ // Represents the high bits of A*s + t.
63
+
64
+ // 2. (c_tilde, z, h) = sigDecode(sigma) [ALWAYS PRIVATE]
65
+ // Decode signature bytes.
66
+ // c_tilde: 32-byte hash commitment (the "challenge" seed).
67
+ // z: Vector of 4 polynomials in R_q (l=4). The masked secret vector.
68
+ // h: Vector of 4 polynomials in R_q (k=4). The hint vector used to
69
+ // recover high bits.
70
+ // 3. IF h is INVALID (e.g., decoding failed or malformed) THEN
71
+ // RETURN False
72
+ // END IF
73
+
74
+ // 4. A_hat = ExpandA(rho)
75
+ // Expand the public matrix A from the seed rho.
76
+ // A_hat: 4x4 Matrix of polynomials in R_q (k=4, l=4).
77
+ // Note: The matrix is generated and stored directly in NTT (Number
78
+ // Theoretic Transform) representation.
79
+ // ----------------------------------------------------------------------------
80
+
81
+ template <class LogicCircuit, class Field>
82
+ class MLDSA44Verify {
83
+ using v6 = typename LogicCircuit::template bitvec<6>;
84
+ using v8 = typename LogicCircuit::v8;
85
+ using v10 = typename LogicCircuit::template bitvec<10>;
86
+ using v16 = typename LogicCircuit::template bitvec<16>;
87
+ using v19 = typename LogicCircuit::template bitvec<19>;
88
+ using v64 = typename LogicCircuit::v64;
89
+ using EltW = typename LogicCircuit::EltW;
90
+ using Elt = typename Field::Elt;
91
+ using BitW = typename LogicCircuit::BitW;
92
+ using BlockWitness = typename Sha3Circuit<LogicCircuit>::BlockWitness;
93
+
94
+ public:
95
+ struct RqW {
96
+ std::array<EltW, ml_dsa::N> coeffs;
97
+
98
+ void input(const LogicCircuit& lc) {
99
+ for (size_t i = 0; i < ml_dsa::N; ++i) {
100
+ coeffs[i] = lc.eltw_input();
101
+ }
102
+ }
103
+ };
104
+
105
+ struct MatrixAW {
106
+ std::array<std::array<RqW, ml_dsa::L>, ml_dsa::K> mat;
107
+
108
+ void input(const LogicCircuit& lc) {
109
+ for (size_t r = 0; r < ml_dsa::K; ++r) {
110
+ for (size_t c = 0; c < ml_dsa::L; ++c) {
111
+ mat[r][c].input(lc);
112
+ }
113
+ }
114
+ }
115
+ };
116
+
117
+ struct Pk {
118
+ MatrixAW a_hat;
119
+ std::array<RqW, ml_dsa::K> nttt1;
120
+ std::array<v8, 64> tr;
121
+
122
+ void input(const LogicCircuit& lc) {
123
+ a_hat.input(lc);
124
+ for (size_t i = 0; i < ml_dsa::K; ++i) {
125
+ nttt1[i].input(lc);
126
+ }
127
+ for (size_t i = 0; i < 64; ++i) {
128
+ tr[i] = lc.template vinput<8>();
129
+ }
130
+ }
131
+ };
132
+
133
+ struct SignatureW {
134
+ std::array<v8, 32> c_tilde;
135
+ std::array<RqW, ml_dsa::L> z;
136
+ // 19 bits per coefficient for z to cover 2 * GAMMA_1 (gamma_1 = 131072,
137
+ // so 262144 range fits in 19 bits max)
138
+ std::array<std::array<v19, ml_dsa::N>, ml_dsa::L> z_bits;
139
+ std::array<RqW, ml_dsa::K> h;
140
+
141
+ void input(const LogicCircuit& lc) {
142
+ for (size_t i = 0; i < 32; ++i) {
143
+ c_tilde[i] = lc.template vinput<8>();
144
+ }
145
+ for (size_t i = 0; i < ml_dsa::L; ++i) {
146
+ z[i].input(lc);
147
+ }
148
+ for (size_t i = 0; i < ml_dsa::L; ++i) {
149
+ for (size_t j = 0; j < ml_dsa::N; ++j) {
150
+ z_bits[i][j] = lc.template vinput<19>();
151
+ }
152
+ }
153
+ for (size_t i = 0; i < ml_dsa::K; ++i) {
154
+ h[i].input(lc);
155
+ }
156
+ }
157
+ };
158
+
159
+ struct SampleInBallWitness {
160
+ BlockWitness shake_bws;
161
+ std::array<v8, ml_dsa::TAU> j_vals;
162
+ std::array<v16, ml_dsa::TAU> j_k_indices;
163
+ std::vector<std::vector<v8>> position_trace;
164
+
165
+ void input(const LogicCircuit& lc) {
166
+ for (size_t i = 0; i < ml_dsa::TAU; ++i) {
167
+ j_vals[i] = lc.template vinput<8>();
168
+ j_k_indices[i] = lc.template vinput<16>();
169
+ }
170
+ shake_bws.input(lc);
171
+ // Note: position_trace is sized by caller.
172
+ if (position_trace.empty()) {
173
+ position_trace.resize(ml_dsa::TAU);
174
+ }
175
+ for (size_t s = 0; s < ml_dsa::TAU; ++s) {
176
+ if (position_trace[s].size() != s + 1) {
177
+ position_trace[s].resize(s + 1);
178
+ }
179
+ for (size_t k = 0; k <= s; ++k) {
180
+ position_trace[s][k] = lc.template vinput<8>();
181
+ }
182
+ }
183
+ }
184
+ };
185
+
186
+ class Witness {
187
+ public:
188
+ SampleInBallWitness sample_in_ball_;
189
+ RqW c_;
190
+ RqW w_prime_approx_[ml_dsa::K];
191
+ RqW w1_[ml_dsa::K];
192
+ std::array<std::array<v19, ml_dsa::N>, ml_dsa::K> hint_aux_bits_;
193
+ RqW w_prime_1_[ml_dsa::K];
194
+ std::array<std::array<v6, ml_dsa::N>, ml_dsa::K> w_prime_1_bits_;
195
+ std::array<RqW, ml_dsa::L> nttz_;
196
+ RqW nttc_;
197
+ std::array<v8, ml_dsa::K * 192> w1_tilde_;
198
+ std::vector<BlockWitness> c_prime_tilde_bws_;
199
+
200
+ void input(const LogicCircuit& lc) {
201
+ sample_in_ball_.input(lc);
202
+ c_.input(lc);
203
+ for (size_t i = 0; i < ml_dsa::K; ++i) {
204
+ w_prime_approx_[i].input(lc);
205
+ w1_[i].input(lc);
206
+ for (size_t j = 0; j < ml_dsa::N; ++j) {
207
+ hint_aux_bits_[i][j] = lc.template vinput<19>();
208
+ }
209
+ w_prime_1_[i].input(lc);
210
+ for (size_t j = 0; j < ml_dsa::N; ++j) {
211
+ w_prime_1_bits_[i][j] = lc.template vinput<6>();
212
+ }
213
+ }
214
+ for (size_t i = 0; i < ml_dsa::L; ++i) {
215
+ nttz_[i].input(lc);
216
+ }
217
+ nttc_.input(lc);
218
+ for (auto& w1 : w1_tilde_) {
219
+ w1 = lc.template vinput<8>();
220
+ }
221
+ for (auto& bw : c_prime_tilde_bws_) {
222
+ bw.input(lc);
223
+ }
224
+ }
225
+ };
226
+
227
+ void matrix_vector_mul(const MatrixAW& A, const std::array<RqW, ml_dsa::L>& x,
228
+ std::array<RqW, ml_dsa::K>& y) const {
229
+ for (size_t i = 0; i < ml_dsa::K; ++i) {
230
+ for (size_t c = 0; c < ml_dsa::N; ++c) {
231
+ y[i].coeffs[c] = lc_.konst(lc_.f_.zero());
232
+ }
233
+ for (size_t j = 0; j < ml_dsa::L; ++j) {
234
+ for (size_t c = 0; c < ml_dsa::N; ++c) {
235
+ y[i].coeffs[c] = lc_.add(
236
+ y[i].coeffs[c], lc_.mul(A.mat[i][j].coeffs[c], x[j].coeffs[c]));
237
+ }
238
+ }
239
+ }
240
+ }
241
+
242
+ void scalar_vector_mul(const RqW& c, const std::array<RqW, ml_dsa::K>& x,
243
+ std::array<RqW, ml_dsa::K>& y) const {
244
+ for (size_t i = 0; i < ml_dsa::K; ++i) {
245
+ for (size_t k = 0; k < ml_dsa::N; ++k) {
246
+ y[i].coeffs[k] = lc_.mul(c.coeffs[k], x[i].coeffs[k]);
247
+ }
248
+ }
249
+ }
250
+
251
+ void assert_ntt(const RqW& c, const RqW& cprime) const {
252
+ std::vector<EltW> p(c.coeffs.begin(), c.coeffs.end());
253
+ int k = 1;
254
+ int length = ml_dsa::N / 2;
255
+ while (length > 0) {
256
+ for (int start = 0; start < ml_dsa::N; start += 2 * length) {
257
+ auto zeta = lc_.f_.of_scalar_field(ml_dsa::kZetas[k]);
258
+ auto neg_zeta = lc_.f_.negf(zeta);
259
+ k++;
260
+ for (int j = start; j < start + length; ++j) {
261
+ auto t = lc_.axpy(p[j], zeta, p[j + length]);
262
+ p[j + length] = lc_.axpy(p[j], neg_zeta, p[j + length]);
263
+ p[j] = t;
264
+ }
265
+ }
266
+ length /= 2;
267
+ }
268
+ for (size_t i = 0; i < ml_dsa::N; ++i) {
269
+ lc_.assert_eq(p[i], cprime.coeffs[i]);
270
+ }
271
+ }
272
+
273
+ void assert_inverse_ntt(const RqW& c, const RqW& cprime) const {
274
+ std::vector<EltW> p(c.coeffs.begin(), c.coeffs.end());
275
+ int k = 256;
276
+ int length = 1;
277
+ while (length < ml_dsa::N) {
278
+ for (int start = 0; start < ml_dsa::N; start += 2 * length) {
279
+ k--;
280
+ auto neg_zeta = lc_.f_.negf(lc_.f_.of_scalar_field(ml_dsa::kZetas[k]));
281
+ for (int j = start; j < start + length; ++j) {
282
+ auto t = p[j];
283
+ p[j] = lc_.add(t, p[j + length]);
284
+ auto diff = lc_.sub(t, p[j + length]);
285
+ p[j + length] = lc_.mul(neg_zeta, diff);
286
+ }
287
+ }
288
+ length *= 2;
289
+ }
290
+
291
+ // Multiply by 256^(-1) mod q = 8347681
292
+ auto f = lc_.konst(lc_.f_.of_scalar_field(8347681u));
293
+ for (size_t i = 0; i < ml_dsa::N; ++i) {
294
+ p[i] = lc_.mul(f, p[i]);
295
+ lc_.assert_eq(p[i], cprime.coeffs[i]);
296
+ }
297
+ }
298
+
299
+ explicit MLDSA44Verify(const LogicCircuit& lc) : lc_(lc) {}
300
+
301
+ // Validates the "UseHint" operation for a single coefficient, ensuring that
302
+ // the high bits `w_prime_1` are correctly derived from the approximate high
303
+ // bits `w_prime_approx` and the hint `h` according to FIPS 204.
304
+ //
305
+ // FIPS UseHint(h, r) Standard Logic:
306
+ // 1. Decompose `r = r1 * 2*gamma2 + r0` where `-gamma2 < r0 <= gamma2`.
307
+ // 2. If `h == 1` and `r0 > 0`, return `(r1 + 1) mod 44`.
308
+ // 3. If `h == 1` and `r0 <= 0`, return `(r1 - 1) mod 44`.
309
+ // 4. If `h == 0`, return `r1`.
310
+ //
311
+ // Our Circuit Optimization:
312
+ // This function uses an optimized algorithm (interval shifting) that offloads
313
+ // the computation of the expected answer `hinted_r1` to the prover and
314
+ // requires ONLY ONE range check.
315
+ //
316
+ // Specifically, this function asserts:
317
+ // 1. Shift Indicator `c` derivation:
318
+ // - Extracts the 19th bit of `hint_r0_bits_elt` as a sign bit `s`.
319
+ // - Compute `c = h * (1 - 2*s)`. This maps `h=0 -> c=0`, and `h=1 -> c
320
+ // \in {-1, 1}`.
321
+ // - This carefully aligns with the FIPS standard constraints: if the hint
322
+ // `h` is 1, `c` will tell us whether we are shifting `r1` by +1
323
+ // (`c=1`, because `r0 > 0`) or by -1 (`c=-1`, because `r0 <= 0`).
324
+ // If `h = 0`, no shift applies (`c=0`).
325
+ //
326
+ // 2. Decomposition and Range check for `r0`:
327
+ // - The approximated value `r` decomposes into `r1` and `r0` such that:
328
+ // `r0 = r - r1 * 2*gamma2`
329
+ // - If we follow the standard, `r0` must lie in `(-gamma2, gamma2]`.
330
+ // - Instead of range-checking `r0` over this signed interval, we assert
331
+ // that `r0_shifted = r0 - c * 2*gamma2 + (gamma2 - 1)` must lie
332
+ // strictly in `[0, 2*gamma2 - 1]`.
333
+ // - By adding `(gamma2 - 1)`, we functionally shift the legitimate range
334
+ // to be strictly non-negative.
335
+ // - By subtracting `c * 2*gamma2`, we logically enforce the explicit FIPS
336
+ // boundaries on `r0` depending on `c`:
337
+ // - If `c = 1` (`r1` shifts +1), then `r0` MUST have been `> 0`.
338
+ // - If `c = -1` (`r1` shifts -1), then `r0` MUST have been `<= 0`.
339
+ // - This requires only one range check by reconstructing `r0_shifted` from
340
+ // the first 18 bits of `hint_r0_bits_elt` and bounds checking `r0_shifted
341
+ // <= 2*gamma2 - 1`.
342
+ //
343
+ // 3. Modulo check on computed `hinted_r1`:
344
+ // - Verifies that `hinted_r1` is indeed congruent to the raw (unmoduloed)
345
+ // shift `r1 + c` meaning `(r1 + c - hinted_r1) \in {0, 44, -44}`.
346
+ //
347
+ // 4. Range check on `hinted_r1` bounds:
348
+ // - `hinted_r1` is the final answer supplied by the prover.
349
+ // - It is explicitly reconstructed from boolean bits `r1_bits_elt`
350
+ // matching bounded `[0, 43]`.
351
+ void assert_use_hint_single(const EltW& h_elt, const EltW& r_elt,
352
+ const EltW& r1_raw, const v19& hint_r0_bits_elt,
353
+ const EltW& hinted_r1,
354
+ const v6& r1_bits_elt) const {
355
+ auto two_gamma2 = lc_.konst(lc_.f_.of_scalar(2 * ml_dsa::GAMMA_2));
356
+ auto shift_val = lc_.konst(lc_.f_.of_scalar(ml_dsa::GAMMA_2 - 1));
357
+ EltW zero = lc_.konst(lc_.f_.zero());
358
+ EltW one = lc_.konst(lc_.f_.one());
359
+
360
+ lc_.assert_is_bit(h_elt);
361
+
362
+ // 1. Reconstruct R and extract sign bit s
363
+ EltW r0_shifted = lc_.konst(lc_.f_.zero());
364
+ Elt p = lc_.f_.one();
365
+ Elt two = lc_.f_.two();
366
+ for (size_t b = 0; b < 18; ++b) {
367
+ EltW bit_val = lc_.mux(hint_r0_bits_elt[b], one, zero);
368
+ r0_shifted = lc_.axpy(r0_shifted, p, bit_val);
369
+ p = lc_.f_.mulf(p, two);
370
+ }
371
+
372
+ // Check R <= 2*GAMMA_2 - 1 (18 bits since 2*GAMMA_2 - 1 = 190463 < 2^18)
373
+ auto max_bound = lc_.template vbit<18>(2 * ml_dsa::GAMMA_2 - 1);
374
+ auto is_leq_max = lc_.leq(18, hint_r0_bits_elt.data(), max_bound.data());
375
+ lc_.assert1(is_leq_max);
376
+
377
+ // Extract s as the 19th bit
378
+ BitW s_bit = hint_r0_bits_elt[18];
379
+
380
+ // Compute c = h * (1 - 2*s) -> If s=1, c = -h; else c = h.
381
+ EltW neg_h = lc_.sub(zero, h_elt);
382
+ EltW c_elt = lc_.mux(s_bit, neg_h, h_elt);
383
+
384
+ // In UseHint, delta is exactly r0. There is no +/- 2*gamma2 shifted bounds.
385
+ // delta = R - (gamma2 - 1)
386
+ EltW delta = lc_.sub(r0_shifted, shift_val);
387
+
388
+ // Verify r_elt == r1_elt * 2*GAMMA_2 + delta
389
+ EltW term1 = lc_.mul(r1_raw, two_gamma2);
390
+ EltW val = lc_.add(term1, delta);
391
+ lc_.assert_eq(r_elt, val);
392
+
393
+ // 3. Verify r1_recon range [0, 43]
394
+ EltW r1_recon = lc_.konst(lc_.f_.zero());
395
+ p = lc_.f_.one();
396
+ for (size_t b = 0; b < 6; ++b) {
397
+ EltW bit_val = lc_.mux(r1_bits_elt[b], one, zero);
398
+ r1_recon = lc_.axpy(r1_recon, p, bit_val);
399
+ p = lc_.f_.mulf(p, two);
400
+ }
401
+ lc_.assert_eq(hinted_r1, r1_recon);
402
+ auto r1_bound = lc_.template vbit<6>(43);
403
+ auto is_w1_valid = lc_.leq(6, r1_bits_elt.data(), r1_bound.data());
404
+ lc_.assert1(is_w1_valid);
405
+
406
+ // 4. Verify hinted_r1 == r1_raw - c modulo 44
407
+ EltW diff = lc_.sub(r1_raw, hinted_r1);
408
+ EltW true_shift_diff = lc_.add(diff, c_elt);
409
+
410
+ EltW m = lc_.konst(lc_.f_.of_scalar(44));
411
+ EltW diff_minus_44 = lc_.sub(true_shift_diff, m);
412
+ EltW diff_plus_44 = lc_.add(true_shift_diff, m);
413
+
414
+ EltW prod1 = lc_.mul(true_shift_diff, diff_minus_44);
415
+ EltW prod2 = lc_.mul(prod1, diff_plus_44);
416
+ lc_.assert0(prod2);
417
+ }
418
+
419
+ void assert_use_hint(
420
+ const std::array<RqW, ml_dsa::K>& h,
421
+ const RqW (&w_prime_approx)[ml_dsa::K], const RqW (&w1)[ml_dsa::K],
422
+ const std::array<std::array<v19, ml_dsa::N>, ml_dsa::K>& hint_aux_bits,
423
+ const RqW (&w_prime_1)[ml_dsa::K],
424
+ const std::array<std::array<v6, ml_dsa::N>, ml_dsa::K>& w_prime_1_bits)
425
+ const {
426
+ for (size_t i = 0; i < ml_dsa::K; ++i) {
427
+ for (size_t k = 0; k < ml_dsa::N; ++k) {
428
+ assert_use_hint_single(h[i].coeffs[k], w_prime_approx[i].coeffs[k],
429
+ w1[i].coeffs[k], hint_aux_bits[i][k],
430
+ w_prime_1[i].coeffs[k], w_prime_1_bits[i][k]);
431
+ }
432
+ }
433
+ }
434
+
435
+ // Verifies that the infinity norm of the polynomial vector `vec` is within
436
+ // the specified `bound`. This function checks that each coefficient `c` of
437
+ // `vec` satisfies `-bound <= c < bound` (i.e., `c \in [-bound, bound - 1]`).
438
+ //
439
+ // The verification is performed using a provided bit-decomposition `vec_bits`
440
+ // for each coefficient. The steps are:
441
+ // 1. Reconstruct a value `r` from `vec_bits` such that `r = sum(bits * 2^k)`.
442
+ // This `r` represents the shifted coefficient `c + bound`.
443
+ // 2. Assert that `vec[i][j] + bound == r`. This ensures that the
444
+ // bit-decomposition `vec_bits` corresponds to the coefficient `vec[i][j]`
445
+ // shifted by `bound`.
446
+ // 3. Assert that `r <= 2 * bound - 1`. Since `r` is non-negative (from bits),
447
+ // this enforces `0 <= c + bound <= 2 * bound - 1`, which simplifies to
448
+ // `-bound <= c <= bound - 1`.
449
+ template <size_t SIZE, size_t BIT_WIDTH>
450
+ void assert_infty_norm(
451
+ const std::array<RqW, SIZE>& vec,
452
+ const std::array<
453
+ std::array<typename LogicCircuit::template bitvec<BIT_WIDTH>,
454
+ ml_dsa::N>,
455
+ SIZE>& vec_bits,
456
+ uint64_t bound) const {
457
+ const Memcmp<LogicCircuit> CMP(lc_);
458
+
459
+ Elt two = lc_.f_.two();
460
+ for (size_t i = 0; i < SIZE; ++i) {
461
+ for (size_t j = 0; j < ml_dsa::N; ++j) {
462
+ // 1. Reconstruct the shifted value from bit witnesses
463
+ EltW r = lc_.konst(lc_.f_.zero());
464
+ Elt p = lc_.f_.one();
465
+ for (size_t b = 0; b < BIT_WIDTH; ++b) {
466
+ EltW bit_val = lc_.eval(vec_bits[i][j][b]);
467
+ r = lc_.axpy(r, p, bit_val);
468
+ p = lc_.f_.mulf(p, two);
469
+ }
470
+
471
+ // 2. Check that the reconstructed (shifted) value matches the
472
+ // original value shifted by bound.
473
+ // vec[i].coeffs[j] + bound == reconstructed.
474
+ EltW shifted_original =
475
+ lc_.add(vec[i].coeffs[j], lc_.konst(lc_.f_.of_scalar(bound)));
476
+ lc_.assert_eq(shifted_original, r);
477
+
478
+ // 3. Verify inequality constraint (reconstructed < 2*bound + 1) ->
479
+ // reconstructed <= 2*bound.The shifted value must fall in [1, 2*bound -
480
+ // 1]. Hence, vec_bits[i][j] <= 2*bound - 1.
481
+ auto is_leq =
482
+ lc_.leq(BIT_WIDTH, vec_bits[i][j].data(),
483
+ lc_.template vbit<BIT_WIDTH>(2 * bound - 1).data());
484
+ lc_.assert1(is_leq);
485
+ }
486
+ }
487
+ }
488
+
489
+ // Verifies the `w1Encode` operation, which serializes the polynomial vector
490
+ // `w_prime_1` into a byte array. This byte array is subsequently used to
491
+ // hash (along with `mu`) and validate the signature challenge `c_tilde`.
492
+ //
493
+ // The encoding constraints are structured and validated as follows:
494
+ // 1. **Bit Extraction**:
495
+ // - Each coefficient in `w_prime_1` is bounded in `[0, 43]` and is
496
+ // fully represented using exactly 6 bits.
497
+ // - The method iterates through all `K` polynomials and all `N` (256)
498
+ // coefficients, extracting the lowest 6 bits of each coefficient.
499
+ // - These bits are concatenated into a flat array of `K * N * 6` bits.
500
+ // 2. **Byte Packing (SimpleBitPack)**:
501
+ // - The bit array is partitioned into 8-bit subsets to form bytes.
502
+ // - As required by FIPS 204 Algorithm 18 (`SimpleBitPack`), bits are
503
+ // packed in little-endian order, meaning the first bit of each subset
504
+ // is bound to the Least Significant Bit (LSB) of the output byte.
505
+ // 3. **Padding Constraints**:
506
+ // - The algorithm enforces that if the total bit count is not perfectly
507
+ // divisible by 8, any residual bits making up the final byte are
508
+ // constrained to zero-wires (`lc_.bit(0)`).
509
+ void assert_w1_encode(
510
+ const std::array<std::array<v6, ml_dsa::N>, ml_dsa::K>& w_prime_1_bits,
511
+ const std::array<v8, ml_dsa::K * 192>& putative_w1_tilde) const {
512
+ // Each coefficient in w_prime_1 used 6 bits.
513
+ // We construct the byte representation directly from these bits.
514
+ // bitlen = 6.
515
+ size_t bitlen = 6;
516
+ size_t total_bytes = ml_dsa::K * 192;
517
+
518
+ // Gather all 6*256*K bits into a big vector, then split.
519
+ std::vector<BitW> all_bits;
520
+ all_bits.reserve(ml_dsa::K * ml_dsa::N * bitlen);
521
+
522
+ for (size_t k = 0; k < ml_dsa::K; ++k) {
523
+ for (size_t i = 0; i < ml_dsa::N; ++i) {
524
+ for (size_t b = 0; b < bitlen; ++b) {
525
+ all_bits.push_back(w_prime_1_bits[k][i][b]);
526
+ }
527
+ }
528
+ }
529
+
530
+ for (size_t i = 0; i < total_bytes; ++i) {
531
+ // FIPS 204 Algorithm 18 SimpleBitPack:
532
+ // z[byte_idx] |= (1 << bit_idx) where bit_idx is pos % 8.
533
+ v8 byte_val;
534
+ for (size_t b = 0; b < 8; ++b) {
535
+ if (i * 8 + b < all_bits.size()) {
536
+ byte_val[b] = all_bits[i * 8 + b];
537
+ } else {
538
+ byte_val[b] = lc_.bit(0);
539
+ }
540
+ }
541
+ lc_.vassert_eq(putative_w1_tilde[i], byte_val);
542
+ }
543
+ }
544
+
545
+ // Verifies the "SampleInBall" operation, which generates a sparse polynomial
546
+ // `c` with coefficients in {-1, 0, 1} and exactly `TAU` non-zero
547
+ // coefficients. This corresponds to Algorithm 29 in FIPS 204.
548
+ //
549
+ // 4: (ctx, s) <- H.Squeeze(ctx, 8)
550
+ // 5: h <- BytesToBits(s) # 64 bits for -1,1
551
+ // 6: for i from 256 - TAU to 255 do
552
+ // 7: (ctx, j) <- H.Squeeze(ctx, 1)
553
+ // 8: while j > i do # rejection sampling in {0, … , i}
554
+ // 9: (ctx, j) <- H.Squeeze(ctx, 1)
555
+ // 10: end while # j is a pseudorandom byte that is ≤ i
556
+ // 11: c_i <- c_j
557
+ // 12: c_j <- (-1)^h[i + TAU - 256]
558
+ // 13: end for
559
+ //
560
+ // The function validates the generation of `c` from the seed `rho`:
561
+ // 1. **SHAKE256**: Computes 272b of SHAKE256 output `out` from `rho`.
562
+ // 2. **Rejection Sampling Verification**: The algorithm picks `TAU` indices
563
+ // `j` using rejection sampling from `out` (starting at byte 8). For each
564
+ // step `s` (target index `i = 256 - TAU + s`):
565
+ // - The witness provides the index `k_idx` in `out` where a valid sample
566
+ // `j` was found.
567
+ // - **Validation**:
568
+ // - `out[k_idx] == j`: verifies the witness `j` matches the SHAKE
569
+ // output.
570
+ // - `j <= i`: verifies the sample is within the valid range for the
571
+ // swap.
572
+ // - For all `k` such that `prev_k_index <= k < k_idx`: verifies `out[k]
573
+ // > i`.
574
+ // This ensures that all skipped bytes were legitimately rejected
575
+ // because they were out of range.
576
+ //
577
+ // 3. **Shuffle Trace Verification (Parallel)**:
578
+ // - Instead of sequentially updating the polynomial `c`, we verify a
579
+ // "trace" of the shuffle positions witnessed by
580
+ // `witness.position_trace`.
581
+ // - For each step `s`, we verify that `position_trace[s]` is correctly
582
+ // derived from `position_trace[s-1]` by swapping the element at `j` with
583
+ // `i`.
584
+ // - This allows all `s` steps to be verified in parallel, reducing the
585
+ // circuit depth from O(TAU) to O(1) (relative to the shuffle steps).
586
+ //
587
+ // 4. **Final Polynomial Construction**:
588
+ // - Constructs the expected polynomial `c` from the final positions in
589
+ // `position_trace[TAU-1]`.
590
+ // - For each coefficient index `k`, we sum the contributions from all `s`
591
+ // (where `final_pos[s] == k`).
592
+ // - `c[k] = sum_{s} (final_pos[s] == k ? (-1)^sign_s : 0)`.
593
+ // - Asserts that `cprime` matches this constructed `c`.
594
+ void assert_sample_in_ball(const std::array<v8, 32>& rho, const RqW& cprime,
595
+ const SampleInBallWitness& witness) const {
596
+ // 1. Compute SHAKE256 on rho
597
+ Sha3Circuit<LogicCircuit> sha3(lc_);
598
+ std::vector<v8> out;
599
+ std::vector<v8> rho_vec(rho.begin(), rho.end());
600
+ size_t out_bytes = 136;
601
+ std::vector<BlockWitness> bws;
602
+ bws.push_back(witness.shake_bws);
603
+ sha3.assert_shake256(rho_vec, out_bytes, out, bws);
604
+
605
+ // 2. Verification of Rejection Sampling (j values)
606
+ v16 prev_k_index = lc_.template vbit<16>(8); // out_idx starts at 8
607
+
608
+ for (size_t s = 0; s < ml_dsa::TAU; ++s) {
609
+ size_t i = 256 - ml_dsa::TAU + s;
610
+ const v8& j = witness.j_vals[s];
611
+ const v16& k_idx = witness.j_k_indices[s];
612
+
613
+ // Enforce the out_idx is increasing
614
+ auto is_increasing = lc_.vleq(prev_k_index, k_idx);
615
+ lc_.assert1(is_increasing);
616
+
617
+ // Verify j <= i
618
+ v16 j_ext;
619
+ for (size_t k = 0; k < 8; ++k) j_ext[k] = j[k];
620
+ for (size_t k = 8; k < 16; ++k) j_ext[k] = lc_.bit(0);
621
+
622
+ v16 i_vec = lc_.template vbit<16>(i);
623
+ auto j_valid = lc_.vleq(j_ext, i_vec);
624
+ lc_.assert1(j_valid);
625
+
626
+ // Verify out[k_idx] == j and skipped values > i
627
+ for (size_t k = 0; k < out.size(); ++k) {
628
+ v16 curr_k = lc_.template vbit<16>(k);
629
+ auto is_target = lc_.veq(curr_k, k_idx);
630
+
631
+ // If k == k_idx, then out[k] == j
632
+ auto match_val = lc_.veq(out[k], j);
633
+ lc_.assert_implies(is_target, match_val);
634
+
635
+ // If prev_k_index <= k < k_idx, then out[k] > i
636
+ auto gt_prev = lc_.vleq(prev_k_index, curr_k);
637
+ auto lt_target = lc_.vlt(curr_k, k_idx);
638
+ auto in_range = lc_.land(gt_prev, lt_target);
639
+
640
+ v16 out_k_ext;
641
+ for (size_t b = 0; b < 8; ++b) out_k_ext[b] = out[k][b];
642
+ for (size_t b = 8; b < 16; ++b) out_k_ext[b] = lc_.bit(0);
643
+
644
+ auto rejected_val = lc_.vlt(i_vec, out_k_ext); // out[k] > i
645
+ lc_.assert_implies(in_range, rejected_val);
646
+ }
647
+ prev_k_index = lc_.vadd(k_idx, 1);
648
+ }
649
+
650
+ // 3. Verify Shuffle Trace (Parallel)
651
+ // Step s=0
652
+ lc_.vassert_eq(witness.position_trace[0][0], witness.j_vals[0]);
653
+
654
+ for (size_t s = 1; s < ml_dsa::TAU; ++s) {
655
+ size_t i = 256 - ml_dsa::TAU + s;
656
+ const v8& j = witness.j_vals[s];
657
+
658
+ const auto& prev_pos = witness.position_trace[s - 1];
659
+ const auto& curr_pos = witness.position_trace[s];
660
+
661
+ // Assert curr_pos[s] == j
662
+ lc_.vassert_eq(curr_pos[s], j);
663
+
664
+ // Parallel checks for k < s
665
+ for (size_t k = 0; k < s; ++k) {
666
+ const auto& p = prev_pos[k];
667
+ auto is_j = lc_.veq(p, j);
668
+ // If p == j, update to i, else stay p
669
+ // vmux logic:
670
+ v8 i_v = lc_.template vbit<8>(i);
671
+ v8 target;
672
+ for (size_t b = 0; b < 8; ++b) {
673
+ target[b] = lc_.mux(is_j, i_v[b], p[b]);
674
+ }
675
+ lc_.vassert_eq(curr_pos[k], target);
676
+ }
677
+ }
678
+
679
+ // 4. Verify cprime against final trace
680
+ const auto& final_pos = witness.position_trace[ml_dsa::TAU - 1];
681
+ EltW one = lc_.konst(lc_.f_.one());
682
+ EltW mone = lc_.konst(lc_.f_.mone());
683
+ EltW zero = lc_.konst(lc_.f_.zero());
684
+
685
+ // Pre-calculate expected values for each position in the trace
686
+ std::vector<EltW> trace_vals(ml_dsa::TAU);
687
+ for (size_t s = 0; s < ml_dsa::TAU; ++s) {
688
+ size_t bit_idx = s;
689
+ size_t byte_idx = bit_idx / 8;
690
+ size_t bit_shift = bit_idx % 8;
691
+ auto sign_bit = out[byte_idx][bit_shift];
692
+ trace_vals[s] = lc_.mux(sign_bit, mone, one);
693
+ }
694
+
695
+ // Full Construction Check:
696
+ // c[k] = sum_{s} (final_pos[s] == k ? trace_vals[s] : 0)
697
+ for (size_t k = 0; k < ml_dsa::N; ++k) {
698
+ v8 k_v = lc_.template vbit<8>(k);
699
+
700
+ // We sum up contributions from all s.
701
+ // Since final_pos distinct, at most one s contributes.
702
+ // We can use a linear sum or tree sum.
703
+ // logic.h add(i0, i1, func) checks range.
704
+ // We can use lc_.add(0, TAU, ...)
705
+ EltW val_k = lc_.add(0, ml_dsa::TAU, [&](size_t s) {
706
+ auto is_match = lc_.veq(final_pos[s], k_v);
707
+ return lc_.mux(is_match, trace_vals[s], zero);
708
+ });
709
+
710
+ lc_.assert_eq(cprime.coeffs[k], val_k);
711
+ }
712
+ }
713
+
714
+ std::vector<v8> prepare_mu_input(const std::array<v8, 64>& tr, const v8* msg,
715
+ size_t len) const {
716
+ // 2. Prepare the full input: tr || msg || padding.
717
+ // Maximum size: 64 + 650 = 714 bytes.
718
+ // Block size: 136 bytes.
719
+
720
+ std::vector<v8> input_bytes;
721
+ input_bytes.reserve(64 + len + 2); // +2 for padding
722
+ for (size_t i = 0; i < 64; ++i) input_bytes.push_back(tr[i]);
723
+ for (size_t i = 0; i < len; ++i) input_bytes.push_back(msg[i]);
724
+
725
+ // Padding for SHAKE256: append 0x1F, then … then 0x80 at end of block.
726
+ // Formula: Pad with 10*1.
727
+ // First byte 0x1F (0001 1111) handles "4 bits domain + 1 bit pad start".
728
+ auto pad1 = lc_.template vbit<8>(0x1F);
729
+ input_bytes.push_back(pad1);
730
+
731
+ // We must pad with zeros until we reach block boundary - 1.
732
+ size_t rate = 136;
733
+ size_t current_len = input_bytes.size();
734
+ size_t zero_pad_len = rate - (current_len % rate);
735
+ if (zero_pad_len == 0) zero_pad_len = rate;
736
+
737
+ // We append (zero_pad_len - 1) zero bytes.
738
+ auto zero = lc_.template vbit<8>(0);
739
+ for (size_t i = 0; i < zero_pad_len - 1; ++i) {
740
+ input_bytes.push_back(zero);
741
+ }
742
+
743
+ // Last byte is 0x80.
744
+ auto pad2 = lc_.template vbit<8>(0x80);
745
+ input_bytes.push_back(pad2);
746
+
747
+ // Now input_bytes size should be multiple of rate.
748
+ check(input_bytes.size() % rate == 0, "Padding failed");
749
+ return input_bytes;
750
+ }
751
+ void assert_mu(const std::array<v8, 64>& tr, const v8* msg, size_t len,
752
+ const std::vector<BlockWitness>& mu_bws,
753
+ const std::array<v8, 64>& mu) const {
754
+ Sha3Circuit<LogicCircuit> sha3(lc_);
755
+ using v64 = typename LogicCircuit::template bitvec<64>;
756
+ v64 A[5][5];
757
+ for (int x = 0; x < 5; ++x) {
758
+ for (int y = 0; y < 5; ++y) {
759
+ A[x][y] = lc_.template vbit<64>(0);
760
+ }
761
+ }
762
+
763
+ std::vector<v8> input_bytes = prepare_mu_input(tr, msg, len);
764
+ size_t rate = 136;
765
+ size_t num_blocks = input_bytes.size() / rate;
766
+
767
+ // Absorb
768
+ size_t input_idx = 0;
769
+ size_t bw_idx = 0;
770
+
771
+ for (size_t b_idx = 0; b_idx < num_blocks; ++b_idx) {
772
+ // XOR block into state
773
+ size_t x = 0, y = 0;
774
+ for (size_t i = 0; i < rate; i += 8) {
775
+ v64 a;
776
+ for (size_t b = 0; b < 8; ++b) {
777
+ // Reconstruct v64 from 8 v8s (Little Endian)
778
+ for (size_t j = 0; j < 8; ++j) {
779
+ if (i + b < rate) {
780
+ a[b * 8 + j] = input_bytes[input_idx + i + b][j];
781
+ }
782
+ }
783
+ }
784
+ A[x][y] = lc_.vxor(A[x][y], a);
785
+ ++x;
786
+ if (x == 5) {
787
+ ++y;
788
+ x = 0;
789
+ }
790
+ }
791
+ input_idx += rate;
792
+
793
+ // Permute
794
+ check(bw_idx < mu_bws.size(), "Not enough BlockWitnesses for mu");
795
+ sha3.keccak_f_1600(A, mu_bws[bw_idx++]);
796
+ }
797
+
798
+ // Squeeze 64 bytes
799
+ std::vector<v8> squeezed(64);
800
+ size_t x = 0, y = 0;
801
+ for (size_t i = 0; i < 64; i += 8) {
802
+ for (size_t b = 0; b < 8; ++b) {
803
+ for (size_t j = 0; j < 8; ++j) {
804
+ squeezed[i + b][j] = A[x][y][b * 8 + j];
805
+ }
806
+ }
807
+ ++x;
808
+ if (x == 5) {
809
+ ++y;
810
+ x = 0;
811
+ }
812
+ }
813
+
814
+ // Assert match with witness.mu_
815
+ for (size_t i = 0; i < 64; ++i) {
816
+ for (size_t b = 0; b < 8; ++b) {
817
+ lc_.assert_eq(squeezed[i][b], mu[i][b]);
818
+ }
819
+ }
820
+ }
821
+
822
+ void assert_w_prime_approx(const Pk& pk, const SignatureW& sig,
823
+ const Witness& w) const {
824
+ for (size_t i = 0; i < ml_dsa::L; ++i) {
825
+ assert_ntt(sig.z[i], w.nttz_[i]);
826
+ }
827
+ assert_ntt(w.c_, w.nttc_);
828
+
829
+ std::array<RqW, ml_dsa::K> Az;
830
+ std::array<RqW, ml_dsa::K> ct1;
831
+ // Az = A_hat * nttz
832
+ matrix_vector_mul(pk.a_hat, w.nttz_, Az);
833
+ // ct1 = nttc * nttt1
834
+ scalar_vector_mul(w.nttc_, pk.nttt1, ct1);
835
+
836
+ for (size_t i = 0; i < ml_dsa::K; ++i) {
837
+ RqW diff;
838
+ for (size_t k = 0; k < ml_dsa::N; ++k) {
839
+ diff.coeffs[k] = lc_.sub(Az[i].coeffs[k], ct1[i].coeffs[k]);
840
+ }
841
+ assert_inverse_ntt(diff, w.w_prime_approx_[i]);
842
+ }
843
+ }
844
+
845
+ void assert_ctilde(const std::array<v8, 64>& mu,
846
+ const std::array<v8, ml_dsa::K * 192>& w_prime_1_bytes,
847
+ const std::vector<BlockWitness>& c_prime_tilde_bws,
848
+ const std::array<v8, 32>& c_tilde) const {
849
+ Sha3Circuit<LogicCircuit> sha3(lc_);
850
+
851
+ // Prepare input: mu || w_prime_1_bytes
852
+ // 192 * 4 + 64 = 832 bytes --> requires 7 blocks of shake.
853
+ std::vector<v8> input_bytes;
854
+ input_bytes.insert(input_bytes.end(), mu.begin(), mu.end());
855
+ input_bytes.insert(input_bytes.end(), w_prime_1_bytes.begin(),
856
+ w_prime_1_bytes.end());
857
+
858
+ std::vector<v8> squeezed(32);
859
+
860
+ sha3.assert_shake256(input_bytes, 32, squeezed, c_prime_tilde_bws);
861
+
862
+ // Assert match with c_tilde (from signature)
863
+ for (size_t i = 0; i < 32; ++i) {
864
+ lc_.vassert_eq(squeezed[i], c_tilde[i]);
865
+ }
866
+ }
867
+
868
+ // This method assumes that the 64b mu is verified externally.
869
+ void assert_valid_signature_on_mu(const Pk& pk, const SignatureW& sig,
870
+ const std::array<v8, 64>& mu,
871
+ const Witness& w) const {
872
+ // 7. c = SampleInBall(c_tilde)
873
+ // Generate the challenge c from the commitment c_tilde.
874
+ // c: R_q with small coefficients (weights +/- 1).
875
+ assert_sample_in_ball(sig.c_tilde, w.c_, w.sample_in_ball_);
876
+
877
+ // 8. Compute w'_Approx in the NTT domain.
878
+ // w_prime_approx = InverseNTT( A_hat o NTT(z) - NTT(c) o NTT(t1 * 2^d) )
879
+ // w_prime_approx: Vector of 4 polynomials in R_q (k=4).
880
+ assert_w_prime_approx(pk, sig, w);
881
+
882
+ // 9. w_prime_1 = UseHint(h, w_prime_approx)
883
+ // Use hint h to reconstruct the exact high bits w1 \in R_q^K.
884
+ assert_use_hint(sig.h, w.w_prime_approx_, w.w1_, w.hint_aux_bits_,
885
+ w.w_prime_1_, w.w_prime_1_bits_);
886
+
887
+ assert_w1_encode(w.w_prime_1_bits_, w.w1_tilde_);
888
+
889
+ // 11. Verification Check 1: ||z|| < (gamma1 - beta)
890
+ assert_infty_norm<ml_dsa::L, 19>(sig.z, sig.z_bits,
891
+ ml_dsa::GAMMA_1 - ml_dsa::BETA);
892
+
893
+ // 12. Verification Check 2: c_prime = H(mu || w1Encode(w_prime_1), 32)
894
+ assert_ctilde(mu, w.w1_tilde_, w.c_prime_tilde_bws_, sig.c_tilde);
895
+ }
896
+
897
+ private:
898
+ const LogicCircuit& lc_;
899
+ };
900
+
901
+ } // namespace proofs
902
+
903
+ #endif // PRIVACY_PROOFS_ZK_LIB_CIRCUITS_TESTS_PQ_ML_DSA_ML_DSA_44_H_