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.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +152 -0
- data/ext/longfellow/CMakeLists.txt +76 -0
- data/ext/longfellow/extconf.rb +77 -0
- data/lib/longfellow/attribute.rb +65 -0
- data/lib/longfellow/c.rb +105 -0
- data/lib/longfellow/errors.rb +78 -0
- data/lib/longfellow/version.rb +5 -0
- data/lib/longfellow/zk_spec.rb +40 -0
- data/lib/longfellow.rb +162 -0
- data/sig/longfellow.rbs +74 -0
- data/vendor/longfellow-zk/LICENSE +203 -0
- data/vendor/longfellow-zk/lib/algebra/blas.h +121 -0
- data/vendor/longfellow-zk/lib/algebra/bogorng.h +68 -0
- data/vendor/longfellow-zk/lib/algebra/compare.h +40 -0
- data/vendor/longfellow-zk/lib/algebra/convolution.h +219 -0
- data/vendor/longfellow-zk/lib/algebra/crt.cc +42 -0
- data/vendor/longfellow-zk/lib/algebra/crt.h +299 -0
- data/vendor/longfellow-zk/lib/algebra/crt_convolution.h +114 -0
- data/vendor/longfellow-zk/lib/algebra/crt_test.cc +371 -0
- data/vendor/longfellow-zk/lib/algebra/fft.h +104 -0
- data/vendor/longfellow-zk/lib/algebra/fft_interpolation.h +304 -0
- data/vendor/longfellow-zk/lib/algebra/fft_interpolation_test.cc +168 -0
- data/vendor/longfellow-zk/lib/algebra/fft_test.cc +257 -0
- data/vendor/longfellow-zk/lib/algebra/fp.h +59 -0
- data/vendor/longfellow-zk/lib/algebra/fp2.h +240 -0
- data/vendor/longfellow-zk/lib/algebra/fp24.h +342 -0
- data/vendor/longfellow-zk/lib/algebra/fp24_6.h +305 -0
- data/vendor/longfellow-zk/lib/algebra/fp24_6_test.cc +197 -0
- data/vendor/longfellow-zk/lib/algebra/fp2_test.cc +280 -0
- data/vendor/longfellow-zk/lib/algebra/fp_generic.h +533 -0
- data/vendor/longfellow-zk/lib/algebra/fp_p128.h +91 -0
- data/vendor/longfellow-zk/lib/algebra/fp_p256.h +68 -0
- data/vendor/longfellow-zk/lib/algebra/fp_p256k1.h +123 -0
- data/vendor/longfellow-zk/lib/algebra/fp_p384.h +65 -0
- data/vendor/longfellow-zk/lib/algebra/fp_p521.h +62 -0
- data/vendor/longfellow-zk/lib/algebra/fp_test.cc +522 -0
- data/vendor/longfellow-zk/lib/algebra/hash.h +39 -0
- data/vendor/longfellow-zk/lib/algebra/interpolation.h +117 -0
- data/vendor/longfellow-zk/lib/algebra/interpolation_test.cc +74 -0
- data/vendor/longfellow-zk/lib/algebra/limb.h +153 -0
- data/vendor/longfellow-zk/lib/algebra/limb_test.cc +75 -0
- data/vendor/longfellow-zk/lib/algebra/nat.cc +32 -0
- data/vendor/longfellow-zk/lib/algebra/nat.h +212 -0
- data/vendor/longfellow-zk/lib/algebra/nat_test.cc +183 -0
- data/vendor/longfellow-zk/lib/algebra/nussbaumer.h +400 -0
- data/vendor/longfellow-zk/lib/algebra/nussbaumer_test.cc +138 -0
- data/vendor/longfellow-zk/lib/algebra/nussbaumerfp2_test.cc +139 -0
- data/vendor/longfellow-zk/lib/algebra/permutations.h +79 -0
- data/vendor/longfellow-zk/lib/algebra/poly.h +240 -0
- data/vendor/longfellow-zk/lib/algebra/poly_test.cc +123 -0
- data/vendor/longfellow-zk/lib/algebra/reed_solomon.h +150 -0
- data/vendor/longfellow-zk/lib/algebra/reed_solomon_extension.h +108 -0
- data/vendor/longfellow-zk/lib/algebra/reed_solomon_extension_test.cc +76 -0
- data/vendor/longfellow-zk/lib/algebra/reed_solomon_test.cc +473 -0
- data/vendor/longfellow-zk/lib/algebra/rfft.h +400 -0
- data/vendor/longfellow-zk/lib/algebra/rfft_test.cc +102 -0
- data/vendor/longfellow-zk/lib/algebra/static_string.h +29 -0
- data/vendor/longfellow-zk/lib/algebra/sysdep.h +495 -0
- data/vendor/longfellow-zk/lib/algebra/sysdep_test.cc +41 -0
- data/vendor/longfellow-zk/lib/algebra/twiddle.h +59 -0
- data/vendor/longfellow-zk/lib/algebra/utility.h +86 -0
- data/vendor/longfellow-zk/lib/algebra/utility_test.cc +86 -0
- data/vendor/longfellow-zk/lib/arrays/affine.h +56 -0
- data/vendor/longfellow-zk/lib/arrays/affine_test.cc +220 -0
- data/vendor/longfellow-zk/lib/arrays/dense.h +210 -0
- data/vendor/longfellow-zk/lib/arrays/eq.h +75 -0
- data/vendor/longfellow-zk/lib/arrays/eqs.h +137 -0
- data/vendor/longfellow-zk/lib/arrays/eqs_test.cc +151 -0
- data/vendor/longfellow-zk/lib/arrays/sparse.h +192 -0
- data/vendor/longfellow-zk/lib/cbor/host_decoder.h +323 -0
- data/vendor/longfellow-zk/lib/cbor/host_decoder_test.cc +541 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor.h +594 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_byte_decoder.h +150 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_byte_decoder_test.cc +147 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_constants.h +27 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_pluck.h +110 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_pluck_test.cc +55 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_test.cc +174 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_testing.h +98 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/cbor_witness.h +312 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/mso2_test.cc +662 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/mso_test.cc +485 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/scan.h +104 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser/scan_test.cc +137 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor.h +640 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor_byte_decoder.h +150 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor_byte_decoder_test.cc +147 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor_constants.h +27 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor_testing.h +99 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/cbor_witness.h +319 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/lexer_test.cc +120 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/mdoc_examples_test.cc +89 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/parser_circuit_test.cc +506 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/parser_size_test.cc +79 -0
- data/vendor/longfellow-zk/lib/circuits/cbor_parser_v2/parser_test.cc +473 -0
- data/vendor/longfellow-zk/lib/circuits/compiler/canonicalization_test.cc +185 -0
- data/vendor/longfellow-zk/lib/circuits/compiler/circuit_dump.h +65 -0
- data/vendor/longfellow-zk/lib/circuits/compiler/compiler.h +471 -0
- data/vendor/longfellow-zk/lib/circuits/compiler/compiler_test.cc +110 -0
- data/vendor/longfellow-zk/lib/circuits/compiler/node.h +176 -0
- data/vendor/longfellow-zk/lib/circuits/compiler/pdqhash.h +127 -0
- data/vendor/longfellow-zk/lib/circuits/compiler/schedule.h +435 -0
- data/vendor/longfellow-zk/lib/circuits/ecdsa/verify_circuit.h +371 -0
- data/vendor/longfellow-zk/lib/circuits/ecdsa/verify_external_test.cc +246 -0
- data/vendor/longfellow-zk/lib/circuits/ecdsa/verify_test.cc +587 -0
- data/vendor/longfellow-zk/lib/circuits/ecdsa/verify_witness.h +201 -0
- data/vendor/longfellow-zk/lib/circuits/logic/bit_adder.h +140 -0
- data/vendor/longfellow-zk/lib/circuits/logic/bit_adder_test.cc +64 -0
- data/vendor/longfellow-zk/lib/circuits/logic/bit_plucker.h +247 -0
- data/vendor/longfellow-zk/lib/circuits/logic/bit_plucker_constants.h +35 -0
- data/vendor/longfellow-zk/lib/circuits/logic/bit_plucker_encoder.h +72 -0
- data/vendor/longfellow-zk/lib/circuits/logic/bit_plucker_test.cc +183 -0
- data/vendor/longfellow-zk/lib/circuits/logic/compiler_backend.h +62 -0
- data/vendor/longfellow-zk/lib/circuits/logic/counter.h +171 -0
- data/vendor/longfellow-zk/lib/circuits/logic/counter_test.cc +102 -0
- data/vendor/longfellow-zk/lib/circuits/logic/evaluation_backend.h +94 -0
- data/vendor/longfellow-zk/lib/circuits/logic/logic.h +1232 -0
- data/vendor/longfellow-zk/lib/circuits/logic/logic_circuit_test.cc +310 -0
- data/vendor/longfellow-zk/lib/circuits/logic/logic_test.cc +521 -0
- data/vendor/longfellow-zk/lib/circuits/logic/memcmp.h +68 -0
- data/vendor/longfellow-zk/lib/circuits/logic/memcmp_test.cc +148 -0
- data/vendor/longfellow-zk/lib/circuits/logic/polynomial.h +94 -0
- data/vendor/longfellow-zk/lib/circuits/logic/polynomial_test.cc +62 -0
- data/vendor/longfellow-zk/lib/circuits/logic/routing.h +445 -0
- data/vendor/longfellow-zk/lib/circuits/logic/routing_test.cc +241 -0
- data/vendor/longfellow-zk/lib/circuits/logic/unary.h +55 -0
- data/vendor/longfellow-zk/lib/circuits/logic/unary_plucker.h +77 -0
- data/vendor/longfellow-zk/lib/circuits/logic/unary_plucker_constants.h +37 -0
- data/vendor/longfellow-zk/lib/circuits/logic/unary_plucker_test.cc +53 -0
- data/vendor/longfellow-zk/lib/circuits/logic/unary_size_test.cc +69 -0
- data/vendor/longfellow-zk/lib/circuits/logic/unary_test.cc +62 -0
- data/vendor/longfellow-zk/lib/circuits/mac/mac_circuit.h +193 -0
- data/vendor/longfellow-zk/lib/circuits/mac/mac_circuit_test.cc +223 -0
- data/vendor/longfellow-zk/lib/circuits/mac/mac_reference.h +72 -0
- data/vendor/longfellow-zk/lib/circuits/mac/mac_witness.h +94 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/circuit_maker.cc +242 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_attribute_ids.h +311 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_attribute_test.cc +64 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_circuit_id.cc +85 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_constants.h +85 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_decompress.cc +41 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_decompress.h +27 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_examples.h +5232 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_generate_circuit.cc +199 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_hash.h +554 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_signature.h +143 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_signature_test.cc +444 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_test_attributes.h +157 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_witness.h +863 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_zk.cc +693 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_zk.h +216 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/mdoc_zk_test.cc +724 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/zk_spec.cc +100 -0
- data/vendor/longfellow-zk/lib/circuits/mdoc/zk_spec_test.cc +155 -0
- data/vendor/longfellow-zk/lib/circuits/sha/flatsha256_circuit.h +330 -0
- data/vendor/longfellow-zk/lib/circuits/sha/flatsha256_circuit_test.cc +607 -0
- data/vendor/longfellow-zk/lib/circuits/sha/flatsha256_io.h +26 -0
- data/vendor/longfellow-zk/lib/circuits/sha/flatsha256_witness.cc +163 -0
- data/vendor/longfellow-zk/lib/circuits/sha/flatsha256_witness.h +47 -0
- data/vendor/longfellow-zk/lib/circuits/sha/sha256_constants.cc +34 -0
- data/vendor/longfellow-zk/lib/circuits/sha/sha256_constants.h +27 -0
- data/vendor/longfellow-zk/lib/circuits/sha/sha256_test_values.h +389 -0
- data/vendor/longfellow-zk/lib/circuits/tests/anoncred/ptrcred.h +171 -0
- data/vendor/longfellow-zk/lib/circuits/tests/anoncred/small.h +218 -0
- data/vendor/longfellow-zk/lib/circuits/tests/anoncred/small_examples.h +118 -0
- data/vendor/longfellow-zk/lib/circuits/tests/anoncred/small_io.h +25 -0
- data/vendor/longfellow-zk/lib/circuits/tests/anoncred/small_test.cc +208 -0
- data/vendor/longfellow-zk/lib/circuits/tests/anoncred/small_witness.h +130 -0
- data/vendor/longfellow-zk/lib/circuits/tests/base64/decode.h +508 -0
- data/vendor/longfellow-zk/lib/circuits/tests/base64/decode_circuit_test.cc +95 -0
- data/vendor/longfellow-zk/lib/circuits/tests/base64/decode_test.cc +119 -0
- data/vendor/longfellow-zk/lib/circuits/tests/base64/decode_util.cc +47 -0
- data/vendor/longfellow-zk/lib/circuits/tests/base64/decode_util.h +29 -0
- data/vendor/longfellow-zk/lib/circuits/tests/ec/pk_circuit.h +231 -0
- data/vendor/longfellow-zk/lib/circuits/tests/ec/pk_circuit_test.cc +428 -0
- data/vendor/longfellow-zk/lib/circuits/tests/ec/pk_witness.h +102 -0
- data/vendor/longfellow-zk/lib/circuits/tests/jwt/jwt.h +190 -0
- data/vendor/longfellow-zk/lib/circuits/tests/jwt/jwt_constants.h +26 -0
- data/vendor/longfellow-zk/lib/circuits/tests/jwt/jwt_test.cc +559 -0
- data/vendor/longfellow-zk/lib/circuits/tests/jwt/jwt_witness.h +315 -0
- data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_1f.h +411 -0
- data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_1f_io.h +32 -0
- data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_1f_test.cc +364 -0
- data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_1f_witness.h +278 -0
- data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_revocation.h +146 -0
- data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_revocation_constants.h +25 -0
- data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_revocation_test.cc +315 -0
- data/vendor/longfellow-zk/lib/circuits/tests/mdoc/mdoc_revocation_witness.h +136 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/bitaddr/bitaddr.h +250 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/bitaddr/bitaddr_test.cc +333 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/bitaddr/bitaddr_witness.h +152 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44.h +903 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_circuit_test.cc +274 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_eval_test.cc +440 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_examples.cc +8851 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_examples.h +93 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_types.cc +24 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_types.h +118 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_witness.h +453 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_44_witness_test.cc +49 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref.cc +458 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref.h +150 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref_test.cc +398 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref_test_vectors.inc +3618 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref_test_vectors_pkdecode.inc +689 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/ml_dsa_ref_test_vectors_sigdecode.inc +1501 -0
- data/vendor/longfellow-zk/lib/circuits/tests/pq/ml_dsa/sigdecode_test_vectors.inc +540 -0
- data/vendor/longfellow-zk/lib/circuits/tests/ripemd/ripemd_circuit.h +394 -0
- data/vendor/longfellow-zk/lib/circuits/tests/ripemd/ripemd_circuit_test.cc +577 -0
- data/vendor/longfellow-zk/lib/circuits/tests/ripemd/ripemd_constants.h +90 -0
- data/vendor/longfellow-zk/lib/circuits/tests/ripemd/ripemd_witness.cc +174 -0
- data/vendor/longfellow-zk/lib/circuits/tests/ripemd/ripemd_witness.h +140 -0
- data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_circuit.h +351 -0
- data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_circuit_test.cc +466 -0
- data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_reference.cc +207 -0
- data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_reference.h +59 -0
- data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_reference_test.cc +153 -0
- data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_round_constants.cc +39 -0
- data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_round_constants.h +29 -0
- data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_slicing.h +31 -0
- data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_witness.cc +83 -0
- data/vendor/longfellow-zk/lib/circuits/tests/sha3/sha3_witness.h +72 -0
- data/vendor/longfellow-zk/lib/circuits/tests/sha3/shake_test_vectors.h +477 -0
- data/vendor/longfellow-zk/lib/ec/elliptic_curve.h +596 -0
- data/vendor/longfellow-zk/lib/ec/elliptic_curve_test.cc +548 -0
- data/vendor/longfellow-zk/lib/ec/p256.cc +36 -0
- data/vendor/longfellow-zk/lib/ec/p256.h +60 -0
- data/vendor/longfellow-zk/lib/ec/p256k1.cc +34 -0
- data/vendor/longfellow-zk/lib/ec/p256k1.h +60 -0
- data/vendor/longfellow-zk/lib/gf2k/gf2_128.h +503 -0
- data/vendor/longfellow-zk/lib/gf2k/gf2_128_bench.cc +48 -0
- data/vendor/longfellow-zk/lib/gf2k/gf2_128_test.cc +416 -0
- data/vendor/longfellow-zk/lib/gf2k/gf2poly.h +74 -0
- data/vendor/longfellow-zk/lib/gf2k/lch14.h +242 -0
- data/vendor/longfellow-zk/lib/gf2k/lch14_bench.cc +75 -0
- data/vendor/longfellow-zk/lib/gf2k/lch14_reed_solomon.h +127 -0
- data/vendor/longfellow-zk/lib/gf2k/lch14_reed_solomon_test.cc +110 -0
- data/vendor/longfellow-zk/lib/gf2k/lch14_test.cc +246 -0
- data/vendor/longfellow-zk/lib/gf2k/sysdep.h +329 -0
- data/vendor/longfellow-zk/lib/ligero/ligero_param.h +449 -0
- data/vendor/longfellow-zk/lib/ligero/ligero_prover.h +354 -0
- data/vendor/longfellow-zk/lib/ligero/ligero_test.cc +136 -0
- data/vendor/longfellow-zk/lib/ligero/ligero_transcript.h +67 -0
- data/vendor/longfellow-zk/lib/ligero/ligero_verifier.h +272 -0
- data/vendor/longfellow-zk/lib/merkle/merkle_commitment.h +104 -0
- data/vendor/longfellow-zk/lib/merkle/merkle_tree.h +216 -0
- data/vendor/longfellow-zk/lib/merkle/merkle_tree_test.cc +240 -0
- data/vendor/longfellow-zk/lib/proto/circuit.h +354 -0
- data/vendor/longfellow-zk/lib/proto/circuit_test.cc +202 -0
- data/vendor/longfellow-zk/lib/random/random.h +119 -0
- data/vendor/longfellow-zk/lib/random/random_test.cc +189 -0
- data/vendor/longfellow-zk/lib/random/secure_random_engine.h +37 -0
- data/vendor/longfellow-zk/lib/random/transcript.h +193 -0
- data/vendor/longfellow-zk/lib/random/transcript_test.cc +344 -0
- data/vendor/longfellow-zk/lib/sumcheck/circuit.h +148 -0
- data/vendor/longfellow-zk/lib/sumcheck/circuit_id.h +71 -0
- data/vendor/longfellow-zk/lib/sumcheck/equad.h +126 -0
- data/vendor/longfellow-zk/lib/sumcheck/hquad.h +115 -0
- data/vendor/longfellow-zk/lib/sumcheck/prover.h +59 -0
- data/vendor/longfellow-zk/lib/sumcheck/prover_layers.h +362 -0
- data/vendor/longfellow-zk/lib/sumcheck/quad.h +227 -0
- data/vendor/longfellow-zk/lib/sumcheck/quad_builder.h +211 -0
- data/vendor/longfellow-zk/lib/sumcheck/quad_test.cc +169 -0
- data/vendor/longfellow-zk/lib/sumcheck/sumcheck_test.cc +324 -0
- data/vendor/longfellow-zk/lib/sumcheck/testing.h +69 -0
- data/vendor/longfellow-zk/lib/sumcheck/transcript_sumcheck.h +85 -0
- data/vendor/longfellow-zk/lib/sumcheck/verifier.h +84 -0
- data/vendor/longfellow-zk/lib/sumcheck/verifier_layers.h +221 -0
- data/vendor/longfellow-zk/lib/testing/test_main.cc +50 -0
- data/vendor/longfellow-zk/lib/util/ceildiv.h +164 -0
- data/vendor/longfellow-zk/lib/util/ceildiv_test.cc +152 -0
- data/vendor/longfellow-zk/lib/util/crc64.h +45 -0
- data/vendor/longfellow-zk/lib/util/crypto.cc +39 -0
- data/vendor/longfellow-zk/lib/util/crypto.h +108 -0
- data/vendor/longfellow-zk/lib/util/log.cc +110 -0
- data/vendor/longfellow-zk/lib/util/log.h +33 -0
- data/vendor/longfellow-zk/lib/util/panic.h +40 -0
- data/vendor/longfellow-zk/lib/util/readbuffer.h +67 -0
- data/vendor/longfellow-zk/lib/util/serialization.h +54 -0
- data/vendor/longfellow-zk/lib/zk/zk_common.h +455 -0
- data/vendor/longfellow-zk/lib/zk/zk_proof.h +378 -0
- data/vendor/longfellow-zk/lib/zk/zk_prover.h +202 -0
- data/vendor/longfellow-zk/lib/zk/zk_test.cc +340 -0
- data/vendor/longfellow-zk/lib/zk/zk_testing.h +154 -0
- data/vendor/longfellow-zk/lib/zk/zk_verifier.h +109 -0
- 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_
|