diff --git a/package.json b/package.json index 90c8790a..9bab6fec 100644 --- a/package.json +++ b/package.json @@ -14,21 +14,26 @@ "test:fibonacci:gpu": "npm run fibonacci_buildconst && npm run fibonacci_exec && npm run fibonacci_pil_verify && npm run fibonacci_buildstarkinfo_gpu && npm run fibonacci_buildconsttree_gpu && npm run fibonacci_prove && npm run fibonacci_verify && npm run fibonacci_starkVerifier_gpu", "test:fibonacci:C12:pil": "npm run fibonacci_C12_setup && npm run fibonacci_C12_exec && npm run fibonacci_C12_pil_verify", "test:fibonacci:C12:prove": "npm run fibonacci_C12_buildstarkinfo && npm run fibonacci_C12_buildconsttree && npm run fibonacci_C12_prove && npm run fibonacci_C12_verify && npm run fibonacci_C12_gencircomBN128 && npm run fibonacci_C12_starkVerifierBN128", - "test:fibonacci:C12:prove:custom": "npm run fibonacci_C12_buildstarkinfo && npm run fibonacci_C12_buildconsttree_custom && npm run fibonacci_C12_prove_custom && npm run fibonacci_C12_verify_custom && npm run fibonacci_C12_gencircomBN128_custom && npm run fibonacci_C12_starkVerifierBN128", + "test:fibonacci:C12:prove:custom": "npm run fibonacci_C12_buildstarkinfo_custom && npm run fibonacci_C12_buildconsttree && npm run fibonacci_C12_prove && npm run fibonacci_C12_verify && npm run fibonacci_C12_gencircomBN128 && npm run fibonacci_C12_starkVerifierBN128", "test:all": "npm run all_buildconst && npm run all_exec && npm run all_pil_verify && npm run all_buildstarkinfo && npm run all_buildconsttree && npm run all_prove && npm run all_verify && npm run all_starkVerifier", + "test:all:im": "npm run all_buildconst && npm run all_exec && npm run all_buildstarkinfo_preparePil && npm run all_buildstarkinfo_calculateImPols && npm run all_buildstarkinfo_genPilCode && npm run all_pil_verify && npm run all_buildconsttree && npm run all_prove && npm run all_verify && npm run all_starkVerifier", + "test:all:im:opt": "npm run all_buildconst && npm run all_exec && npm run all_buildstarkinfo_preparePil && npm run all_buildstarkinfo_calculateImPols_opt && npm run all_buildstarkinfo_genPilCode && npm run all_pil_verify && npm run all_buildconsttree && npm run all_prove && npm run all_verify && npm run all_starkVerifier", "test:all:gpu": "npm run all_buildconst && npm run all_exec && npm run all_pil_verify && npm run all_buildstarkinfo_gpu && npm run all_buildconsttree_gpu && npm run all_prove && npm run all_verify && npm run all_starkVerifier_gpu", "test:all:C18:pil": "npm run all_C18_setup && npm run all_C18_exec && npm run all_C18_pil_verify", "test:all:C18:prove": "npm run all_C18_buildstarkinfo && npm run all_C18_buildconsttree && npm run all_C18_prove && npm run all_C18_verify && npm run all_C18_gencircomBN128 && npm run all_C18_starkVerifierBN128", "test:C12": "npm run verifier_C12_setup && npm run verifier_C12_exec && npm run verifier_C12_pil_verify && npm run verifier_C12_buildstarkinfo && npm run verifier_C12_buildconsttree && npm run verifier_C12_prove && npm run verifier_C12_verify && npm run verifier_C12_gencircomBN128 && npm run verifier_C12_starkVerifierBN128", "test:C18": "npm run verifier_C18_setup && npm run verifier_C18_exec && npm run verifier_C18_pil_verify && npm run verifier_C18_buildstarkinfo && npm run verifier_C18_buildconsttree && npm run verifier_C18_prove && npm run verifier_C18_verify && npm run verifier_C18_gencircomBN128 && npm run verifier_C18_starkVerifierBN128", - "test:C12:custom": "npm run verifier_C12_setup && npm run verifier_C12_exec && npm run verifier_C12_pil_verify && npm run verifier_C12_buildstarkinfo && npm run verifier_C12_buildconsttree_custom && npm run verifier_C12_prove_custom && npm run verifier_C12_verify_custom && npm run verifier_C12_gencircomBN128_custom && npm run verifier_C12_starkVerifierBN128", + "test:C12:custom": "npm run verifier_C12_setup && npm run verifier_C12_exec && npm run verifier_C12_pil_verify && npm run verifier_C12_buildstarkinfo_custom && npm run verifier_C12_buildconsttree && npm run verifier_C12_prove && npm run verifier_C12_verify && npm run verifier_C12_gencircomBN128 && npm run verifier_C12_starkVerifierBN128", + "test:buildstarkinfo:all:im:opt": "mkdir -p tmp && npm run all_buildstarkinfo_preparePil && npm run all_buildstarkinfo_calculateImPols_opt && npm run all_buildstarkinfo_genPilCode", + "test:buildstarkinfo:C12:im:opt": "mkdir -p tmp && cp test/state_machines/sm_fibonacci/fibonacci.c12.pil tmp/fibonacci.c12.pil && npm run fibonacci_C12_buildstarkinfo_preparePil && npm run fibonacci_C12_buildstarkinfo_calculateImPols_opt && npm run fibonacci_C12_buildstarkinfo_genPilCode", + "test:buildstarkinfo:C18:im:opt":"mkdir -p tmp && cp test/state_machines/sm_all/all.c18.pil tmp/all.c18.pil && npm run all_C18_buildstarkinfo_preparePil && npm run all_C18_buildstarkinfo_calculateImPols_opt && npm run all_C12_buildstarkinfo_genPilCode", "fibonacci_buildconst": "NODE_OPTIONS=--max-old-space-size=32000 node test/state_machines/sm_fibonacci/main_buildconst_fibonacci.js -o tmp/fibonacci.const", "fibonacci_exec": "NODE_OPTIONS=--max-old-space-size=32000 node test/state_machines/sm_fibonacci/main_exec_fibonacci.js -i test/state_machines/sm_fibonacci/fibonacci.input.json -o tmp/fibonacci.commit", "fibonacci_pil_verify": "NODE_OPTIONS=--max-old-space-size=32000 node node_modules/pilcom/src/main_pilverifier.js tmp/fibonacci.commit -p test/state_machines/sm_fibonacci/fibonacci_main.pil -c tmp/fibonacci.const", "fibonacci_buildstarkinfo": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genstarkinfo.js -p test/state_machines/sm_fibonacci/fibonacci_main.pil -s test/state_machines/sm_fibonacci/fibonacci.starkstruct.json -i tmp/fibonacci.starkinfo.json", "fibonacci_buildstarkinfo_gpu": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genstarkinfo.js -p test/state_machines/sm_fibonacci/fibonacci_main.pil -s test/state_machines/sm_fibonacci/fibonacci.starkstruct.gpu.json -i tmp/fibonacci.starkinfo.json", - "fibonacci_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/fibonacci.const -p test/state_machines/sm_fibonacci/fibonacci_main.pil -s test/state_machines/sm_fibonacci/fibonacci.starkstruct.json -t tmp/fibonacci.consttree -v tmp/fibonacci.verkey.json", - "fibonacci_buildconsttree_gpu": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/fibonacci.const -p test/state_machines/sm_fibonacci/fibonacci_main.pil -s test/state_machines/sm_fibonacci/fibonacci.starkstruct.gpu.json -t tmp/fibonacci.consttree -v tmp/fibonacci.verkey.json", + "fibonacci_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/fibonacci.const -p test/state_machines/sm_fibonacci/fibonacci_main.pil -s tmp/fibonacci.starkinfo.json -t tmp/fibonacci.consttree -v tmp/fibonacci.verkey.json", + "fibonacci_buildconsttree_gpu": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/fibonacci.const -p test/state_machines/sm_fibonacci/fibonacci_main.pil -s tmp/fibonacci.starkinfo.json -t tmp/fibonacci.consttree -v tmp/fibonacci.verkey.json", "fibonacci_prove": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_prover.js -m tmp/fibonacci.commit -c tmp/fibonacci.const -t tmp/fibonacci.consttree -p test/state_machines/sm_fibonacci/fibonacci_main.pil -s tmp/fibonacci.starkinfo.json -o tmp/fibonacci.proof.json -z tmp/fibonacci.proof.zkin.json -b tmp/fibonacci.public.json", "fibonacci_verify": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_verifier.js -s tmp/fibonacci.starkinfo.json -o tmp/fibonacci.proof.json -b tmp/fibonacci.public.json -v tmp/fibonacci.verkey.json", "fibonacci_gencircom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_pil2circom.js -p test/state_machines/sm_fibonacci/fibonacci_main.pil -s tmp/fibonacci.starkinfo.json -v tmp/fibonacci.verkey.json -o tmp/fibonacci.verifier.circom", @@ -40,14 +45,15 @@ "fibonacci_C12_exec": "NODE_OPTIONS=--max-old-space-size=32000 node src/compressor/main_compressor_exec.js -i tmp/fibonacci.proof.zkin.json -w tmp/fibonacci.verifier_js/fibonacci.verifier.wasm -p tmp/fibonacci.c12.pil -e tmp/fibonacci.c12.exec -m tmp/fibonacci.c12.commit", "fibonacci_C12_pil_verify": "NODE_OPTIONS=--max-old-space-size=32000 node node_modules/pilcom/src/main_pilverifier.js tmp/fibonacci.c12.commit -p tmp/fibonacci.c12.pil -c tmp/fibonacci.c12.const", "fibonacci_C12_buildstarkinfo": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genstarkinfo.js -p tmp/fibonacci.c12.pil -s test/state_machines/sm_fibonacci/fibonacci.c12.starkstruct.json -i tmp/fibonacci.c12.starkinfo.json", - "fibonacci_C12_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/fibonacci.c12.const -p tmp/fibonacci.c12.pil -s test/state_machines/sm_fibonacci/fibonacci.c12.starkstruct.json -t tmp/fibonacci.c12.consttree -v tmp/fibonacci.c12.verkey.json", - "fibonacci_C12_buildconsttree_custom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/fibonacci.c12.const -p tmp/fibonacci.c12.pil -s test/state_machines/sm_fibonacci/fibonacci.c12.starkstruct.json -t tmp/fibonacci.c12.consttree -v tmp/fibonacci.c12.verkey.json --arity=4", + "fibonacci_C12_buildstarkinfo_custom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genstarkinfo.js -p tmp/fibonacci.c12.pil -s test/state_machines/sm_fibonacci/fibonacci.c12.starkstruct.json -i tmp/fibonacci.c12.starkinfo.json --arity=4", + "fibonacci_C12_buildstarkinfo_preparePil": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_preparepil.js -p test/state_machines/sm_fibonacci/fibonacci.c12.pil -s test/state_machines/sm_fibonacci/fibonacci.c12.starkstruct.json -f tmp/fibonacci.c12.infopil.json", + "fibonacci_C12_buildstarkinfo_calculateImPols": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_calculateimpols.js -f tmp/fibonacci.c12.infopil.json -m tmp/fibonacci.c12.impols.json", + "fibonacci_C12_buildstarkinfo_calculateImPols_opt": "python3 src/pil_info/imPolsCalculation/calculateImPols.py tmp/fibonacci.c12.infopil.json tmp/fibonacci.c12.impols.json", + "fibonacci_C12_buildstarkinfo_genPilCode": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genpilcode.js -m tmp/fibonacci.c12.impols.json -f tmp/fibonacci.c12.infopil.json -i tmp/fibonacci.c12.starkinfo.json -p test/state_machines/sm_fibonacci/fibonacci.c12.pil", + "fibonacci_C12_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/fibonacci.c12.const -p tmp/fibonacci.c12.pil -s tmp/fibonacci.c12.starkinfo.json -t tmp/fibonacci.c12.consttree -v tmp/fibonacci.c12.verkey.json", "fibonacci_C12_prove": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_prover.js -m tmp/fibonacci.c12.commit -c tmp/fibonacci.c12.const -t tmp/fibonacci.c12.consttree -p tmp/fibonacci.c12.pil -s tmp/fibonacci.c12.starkinfo.json -o tmp/fibonacci.c12.proof.json -z tmp/fibonacci.c12.proof.zkin.json -b tmp/fibonacci.c12.public.json --proverAddr=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", - "fibonacci_C12_prove_custom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_prover.js -m tmp/fibonacci.c12.commit -c tmp/fibonacci.c12.const -t tmp/fibonacci.c12.consttree -p tmp/fibonacci.c12.pil -s tmp/fibonacci.c12.starkinfo.json -o tmp/fibonacci.c12.proof.json -z tmp/fibonacci.c12.proof.zkin.json -b tmp/fibonacci.c12.public.json --proverAddr=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 --arity=4", "fibonacci_C12_verify": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_verifier.js -s tmp/fibonacci.c12.starkinfo.json -o tmp/fibonacci.c12.proof.json -b tmp/fibonacci.c12.public.json -v tmp/fibonacci.c12.verkey.json", - "fibonacci_C12_verify_custom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_verifier.js -s tmp/fibonacci.c12.starkinfo.json -o tmp/fibonacci.c12.proof.json -b tmp/fibonacci.c12.public.json -v tmp/fibonacci.c12.verkey.json --arity=4", "fibonacci_C12_gencircomBN128": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_pil2circom.js -p tmp/fibonacci.c12.pil -s tmp/fibonacci.c12.starkinfo.json -v tmp/fibonacci.c12.verkey.json -o tmp/fibonacci.c12.verifier.circom", - "fibonacci_C12_gencircomBN128_custom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_pil2circom.js -p tmp/fibonacci.c12.pil -s tmp/fibonacci.c12.starkinfo.json -v tmp/fibonacci.c12.verkey.json -o tmp/fibonacci.c12.verifier.circom --arity=4", "fibonacci_C12_compileverifier": "circom -l circuits.bn128 -l node_modules/circomlib/circuits --O1 --r1cs --sym --wasm --verbose tmp/fibonacci.c12.verifier.circom -o tmp", "fibonacci_C12_starkVerifierBN128": "mocha test/stark/fibonacci_bn128_verifier.circuit.test.js", "all_buildconst": "NODE_OPTIONS=--max-old-space-size=32000 node test/state_machines/sm_all/main_buildconst_all.js -o tmp/all.const", @@ -55,8 +61,12 @@ "all_pil_verify": "NODE_OPTIONS=--max-old-space-size=32000 node node_modules/pilcom/src/main_pilverifier.js tmp/all.commit -p test/state_machines/sm_all/all_main.pil -c tmp/all.const", "all_buildstarkinfo": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genstarkinfo.js -p test/state_machines/sm_all/all_main.pil -s test/state_machines/sm_all/all.starkstruct.json -i tmp/all.starkinfo.json", "all_buildstarkinfo_gpu": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genstarkinfo.js -p test/state_machines/sm_all/all_main.pil -s test/state_machines/sm_all/all.starkstruct.gpu.json -i tmp/all.starkinfo.json", - "all_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/all.const -p test/state_machines/sm_all/all_main.pil -s test/state_machines/sm_all/all.starkstruct.json -t tmp/all.consttree -v tmp/all.verkey.json", - "all_buildconsttree_gpu": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/all.const -p test/state_machines/sm_all/all_main.pil -s test/state_machines/sm_all/all.starkstruct.gpu.json -t tmp/all.consttree -v tmp/all.verkey.json", + "all_buildstarkinfo_preparePil": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_preparepil.js -p test/state_machines/sm_all/all_main.pil -s test/state_machines/sm_all/all.starkstruct.json -f tmp/all.infopil.json", + "all_buildstarkinfo_calculateImPols": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_calculateimpols.js -f tmp/all.infopil.json -m tmp/all.impols.json", + "all_buildstarkinfo_calculateImPols_opt": "python3 -B src/pil_info/imPolsCalculation/calculateImPols.py tmp/all.infopil.json tmp/all.impols.json", + "all_buildstarkinfo_genPilCode": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genpilcode.js -m tmp/all.impols.json -f tmp/all.infopil.json -i tmp/all.starkinfo.json -p test/state_machines/sm_all/all_main.pil", + "all_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/all.const -p test/state_machines/sm_all/all_main.pil -s tmp/all.starkinfo.json -t tmp/all.consttree -v tmp/all.verkey.json", + "all_buildconsttree_gpu": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/all.const -p test/state_machines/sm_all/all_main.pil -s tmp/all.starkinfo.json -t tmp/all.consttree -v tmp/all.verkey.json", "all_prove": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_prover.js -m tmp/all.commit -c tmp/all.const -t tmp/all.consttree -p test/state_machines/sm_all/all_main.pil -s tmp/all.starkinfo.json -o tmp/all.proof.json -z tmp/all.proof.zkin.json -b tmp/all.public.json", "all_verify": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_verifier.js -s tmp/all.starkinfo.json -o tmp/all.proof.json -b tmp/all.public.json -v tmp/all.verkey.json", "all_gencircom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_pil2circom.js -p test/state_machines/sm_all/all_main.pil -s tmp/all.starkinfo.json -v tmp/all.verkey.json -o tmp/all.verifier.circom", @@ -67,7 +77,11 @@ "all_C18_exec": "NODE_OPTIONS=--max-old-space-size=32000 node src/compressor/main_compressor_exec.js -i tmp/all.proof.zkin.json -w tmp/all.verifier_js/all.verifier.wasm -p tmp/all.c18.pil -e tmp/all.c18.exec -m tmp/all.c18.commit", "all_C18_pil_verify": "NODE_OPTIONS=--max-old-space-size=32000 node node_modules/pilcom/src/main_pilverifier.js tmp/all.c18.commit -p tmp/all.c18.pil -c tmp/all.c18.const", "all_C18_buildstarkinfo": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genstarkinfo.js -p tmp/all.c18.pil -s test/state_machines/sm_all/all.c18.starkstruct.json -i tmp/all.c18.starkinfo.json", - "all_C18_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/all.c18.const -p tmp/all.c18.pil -s test/state_machines/sm_all/all.c18.starkstruct.json -t tmp/all.c18.consttree -v tmp/all.c18.verkey.json", + "all_C18_buildstarkinfo_preparePil": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_preparepil.js -p test/state_machines/sm_all/all.c18.pil -s test/state_machines/sm_all/all.c18.starkstruct.json -f tmp/all.c18.infopil.json", + "all_C18_buildstarkinfo_calculateImPols": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_calculateimpols.js -f tmp/all.c18.infopil.json -m tmp/all.c18.impols.json", + "all_C18_buildstarkinfo_calculateImPols_opt": "python3 -B src/pil_info/imPolsCalculation/calculateImPols.py tmp/all.c18.infopil.json tmp/all.c18.impols.json", + "all_C18_buildstarkinfo_genPilCode": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genpilcode.js -m tmp/all.c18.impols.json -f tmp/all.c18.infopil.json -i tmp/all.c18.starkinfo.json -p test/state_machines/sm_all/all.c18.pil", + "all_C18_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/all.c18.const -p tmp/all.c18.pil -s tmp/all.c18.starkinfo.json -t tmp/all.c18.consttree -v tmp/all.c18.verkey.json", "all_C18_prove": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_prover.js -m tmp/all.c18.commit -c tmp/all.c18.const -t tmp/all.c18.consttree -p tmp/all.c18.pil -s tmp/all.c18.starkinfo.json -o tmp/all.c18.proof.json -z tmp/all.c18.proof.zkin.json -b tmp/all.c18.public.json --proverAddr=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", "all_C18_verify": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_verifier.js -s tmp/all.c18.starkinfo.json -o tmp/all.c18.proof.json -b tmp/all.c18.public.json -v tmp/all.c18.verkey.json", "all_C18_gencircomBN128": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_pil2circom.js -s tmp/all.c18.starkinfo.json -p tmp/all.c18.pil -v tmp/all.c18.verkey.json -o tmp/all.c18.verifier.circom", @@ -79,7 +93,7 @@ "verifier_C18_exec": "NODE_OPTIONS=--max-old-space-size=32000 node src/compressor/main_compressor_exec.js -i test/compressor/verifier.proof.zkin.json -w test/compressor/verifier_js/verifier.wasm -p tmp/test.c18.pil -e tmp/test.c18.exec -m tmp/test.c18.commit", "verifier_C18_pil_verify": "NODE_OPTIONS=--max-old-space-size=32000 node src/compressor/main_compressor_pil_verify.js -t tmp/test.c18.commit -p tmp/test.c18.pil -c tmp/test.c18.const", "verifier_C18_buildstarkinfo": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genstarkinfo.js -p tmp/test.c18.pil -s test/state_machines/sm_all/all.c18.starkstruct.json -i tmp/test.c18.starkinfo.json", - "verifier_C18_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/test.c18.const -p tmp/test.c18.pil -s test/state_machines/sm_all/all.c18.starkstruct.json -t tmp/test.c18.consttree -v tmp/test.c18.verkey.json", + "verifier_C18_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/test.c18.const -p tmp/test.c18.pil -s tmp/test.c18.starkinfo.json -t tmp/test.c18.consttree -v tmp/test.c18.verkey.json", "verifier_C18_prove": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_prover.js -m tmp/test.c18.commit -c tmp/test.c18.const -t tmp/test.c18.consttree -p tmp/test.c18.pil -s tmp/test.c18.starkinfo.json -o tmp/test.c18.proof.json -z tmp/test.c18.proof.zkin.json -b tmp/test.c18.public.json --proverAddr=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", "verifier_C18_verify": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_verifier.js -s tmp/test.c18.starkinfo.json -o tmp/test.c18.proof.json -b tmp/test.c18.public.json -v tmp/test.c18.verkey.json", "verifier_C18_gencircomBN128": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_pil2circom.js -s tmp/test.c18.starkinfo.json -p tmp/test.c18.pil -v tmp/test.c18.verkey.json -o tmp/test.c18.verifier.circom", @@ -88,14 +102,11 @@ "verifier_C12_exec": "NODE_OPTIONS=--max-old-space-size=32000 node src/compressor/main_compressor_exec.js -i test/compressor/verifier.proof.zkin.json -w test/compressor/verifier_js/verifier.wasm -p tmp/test.c12.pil -e tmp/test.c12.exec -m tmp/test.c12.commit", "verifier_C12_pil_verify": "NODE_OPTIONS=--max-old-space-size=32000 node src/compressor/main_compressor_pil_verify.js -t tmp/test.c12.commit -p tmp/test.c12.pil -c tmp/test.c12.const", "verifier_C12_buildstarkinfo": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genstarkinfo.js -p tmp/test.c12.pil -s test/state_machines/sm_fibonacci/fibonacci.c12.starkstruct.json -i tmp/test.c12.starkinfo.json", - "verifier_C12_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/test.c12.const -p tmp/test.c12.pil -s test/state_machines/sm_fibonacci/fibonacci.c12.starkstruct.json -t tmp/test.c12.consttree -v tmp/test.c12.verkey.json", - "verifier_C12_buildconsttree_custom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/test.c12.const -p tmp/test.c12.pil -s test/state_machines/sm_fibonacci/fibonacci.c12.starkstruct.json -t tmp/test.c12.consttree -v tmp/test.c12.verkey.json --arity=4", + "verifier_C12_buildstarkinfo_custom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_genstarkinfo.js -p tmp/test.c12.pil -s test/state_machines/sm_fibonacci/fibonacci.c12.starkstruct.json -i tmp/test.c12.starkinfo.json --arity=4", + "verifier_C12_buildconsttree": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_buildconsttree.js -c tmp/test.c12.const -p tmp/test.c12.pil -s tmp/test.c12.starkinfo.json -t tmp/test.c12.consttree -v tmp/test.c12.verkey.json", "verifier_C12_prove": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_prover.js -m tmp/test.c12.commit -c tmp/test.c12.const -t tmp/test.c12.consttree -p tmp/test.c12.pil -s tmp/test.c12.starkinfo.json -o tmp/test.c12.proof.json -z tmp/test.c12.proof.zkin.json -b tmp/test.c12.public.json --proverAddr=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", - "verifier_C12_prove_custom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_prover.js -m tmp/test.c12.commit -c tmp/test.c12.const -t tmp/test.c12.consttree -p tmp/test.c12.pil -s tmp/test.c12.starkinfo.json -o tmp/test.c12.proof.json -z tmp/test.c12.proof.zkin.json -b tmp/test.c12.public.json --proverAddr=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 --arity=4", "verifier_C12_verify": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_verifier.js -s tmp/test.c12.starkinfo.json -o tmp/test.c12.proof.json -b tmp/test.c12.public.json -v tmp/test.c12.verkey.json", - "verifier_C12_verify_custom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_verifier.js -s tmp/test.c12.starkinfo.json -o tmp/test.c12.proof.json -b tmp/test.c12.public.json -v tmp/test.c12.verkey.json --arity=4", "verifier_C12_gencircomBN128": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_pil2circom.js -s tmp/test.c12.starkinfo.json -p tmp/test.c12.pil -v tmp/test.c12.verkey.json -o tmp/test.c12.verifier.circom", - "verifier_C12_gencircomBN128_custom": "NODE_OPTIONS=--max-old-space-size=32000 node src/main_pil2circom.js -s tmp/test.c12.starkinfo.json -p tmp/test.c12.pil -v tmp/test.c12.verkey.json -o tmp/test.c12.verifier.circom --arity=4", "verifier_C12_starkVerifierBN128": "mocha test/stark/test_c12_bn128_verifier.circuit.test.js", "plonktest_compile": "circom --O1 --prime goldilocks --r1cs --sym --wasm --c --verbose test/circuits/plonktest.circom -o tmp", "plonktest_wc": "snarkjs wc tmp/plonktest_js/plonktest.wasm test/circuits/plonkinput.json tmp/plonktest.wtns" diff --git a/src/helpers/expressionops.js b/src/helpers/expressionops.js index 9cce1945..5cdb757a 100644 --- a/src/helpers/expressionops.js +++ b/src/helpers/expressionops.js @@ -91,7 +91,7 @@ class ExpressionOps { number(n) { return { op: "number", - value: BigInt(n) + value: n.toString() } } diff --git a/src/main_buildchelpers.js b/src/main_buildchelpers.js index 959f9cab..dc3cfe8e 100644 --- a/src/main_buildchelpers.js +++ b/src/main_buildchelpers.js @@ -10,6 +10,7 @@ const argv = require("yargs") .alias("c", "chelpers") .alias("C", "cls") .alias("b", "binfile") + .alias("g", "genericbinfile") .argv; async function run() { @@ -17,10 +18,11 @@ async function run() { const starkInfoFile = typeof (argv.starkinfo) === "string" ? argv.starkinfo.trim() : "mycircuit.starkinfo.json"; const cHelpersFile = typeof (argv.chelpers) === "string" ? argv.chelpers.trim() : "mycircuit.chelpers"; const binFile = typeof (argv.binfile) === "string" ? argv.binfile.trim() : "mycircuit.chelpers.bin"; + const genericBinFile = typeof (argv.genericbinfile) === "string" ? argv.genericbinfile.trim() : undefined; const starkInfo = JSON.parse(await fs.promises.readFile(starkInfoFile, "utf8")); - await buildCHelpers(starkInfo, cHelpersFile, binFile, cls); + await buildCHelpers(starkInfo, cHelpersFile, cls, binFile, genericBinFile); console.log("files Generated Correctly"); } diff --git a/src/main_buildchelpers_generic.js b/src/main_buildchelpers_generic.js new file mode 100644 index 00000000..307a92b7 --- /dev/null +++ b/src/main_buildchelpers_generic.js @@ -0,0 +1,56 @@ +const { generateParser, getAllOperations } = require("./stark/chelpers/generateParser"); +const fs = require("fs"); + +const version = require("../package").version; + +const argv = require("yargs") + .version(version) + .usage("node main_buildchelpers_generic.js -c ") + .alias("c", "chelpers") + .string("parserType") + .argv; + +async function run() { + const cHelpersFile = typeof (argv.chelpers) === "string" ? argv.chelpers.trim() : "mycircuit.chelpers"; + + let operations = getAllOperations(); + + let parserType = "avx"; + + if(argv.parserType) { + if(!["avx", "avx512","pack"].includes(argv.parserType)) throw new Error("Invalid parser type"); + parserType = argv.parserType; + } + + const parser = generateParser(operations, undefined, parserType); + + const cHelpersStepsName = parserType === "avx" ? `CHELPERS_STEPS_HPP` : parserType === "avx512" ? "CHELPERS_STEPS_AVX512_HPP" : "CHELPERS_STEPS_PACK_HPP"; + + const cHelpersStepsClassName = parserType === "avx" ? `CHelpersSteps` : parserType === "avx512" ? "CHelpersStepsAvx512 : public CHelpersSteps" : "CHelpersStepsPack : public CHelpersSteps"; + + const cHelpersStepsHpp = [ + `#ifndef ${cHelpersStepsName}`, + `#define ${cHelpersStepsName}`, + `#include "chelpers.hpp"`, + `${parserType !== "avx" ? `#include "chelpers_steps.hpp"` : ""}`, + `#include "steps.hpp"\n`, + `class ${cHelpersStepsClassName} {`, + "public:", + ]; + + cHelpersStepsHpp.push(parser); + cHelpersStepsHpp.push("};\n"); + cHelpersStepsHpp.push("#endif") + + await fs.promises.writeFile(cHelpersFile, cHelpersStepsHpp.join("\n"), "utf8"); + + console.log("Generic parser generated correctly"); +} + +run().then(() => { + process.exit(0); +}, (err) => { + console.log(err.message); + console.log(err.stack); + process.exit(1); +}); \ No newline at end of file diff --git a/src/main_buildconsttree.js b/src/main_buildconsttree.js index 3b4c1b5d..7f20a726 100644 --- a/src/main_buildconsttree.js +++ b/src/main_buildconsttree.js @@ -8,14 +8,13 @@ const { buildConstTree } = require("./stark/stark_buildConstTree"); const argv = require("yargs") .version(version) - .usage("node main_buildconsttree.js -c const.bin -p [-P ] -s -t -v ") + .usage("node main_buildconsttree.js -c const.bin -p [-P ] -s -t -v ") .alias("c", "const") .alias("p", "pil") .alias("P", "pilconfig") - .alias("s", "starkstruct") + .alias("s", "starkinfo") .alias("t", "consttree") .alias("v", "verkey") - .string("arity") .argv; async function run() { @@ -24,18 +23,17 @@ async function run() { const pilFile = typeof(argv.pil) === "string" ? argv.pil.trim() : "mycircuit.pil"; const pilConfig = typeof(argv.pilconfig) === "string" ? JSON.parse(fs.readFileSync(argv.pilconfig.trim())) : {}; const constFile = typeof(argv.const) === "string" ? argv.const.trim() : "mycircuit.const"; - const starkStructFile = typeof(argv.starkstruct) === "string" ? argv.starkstruct.trim() : "mycircuit.stark_struct.json"; + const starkInfoFile = typeof(argv.starkinfo) === "string" ? argv.starkinfo.trim() : "mycircuit.stark_struct.json"; const constTreeFile = typeof(argv.consttree) === "string" ? argv.consttree.trim() : "mycircuit.consttree"; const verKeyFile = typeof(argv.verkey) === "string" ? argv.verkey.trim() : "mycircuit.verkey.json"; - const starkStruct = JSON.parse(await fs.promises.readFile(starkStructFile, "utf8")); + const starkInfo = JSON.parse(await fs.promises.readFile(starkInfoFile, "utf8")); const pil = await compile(F, pilFile, null, pilConfig); const constPols = newConstantPolsArray(pil, F); await constPols.loadFromFile(constFile); - let arity = Number(argv.arity) || 16; - const {MH, constTree, verKey} = await buildConstTree(starkStruct, pil, constPols, arity); + const {MH, constTree, verKey} = await buildConstTree(starkInfo, pil, constPols); await fs.promises.writeFile(verKeyFile, JSONbig.stringify(verKey, null, 1), "utf8"); diff --git a/src/main_calculateimpols.js b/src/main_calculateimpols.js new file mode 100644 index 00000000..74e7967b --- /dev/null +++ b/src/main_calculateimpols.js @@ -0,0 +1,38 @@ +const fs = require("fs"); +const version = require("../package").version; + +const { calculateIntermediatePolynomials } = require("./pil_info/imPolsCalculation/imPolynomials"); + +const argv = require("yargs") + .version(version) + .usage("node main_calculateimpols.js -f -m ") + .alias("f", "infopil") + .alias("m", "impols") + .argv; + +async function run() { + const infoPilFile = typeof(argv.infopil) === "string" ? argv.infopil.trim() : "mycircuit.infopil.json"; + const imPolsFile = typeof(argv.impols) === "string" ? argv.impols.trim() : "mycircuit.impols.json"; + + const infoPil = JSON.parse(await fs.promises.readFile(infoPilFile, "utf8")); + + const expressions = infoPil.expressions; + const maxDeg = infoPil.maxDeg; + const cExpId = infoPil.cExpId; + const qDim = infoPil.qDim; + + const imPols = calculateIntermediatePolynomials(expressions, cExpId, maxDeg, qDim); + + await fs.promises.writeFile(imPolsFile, JSON.stringify(imPols, null, 1), "utf8"); + + console.log("files Generated Correctly"); +} + +run().then(()=> { + process.exit(0); +}, (err) => { + console.log(err.message); + console.log(err.stack); + process.exit(1); +}); + diff --git a/src/main_genpilcode.js b/src/main_genpilcode.js new file mode 100644 index 00000000..d2cceb12 --- /dev/null +++ b/src/main_genpilcode.js @@ -0,0 +1,66 @@ +const fs = require("fs"); +const version = require("../package").version; + +const { generatePilCode } = require("./pil_info/generatePilCode"); +const { addIntermediatePolynomials } = require("./pil_info/imPolsCalculation/imPolynomials"); +const map = require("./pil_info/map"); +const { compile } = require("pilcom"); +const F3g = require("./helpers/f3g"); + +const argv = require("yargs") + .version(version) + .usage("node main_genpilcode.js -f -p -m -i ") + .alias("p", "pil") + .alias("f", "infopil") + .alias("m", "impols") + .alias("i", "starkinfo") + .argv; + +async function run() { + const F = new F3g(); + + const infoPilFile = typeof(argv.infopil) === "string" ? argv.infopil.trim() : "mycircuit.infopil.json"; + const imPolsFile = typeof(argv.impols) === "string" ? argv.impols.trim() : "mycircuit.impols.json"; + + const pilFile = typeof(argv.pil) === "string" ? argv.pil.trim() : "mycircuit.pil"; + const pil = await compile(F, pilFile); + + const starkInfoFile = typeof(argv.starkinfo) === "string" ? argv.starkinfo.trim() : "mycircuit.starkinfo.json"; + + const infoPil = JSON.parse(await fs.promises.readFile(infoPilFile, "utf8")); + const imPols = JSON.parse(await fs.promises.readFile(imPolsFile, "utf8")); + + const res = infoPil.res; + const expressions = imPols.newExpressions; + const qDeg = imPols.qDeg; + const imExps = imPols.imExps; + + addIntermediatePolynomials(res, expressions, imExps, qDeg); + + generatePilCode(res, pil, expressions); + + map(res, expressions); + + console.log("--------------------- POLINOMIALS INFO ---------------------") + console.log(`Columns stage 1: ${res.nCm1} -> Columns in the basefield: ${res.mapSectionsN.cm1_2ns}`); + console.log(`Columns stage 2: ${res.nCm2} -> Columns in the basefield: ${res.mapSectionsN.cm2_2ns}`); + console.log(`Columns stage 3: ${res.nCm3} (${res.nImPols} intermediate polinomials) -> Columns in the basefield: ${res.mapSectionsN.cm3_2ns}`); + console.log(`Columns stage 4: ${res.nCm4} -> Columns in the basefield: ${res.mapSectionsN.cm4_2ns}`); + console.log(`Total Columns: ${res.nCm1 + res.nCm2 + res.nCm3 + res.nCm4} -> Total Columns in the basefield: ${res.mapSectionsN.cm1_2ns + res.mapSectionsN.cm2_2ns + res.mapSectionsN.cm3_2ns + res.mapSectionsN.cm4_2ns}`); + console.log(`Total Constraints: ${res.nConstraints}`) + console.log(`Number of evaluations: ${res.evMap.length}`) + console.log("------------------------------------------------------------") + + await fs.promises.writeFile(starkInfoFile, JSON.stringify(res, null, 1), "utf8"); + + console.log("files Generated Correctly"); +} + +run().then(()=> { + process.exit(0); +}, (err) => { + console.log(err.message); + console.log(err.stack); + process.exit(1); +}); + diff --git a/src/main_genstarkinfo.js b/src/main_genstarkinfo.js index 0d3775af..3ef248a3 100644 --- a/src/main_genstarkinfo.js +++ b/src/main_genstarkinfo.js @@ -12,6 +12,7 @@ const argv = require("yargs") .alias("P", "pilconfig") .alias("s", "starkstruct") .alias("i", "starkinfo") + .string("arity") .argv; async function run() { @@ -26,7 +27,11 @@ async function run() { const pil = await compile(F, pilFile, null, pilConfig); const starkStruct = JSON.parse(await fs.promises.readFile(starkStructFile, "utf8")); - const starkInfo = starkInfoGen(pil, starkStruct); + const options = {}; + if(starkStruct.verificationHashType === "BN128") { + options.arity = Number(argv.arity) || 16; + } + const starkInfo = starkInfoGen(pil, starkStruct, options); await fs.promises.writeFile(starkInfoFile, JSON.stringify(starkInfo, null, 1), "utf8"); diff --git a/src/main_pil2circom.js b/src/main_pil2circom.js index d01432c3..f7182b0f 100644 --- a/src/main_pil2circom.js +++ b/src/main_pil2circom.js @@ -10,23 +10,18 @@ const JSONbig = require('json-bigint')({ useNativeBigInt: true, alwaysParseAsBig const argv = require("yargs") .version(version) - .usage("node main_pil2circom.js -o -v -s [--skipMain] [--enableInput] [--verkeyInput] [--arity]") + .usage("node main_pil2circom.js -o -v -s [--skipMain] [--enableInput] [--verkeyInput]") .alias("s", "starkinfo") .alias("v", "verkey") .alias("o", "output") - .string("arity") .string("index") .argv; async function run() { - const starkInfoFIle = typeof(argv.starkinfo) === "string" ? argv.starkinfo.trim() : "starkinfo.json"; - const verKeyFile = typeof(argv.verkey) === "string" ? argv.verkey.trim() : "mycircuit.verkey.json"; + const starkInfoFile = typeof(argv.starkinfo) === "string" ? argv.starkinfo.trim() : "starkinfo.json"; const outputFile = typeof(argv.output) === "string" ? argv.output.trim() : "mycircuit.verifier.circom"; - - const verKey = JSONbig.parse(await fs.promises.readFile(verKeyFile, "utf8")); - const constRoot = verKey.constRoot; - - const starkInfo = JSON.parse(await fs.promises.readFile(starkInfoFIle, "utf8")); + + const starkInfo = JSON.parse(await fs.promises.readFile(starkInfoFile, "utf8")); const options = { skipMain: argv.skipMain || false, @@ -34,9 +29,13 @@ async function run() { verkeyInput: argv.verkeyInput || false } - if(starkInfo.starkStruct.verificationHashType === "BN128") { - options.arity = Number(argv.arity) || 16; - console.log(`Arity: ${options.arity}`); + let constRoot; + if(!options.verkeyInput ) { + const verKeyFile = typeof(argv.verkey) === "string" ? argv.verkey.trim() : "mycircuit.verkey.json"; + const verKey = JSONbig.parse(await fs.promises.readFile(verKeyFile, "utf8")); + + constRoot = verKey.constRoot; + } if(argv.index) { diff --git a/src/main_preparepil.js b/src/main_preparepil.js new file mode 100644 index 00000000..cfa98210 --- /dev/null +++ b/src/main_preparepil.js @@ -0,0 +1,51 @@ +const fs = require("fs"); +const version = require("../package").version; + +const F3g = require("./helpers/f3g.js"); +const { compile } = require("pilcom"); +const { preparePil } = require("./pil_info/preparePil"); + +const argv = require("yargs") + .version(version) + .usage("node main_preparepil.js -p [-P -f ") + .alias("p", "pil") + .alias("P", "pilconfig") + .alias("s", "starkstruct") + .alias("f", "infopil") + .argv; + +async function run() { + const F = new F3g(); + + const pilFile = typeof(argv.pil) === "string" ? argv.pil.trim() : "mycircuit.pil"; + const pilConfig = typeof(argv.pilconfig) === "string" ? JSON.parse(fs.readFileSync(argv.pilconfig.trim())) : {}; + + const starkStructFile = typeof(argv.starkstruct) === "string" ? argv.starkstruct.trim() : "mycircuit.stark_struct.json"; + + const infoPilFile = typeof(argv.infopil) === "string" ? argv.infopil.trim() : "mycircuit.infopil.json"; + + let pil = await compile(F, pilFile, null, pilConfig); + + const starkStruct = JSON.parse(await fs.promises.readFile(starkStructFile, "utf8")); + + const infoPil = preparePil(F, pil, starkStruct); + + let maxDeg = (1 << (starkStruct.nBitsExt - starkStruct.nBits)) + 1; + + const infoPilJSON = { maxDeg, cExpId: infoPil.res.cExpId, qDim: infoPil.res.qDim, ...infoPil }; + + console.log("Writing file..."); + + await fs.promises.writeFile(infoPilFile, JSON.stringify(infoPilJSON, null, 1), "utf8"); + + console.log("files Generated Correctly"); +} + +run().then(()=> { + process.exit(0); +}, (err) => { + console.log(err.message); + console.log(err.stack); + process.exit(1); +}); + diff --git a/src/main_prover.js b/src/main_prover.js index 70dc3236..34b2b86d 100644 --- a/src/main_prover.js +++ b/src/main_prover.js @@ -26,7 +26,6 @@ const argv = require("yargs") .alias("z", "zkin") .alias("b", "public") .string("proverAddr") - .string("arity") .argv; async function run() { @@ -52,24 +51,19 @@ async function run() { const cmPols = newCommitPolsArray(pil); await cmPols.loadFromFile(commitFile); - let options = {}; let MH; if (starkInfo.starkStruct.verificationHashType == "GL") { MH = await buildMerklehashGL(); } else if (starkInfo.starkStruct.verificationHashType == "BN128") { - let arity = Number(argv.arity) || 16; - - options = {arity}; - - console.log(`Arity: ${arity}`); - MH = await buildMerkleHashBN128(arity); + console.log(`Merkle Tree Arity: ${starkInfo.merkleTreeArity}`); + MH = await buildMerkleHashBN128(starkInfo.merkleTreeArity); } else { throw new Error("Invalid Hash Type: "+ starkInfo.starkStruct.verificationHashType); } const constTree = await MH.readFromFile(constTreeFile); - const resP = await starkGen(cmPols, constPols, constTree, starkInfo, options); + const resP = await starkGen(cmPols, constPols, constTree, starkInfo); await fs.promises.writeFile(proofFile, JSONbig.stringify(resP.proof, null, 1), "utf8"); diff --git a/src/main_verifier.js b/src/main_verifier.js index 1c3b4afd..401c7dda 100644 --- a/src/main_verifier.js +++ b/src/main_verifier.js @@ -10,7 +10,6 @@ const argv = require("yargs") .alias("v", "verkey") .alias("o", "proof") .alias("b", "public") - .string("arity") .argv; async function run() { @@ -28,14 +27,7 @@ async function run() { proof = str2bigInt(proof); - let options = {}; - if (starkInfo.starkStruct.verificationHashType === "BN128") { - options.arity = Number(argv.arity) || 16; - console.log(`Arity: ${options.arity}`); - - } - - const resV = await starkVerify(proof, public, constRoot, starkInfo, options); + const resV = await starkVerify(proof, public, constRoot, starkInfo); if (resV === true) { console.log("Verification Ok!!") diff --git a/src/pil2circom.js b/src/pil2circom.js index e9b81d75..d911ab1b 100644 --- a/src/pil2circom.js +++ b/src/pil2circom.js @@ -33,8 +33,8 @@ module.exports = async function pil2circom(constRoot, starkInfo, options) { starkStruct: starkStruct, constRoot: constRoot, options: options, - arity: Number(options.arity), - nBitsArity: log2(options.arity), + arity: starkInfo.merkleTreeArity, + nBitsArity: log2(starkInfo.merkleTreeArity), arityTranscript: 16, }; diff --git a/src/pil_info/code/generateCode.js b/src/pil_info/code/generateCode.js new file mode 100644 index 00000000..be36d5af --- /dev/null +++ b/src/pil_info/code/generateCode.js @@ -0,0 +1,238 @@ +const { pilCodeGen, buildCode, iterateCode } = require("../codegen"); + +module.exports.generatePublicsCode = function generatePublicsCode(res, pil, expressions) { + res.publicsCode = []; + for (let i=0; i= 0) { + r.type = "cm"; + r.id = res.imExp2cm[res.imExpsList[idx]]; + // Treat it as a commit. + } else { + const p = r.prime ? 1 : 0; + if (typeof ctx.expMap[p][r.id] === "undefined") { + ctx.expMap[p][r.id] = ctx.code.tmpUsed ++; + } + r.type= "tmp"; + r.expId = r.id; + r.id= ctx.expMap[p][r.id]; + break; + } + case "cm": + case "const": + if (typeof res.evIdx[r.type][p][r.id] === "undefined") { + res.evIdx[r.type][p][r.id] = res.evMap.length; + const rf = { + type: r.type, + id: r.id, + prime: r.prime ? true : false, + }; + res.evMap.push(rf); + } + delete r.prime; + r.id= res.evIdx[r.type][p][r.id]; + r.type= "eval"; + break; + case "number": + case "challenge": + case "public": + case "tmp": + case "Z": + case "x": + case "eval": + break; + default: + throw new Error("Invalid reference type: "+r.type); + } + } +} + + +module.exports.generateFRICode = function generateFRICode(res, pil, expressions) { + const ctxExt = { + pil, + calculated: {exps: {}, expsPrime: {}}, + tmpUsed: 0, + code: [], + expMap: [], + dom: "ext", + }; + + pilCodeGen(ctxExt, expressions, res.friExpId, false); + + const code = ctxExt.code[ctxExt.code.length-1].code; + + code[code.length-1].dest = { type: "f", id: 0 }; + + res.step52ns = buildCode(ctxExt, expressions); + + ctxExt.verifierQuery = true; + ctxExt.addMul = false; + + const ctxExt2 = { + pil, + calculated: {exps: {}, expsPrime: {}}, + tmpUsed: 0, + code: [], + expMap: [], + dom: "ext", + }; + + pilCodeGen(ctxExt2, expressions, res.friExpId); + res.verifierQueryCode = buildCode(ctxExt2, expressions); +} diff --git a/src/pil_info/codegen.js b/src/pil_info/codegen.js index 47718137..dd2437fe 100644 --- a/src/pil_info/codegen.js +++ b/src/pil_info/codegen.js @@ -1,13 +1,13 @@ -function pilCodeGen(ctx, expId, prime, addMul) { +function pilCodeGen(ctx, expressions, expId, prime) { prime = prime || false; const primeIdx = prime ? "expsPrime" : "exps"; if (ctx.calculated[primeIdx][expId]) return; - calculateDeps(ctx, ctx.pil.expressions[expId], prime, expId); + calculateDeps(ctx, expressions, expressions[expId], prime); const codeCtx = { pil: ctx.pil, @@ -16,12 +16,7 @@ function pilCodeGen(ctx, expId, prime, addMul) { code: [] } - let e; - if (addMul) { - e = findAddMul(ctx.pil.expressions[expId]); - } else { - e = ctx.pil.expressions[expId]; - } + let e = expressions[expId]; const retRef = evalExp(codeCtx, e, prime); if (retRef.type == "tmp") { @@ -227,14 +222,14 @@ function evalExp(codeCtx, exp, prime) { } -function calculateDeps(ctx, exp, prime, expIdErr, addMul) { +function calculateDeps(ctx, expressions, exp, prime) { if (exp.op == "exp") { if (prime && exp.next) expressionError(ctx.pil, `Double prime`, expIdErr, exp.id); - pilCodeGen(ctx, exp.id, prime || exp.next, addMul); + pilCodeGen(ctx, expressions, exp.id, prime || exp.next); } if (exp.values) { for (let i=0; i=0 ) { - let md =0; - for (let i=0; imd) md = d; - } - return [imExpressions, md]; - } else if (["number", "public", "challenge"].indexOf(exp.op) >=0 ) { - return [imExpressions, 0]; - } else if (["x", "const", "cm"].indexOf(exp.op) >= 0) { - if (maxDeg < 1) { - return [false, -1]; - } - return [imExpressions, 1]; - } else if (exp.op == "mul") { - let eb = false; - let ed = -1; - if (["number", "public", "challenge"].indexOf(exp.values[0].op) >= 0 ) { - return _calculateImPols(pil, exp.values[1], imExpressions, maxDeg); - } - if (["number", "public", "challenge"].indexOf(exp.values[1].op) >= 0 ) { - return _calculateImPols(pil, exp.values[0], imExpressions, maxDeg); - } - const maxDegHere = getExpDim(pil, exp, maxDeg); - if (maxDegHere <= maxDeg) { - return [imExpressions, maxDegHere]; - } - for (let l=0; l<=maxDeg; l++) { - let r = maxDeg-l; - const [e1, d1] = _calculateImPols(pil, exp.values[0], imExpressions, l); - const [e2, d2] = _calculateImPols(pil, exp.values[1], e1, r ); - if (e2 !== false) { - if (eb === false) { - eb = e2; - ed = d1+d2; - } else { - if (Object.keys(e2).length < Object.keys(eb).length) { - eb=e2; - ed = d1+d2; - } - } - } - if (eb !== false) { - if (Object.keys(eb).length == Object.keys(imExpressions).length) return [eb, ed]; // Cannot o it better. - } - } - return [eb, ed] - } else if (exp.op == "exp") { - if (maxDeg < 1) { - return [false, -1]; - } - if (imExpressions[exp.id]) return [imExpressions, 1]; - let e,d; - if(exp.res && exp.res[absoluteMax] && exp.res[absoluteMax][JSON.stringify(imExpressions)]) { - [e,d] = exp.res[absoluteMax][JSON.stringify(imExpressions)]; - } else { - [e,d] = _calculateImPols(pil, pil.expressions[exp.id], imExpressions, absoluteMax); - } - if (e === false) { - return [false, -1]; - } - if (d > maxDeg) { - const ce = Object.assign({}, e); - ce[exp.id] = true; - if (d>absMaxD) absMaxD = d; - return [ce, 1]; - } else { - if(!exp.res) exp.res = {}; - if(!exp.res[absoluteMax]) exp.res[absoluteMax] = {}; - exp.res[absoluteMax][JSON.stringify(imExpressions)] = [e, d]; - return exp.res[absoluteMax][JSON.stringify(imExpressions)]; - } - } else { - throw new Error("Exp op not defined: "+ exp.op); - } - } - -} - - -function getExpDim(pil, exp, maxDeg) { - switch (exp.op) { - case "add": - case "sub": - case "addc": - case "mulc": - case "neg": - const d = Math.max(...exp.values.map(v => getExpDim(pil, v, maxDeg))); - return d; - case "mul": - return getExpDim(pil, exp.values[0], maxDeg) + getExpDim(pil, exp.values[1], maxDeg) - case "muladd": - return Math.max(getExpDim(pil, exp.values[0], maxDeg) + getExpDim(pil, exp.values[1], maxDeg), getExpDim(pil, exp.values[2], maxDeg)); - case "cm": return 1; - case "const": return 1; - case "exp": - if(exp.dim && exp.dim[maxDeg] >= 0) return exp.dim[maxDeg]; - if(!exp.dim) exp.dim = {}; - exp.dim[maxDeg] = getExpDim(pil, pil.expressions[exp.id], maxDeg); - return exp.dim[maxDeg]; - case "number": return 0; - case "public": return 0; - case "challenge": return 0; - case "eval": return 0; - case "x": return 1; - default: throw new Error("Exp op not defined: " + exp.op); - } -} \ No newline at end of file diff --git a/src/pil_info/cp_ver.js b/src/pil_info/cp_ver.js deleted file mode 100644 index 6346b1fe..00000000 --- a/src/pil_info/cp_ver.js +++ /dev/null @@ -1,87 +0,0 @@ -const {pilCodeGen, buildCode, iterateCode} = require("./codegen.js"); - -module.exports = function generateConstraintPolynomialVerifier(res, pil, addMul) { - const ctxC = { - pil: pil, - calculated: { - exps: Object.assign({}, res.imExps), - expsPrime: Object.assign({}, res.imExps) - }, - tmpUsed: 0, - code: [] - }; - - pilCodeGen(ctxC, res.cExp, false, addMul); - - res.verifierCode = buildCode(ctxC); - - res.evIdx = { - cm: [{}, {}], - const: [{}, {}], - } - - res.evMap = []; - - const ctxF = {}; - ctxF.expMap = [{}, {}]; - ctxF.code = res.verifierCode; - - iterateCode(res.verifierCode, fixRef, ctxF); - - for (let i=0; i= 0) { - r.type = "cm"; - r.id = res.imExp2cm[res.imExpsList[idx]]; - // Treat it as a commit. - } else { - const p = r.prime ? 1 : 0; - if (typeof ctx.expMap[p][r.id] === "undefined") { - ctx.expMap[p][r.id] = ctx.code.tmpUsed ++; - } - r.type= "tmp"; - r.expId = r.id; - r.id= ctx.expMap[p][r.id]; - break; - } - case "cm": - case "const": - if (typeof res.evIdx[r.type][p][r.id] === "undefined") { - res.evIdx[r.type][p][r.id] = res.evMap.length; - const rf = { - type: r.type, - id: r.id, - prime: r.prime ? true : false, - }; - res.evMap.push(rf); - } - delete r.prime; - r.id= res.evIdx[r.type][p][r.id]; - r.type= "eval"; - break; - case "number": - case "challenge": - case "public": - case "tmp": - case "Z": - case "x": - case "eval": - break; - default: - throw new Error("Invalid reference type: "+r.type); - } - } -} diff --git a/src/pil_info/fri_verifier.js b/src/pil_info/fri_verifier.js deleted file mode 100644 index 3a5a685a..00000000 --- a/src/pil_info/fri_verifier.js +++ /dev/null @@ -1,24 +0,0 @@ - -const {pilCodeGen, buildCode} = require("./codegen.js"); - -module.exports = function generateVerifierQuery(res, pil, addMul) { - - const ctxFri = { - pil: pil, - calculated: { - exps: {}, - expsPrime: {} - }, - tmpUsed: 0, - code: [] - }; - - pilCodeGen(ctxFri, res.friExpId, false, addMul); - res.verifierQueryCode = buildCode(ctxFri); - res.nExps = pil.expressions.length; - - const ctxF = {}; - ctxF.expMap = [{}, {}]; - ctxF.code = res.verifierQueryCode; -} - diff --git a/src/pil_info/generatePilCode.js b/src/pil_info/generatePilCode.js new file mode 100644 index 00000000..084ecff8 --- /dev/null +++ b/src/pil_info/generatePilCode.js @@ -0,0 +1,19 @@ +const generateFRIPolynomial = require("./polynomials/friPolinomial"); + +const { generateConstraintPolynomialCode, generateConstraintPolynomialVerifierCode, generateFRICode, generatePublicsCode, generateStagesCode } = require("./code/generateCode"); + +module.exports.generatePilCode = function generatePilCode(res, pil, expressions) { + generatePublicsCode(res, pil, expressions); + + generateStagesCode(res, pil, expressions); + + generateConstraintPolynomialCode(res, pil, expressions); + + generateConstraintPolynomialVerifierCode(res, pil, expressions); + + generateFRIPolynomial(res, expressions); + + generateFRICode(res, pil, expressions); + + return res; +} \ No newline at end of file diff --git a/src/pil_info/generatePolynomials.js b/src/pil_info/generatePolynomials.js new file mode 100644 index 00000000..7429d7ea --- /dev/null +++ b/src/pil_info/generatePolynomials.js @@ -0,0 +1,30 @@ +const { log2 } = require("pilcom/src/utils"); +const { grandProductConnection } = require("./libs/grandProductConnection"); +const { grandProductPermutation } = require("./libs/grandProductPermutation"); +const { grandProductPlookup } = require("./libs/grandProductPlookup"); + +module.exports.generatePolynomials = function generatePolynomials(F, res, _pil) { + const pil = JSON.parse(JSON.stringify(_pil)); // Make a copy as we are going to destroy the original + + res.nPublics = pil.publics.length; + res.nConstants = pil.nConstants; + + res.nCm1 = pil.nCommitments; + res.nCm2 = 0; + res.nCm3 = 0; + + grandProductPlookup(res, pil); + + grandProductPermutation(res, pil); + + grandProductConnection(res, pil, F); + + res.nCommitments = pil.nCommitments; + res.pilPower = log2(Object.values(pil.references)[0].polDeg); + + const expressions = [...pil.expressions]; + const constraints = [...pil.polIdentities] + const publicsInfo = pil.publics; + + return { publicsInfo, expressions, constraints }; +} diff --git a/src/pil_info/helpers.js b/src/pil_info/helpers.js new file mode 100644 index 00000000..a9326b2e --- /dev/null +++ b/src/pil_info/helpers.js @@ -0,0 +1,37 @@ + +module.exports.getExpDim = function getExpDim(expressions, cmDims, expId) { + + return _getExpDim(expressions[expId]); + + function _getExpDim(exp) { + if(typeof(exp.dimMap) !== "undefined") return exp.dimMap; + switch (exp.op) { + case "add": + case "sub": + case "mul": + case "muladd": + case "addc": + case "mulc": + case "neg": + let md = 1; + for (let i=0; imd) md=d; + } + return md; + case "cm": return cmDims[exp.id]; + case "const": return 1; + case "exp": + exp.dimMap = _getExpDim(expressions[exp.id]); + return exp.dimMap; + case "number": return 1; + case "public": return 1; + case "challenge": return 3; + case "eval": return 3; + case "xDivXSubXi": return 3; + case "xDivXSubWXi": return 3; + case "x": return 1; + default: throw new Error("Exp op not defined: " + exp.op); + } + } +} diff --git a/src/pil_info/imPolsCalculation/calculateImPols.py b/src/pil_info/imPolsCalculation/calculateImPols.py new file mode 100644 index 00000000..51daa2fb --- /dev/null +++ b/src/pil_info/imPolsCalculation/calculateImPols.py @@ -0,0 +1,259 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Tue Sep 19 11:56:27 2023 + +@author: clara +""" + + +import smt_generation_pil_2 +import json + + + # The degree is the maximum of the list +def mix_degrees(deg_1, deg_2, deg_3): + result = [] + for d in deg_3: + result.append(d) + for i in deg_1: + for j in deg_2: + result.append((i, j)) + return result + + +def get_used_expressions(expr, expressions, used_expressions): + type_union = {"add", "sub", "mul"} + + if expr["op"] in type_union: + values = expr["values"] + for e in values: + get_used_expressions(e, expressions, used_expressions) + elif expr["op"] == "exp": + if not int(expr["id"]) in used_expressions: + used_expressions.add(int(expr["id"])) + get_used_expressions(expressions[int(expr["id"])], expressions, used_expressions) + + + +def parse_expression_pil(expression): + # result: Possible max values + result = 0 + type_add = {"add", "sub", "neg"} + + if expression["op"] in type_add: + result = [] + for e in expression["values"]: + result.append(parse_expression_pil(e)) + elif expression["op"] == "mul": + values = expression["values"] + result = (parse_expression_pil(values[0]), parse_expression_pil(values[1])) + elif expression["op"] == "exp": + result = "exp_" + str(expression["id"]) + elif expression["op"] == "challenge": + result = 0 + else: + result = int(expression["expDeg"]) + return result + + +def minimize_expression_pil(tree, zero_expressions, one_expressions): + if type(tree) == list: + # Case addition -> we take the maximum of the degrees + max_value = 0 + needs_consider = [] + for expr in tree: + new_value = minimize_expression_pil(expr, zero_expressions, one_expressions) + if type(new_value) == int: + if new_value > max_value: + max_value = new_value + elif type(new_value) == list: + needs_consider = needs_consider + new_value + else: + needs_consider.append(new_value) + if len(needs_consider) == 0: + needs_consider = max_value + else: + if max_value > 0: + needs_consider.append(max_value) + if len(needs_consider) == 1: + needs_consider = needs_consider[0] + return needs_consider + elif type(tree) == tuple: + # Case multiplication: in case both number we add the degrees + new_value_a = minimize_expression_pil(tree[0], zero_expressions, one_expressions) + new_value_b = minimize_expression_pil(tree[1], zero_expressions, one_expressions) + + if type(new_value_a) == int and type(new_value_b) == int: + return new_value_a + new_value_b + else: + if new_value_a == 0: + return new_value_b + elif new_value_b == 0: + return new_value_a + else: + return (new_value_a, new_value_b) + elif type(tree) == int: + return tree + else: + #Case expression + if tree in zero_expressions: + return 0 + elif tree in one_expressions: + return 1 + else: + return tree + +# TODO: Check this function as it is not exactly the same as the one in JS +def calculate_added_cols(expressions, used_variables, q_deg, q_dim): + q_cols = q_deg * q_dim + im_cols = 0 + for v in used_variables: + im_cols += expressions[v]["dim"] + added_cols = q_cols + im_cols + print("maxDeg: " + str(q_deg + 1) + ", nIm: " + str(len(used_variables)) + ", d: " + str(q_deg) + ", addedCols in the basefield: " + str(added_cols) + " (" + str(q_cols) + " + " + str(im_cols) + ")") + return added_cols + + +def rebuild_expression(exp, expressions, used_expressions, new_map_expressions): + + type_operation = {"add", "sub", "mul"} + new_expression = {} + if exp["op"] in type_operation: + new_expression["op"] = exp["op"] + new_values = [] + for e in exp["values"]: + new_values.append(rebuild_expression(e, expressions, used_expressions, new_map_expressions)) + new_expression["values"] = new_values + elif exp["op"] == "exp": + id_expr = int(exp["id"]) + if id_expr in used_expressions: + new_expression = exp + else: + new_expression = new_map_expressions[id_expr] + else: + new_expression = exp + return new_expression + + +import sys +sys.setrecursionlimit(10000) + +import argparse +parser = argparse.ArgumentParser() + +parser.add_argument("filein", help=".json file including the tree structure", + type=str) +parser.add_argument("fileout", help= "Output file with the new expressions") + + +args=parser.parse_args() + +# Opening JSON file +f = open(args.filein) +data = json.load(f) + +file = open(args.fileout, "w") + +expressions = data["expressions"] +cExpId = int(data["cExpId"]) +degree = int(data["maxDeg"]) +q_dim = int(data["qDim"]) +used_expressions = {cExpId} +get_used_expressions(expressions[cExpId], expressions, used_expressions) +all_used = len(used_expressions) == len(expressions) + +number_intermediates = len(expressions) + +from z3 import * + + +i = 0 +one_expressions = set() +zero_expressions = set() + +trees = {} + +for e in expressions: + if all_used or i in used_expressions: + tree = parse_expression_pil(e) + + #print("Printing tree " + str(i)) + #print(tree) + #print("---------") + + new_tree = minimize_expression_pil(tree, zero_expressions, one_expressions) + if new_tree == 0: + zero_expressions.add("exp_" + str(i)) + if new_tree == 1: + one_expressions.add("exp_" + str(i)) + #print(new_tree) + #print("--------------------") + + if new_tree != 0 and new_tree != 1: + trees[i] = new_tree + i = i + 1 + +min_value = -1 +optimal_degree = -1 +min_vars = len(expressions) +possible_degree = 2 + +print("*** Considering degrees between 2 and " + str(degree) + " ***") +print() + +while min_vars != 0 and possible_degree <= degree: + # Try with degree possible_degree, declare smt problem and try to solve it + print("--- Using degree " + str(possible_degree) + " ---") + solver = Optimize() + smt_generation_pil_2.declare_keep_variables(number_intermediates, possible_degree, solver) + for (index, value) in trees.items(): + smt_generation_pil_2.generate_expression_declaration(value, zero_expressions, one_expressions, index, possible_degree, solver) + smt_generation_pil_2.declare_minimize_keeps(number_intermediates, solver) + new_used_variables = smt_generation_pil_2.get_minimal_expressions(number_intermediates, solver) + + added_basefield_cols = calculate_added_cols(expressions, new_used_variables, possible_degree - 1, q_dim) + if min_value == -1 or added_basefield_cols < min_value: + min_value = added_basefield_cols + used_variables = new_used_variables + optimal_degree = possible_degree - 1 + if len(new_used_variables) < min_vars: + min_vars = len(new_used_variables) + possible_degree = possible_degree + 1 + print() + + +print("--> Choosing degree: " + str(optimal_degree)) +print("Variables that are kept:" + str(used_variables)) + +#new_map_expressions = {} +#i = 0 +#for e in expressions: +# new_e = rebuild_expression(e, expressions, used_variables, new_map_expressions) +# new_map_expressions[i] = new_e +# print("expresion " + str(i)) +# print(new_e) +# i = i + 1 + +result = {} + +used_index = list(used_variables) +used_index.sort() +filtered_expressions = [] +#for e in used_index: +# filtered_expressions.append(new_map_expressions[e]) + +solution = {} +solution["newExpressions"] = expressions +solution["imExps"] = used_index +solution["qDeg"] = optimal_degree + +json_object = json.dumps(solution, indent = 1, sort_keys=True) +file = open(args.fileout, "w") +file.write(json_object) +file.close() + + + + + diff --git a/src/pil_info/imPolsCalculation/imPolynomials.js b/src/pil_info/imPolsCalculation/imPolynomials.js new file mode 100644 index 00000000..b01b0e2e --- /dev/null +++ b/src/pil_info/imPolsCalculation/imPolynomials.js @@ -0,0 +1,215 @@ + +const ExpressionOps = require("../../helpers/expressionops"); + +module.exports.addIntermediatePolynomials = function addIntermediatePolynomials(res, expressions, imExps, qDeg) { + const E = new ExpressionOps(); + + console.log("Number of intermediate expressions: " + imExps.length); + console.log("Q degree: " + qDeg); + + res.qDeg = qDeg; + + + const vc = E.challenge("vc"); + + console.log("Checking that constraint polynomial numerator expression has degree less than qDeg + 1"); + const maxDegExpr = module.exports.calculateExpDeg(expressions, expressions[res.cExpId], imExps); + if(maxDegExpr > qDeg + 1) { + throw new Error(`The maximum degree of the constraint expression has a higher degree (${maxDegExpr}) than the maximum allowed degree (${qDeg + 1})`); + } + + res.imExpsList = imExps; + res.imExp2cm = {}; + + res.nImPols = res.imExpsList.length; + res.nConstraints += res.nImPols; + + let nImPolsDim1 = 0; + let nImPolsDim3 = 0; + console.log("Checking that intermediate polynomials have degree less than qDeg + 1"); + for (let i=0; i qDeg + 1) { + throw new Error(`Intermediate polynomial with id: ${expId} has a higher degree (${imPolDeg}) than the maximum allowed degree (${qDeg + 1})`); + } + } + + console.log(`nImPols in the basefield: ${nImPolsDim1}`) + console.log(`nImPols in the extended field: ${nImPolsDim3}`) + console.log(`Total imPols columns in the base field: ${nImPolsDim1 + 3*nImPolsDim3}`); + + console.log("Adding intermediate polynomials to the expressions and constraints."); + for (let i=0; i 0 && d <= maxQDeg) { + let [imExpsP, qDegP] = calculateImPols(expressions, cExp, d); + let newAddedBasefieldCols = calculateAddedCols(d, expressions, imExpsP, qDegP, qDim); + if ((maxQDeg && newAddedBasefieldCols < addedBasefieldCols) + || (!maxQDeg && imExpsP.length === 0)) { + [imExps, qDeg] = [imExpsP, qDegP]; + addedBasefieldCols = newAddedBasefieldCols; + } + if(imExpsP === 0) break; + d++; + } + + return {newExpressions: expressions, imExps, qDeg}; +} + + + +function calculateAddedCols(maxDeg, expressions, imExps, qDeg, qDim) { + let qCols = qDeg * qDim; + let imCols = 0; + for(let i = 0; i < imExps.length; i++) { + + imCols += expressions[imExps[i]].dim; + } + let addedCols = qCols + imCols; + console.log(`maxDeg: ${maxDeg}, nIm: ${imExps.length}, d: ${qDeg}, addedCols in the basefield: ${addedCols} (${qCols} + ${imCols})`); + + return addedCols; +} + + +function calculateImPols(expressions, _exp, maxDeg) { + + const imExpressions = []; + const absoluteMax = maxDeg; + let absMaxD = 0; + + [re, rd] = _calculateImPols(expressions, _exp, imExpressions, maxDeg); + + return [re, Math.max(rd, absMaxD) - 1]; // We divide the exp polynomial by 1. + + function _calculateImPols(expressions, exp, imExpressions, maxDeg) { + if (imExpressions === false) { + return [false, -1]; + } + if(["add", "sub", "neg"].indexOf(exp.op) >= 0) { + let md = 0; + for (let i=0; imd) md = d; + } + return [imExpressions, md]; + } else if (exp.op == "mul") { + let eb = false; + let ed = -1; + if (["number", "public", "challenge"].indexOf(exp.values[0].op) >= 0 ) { + return _calculateImPols(expressions, exp.values[1], imExpressions, maxDeg); + } + if (["number", "public", "challenge"].indexOf(exp.values[1].op) >= 0 ) { + return _calculateImPols(expressions, exp.values[0], imExpressions, maxDeg); + } + const maxDegHere = exp.expDeg; + if (maxDegHere <= maxDeg) { + return [imExpressions, maxDegHere]; + } + for (let l=0; l<=maxDeg; l++) { + let r = maxDeg-l; + const [e1, d1] = _calculateImPols(expressions, exp.values[0], imExpressions, l); + const [e2, d2] = _calculateImPols(expressions, exp.values[1], e1, r ); + if (e2 !== false) { + if (eb === false) { + eb = e2; + ed = d1+d2; + } else { + if (Object.keys(e2).length < Object.keys(eb).length) { + eb=e2; + ed = d1+d2; + } + } + } + if (eb !== false) { + if (Object.keys(eb).length == Object.keys(imExpressions).length) return [eb, ed]; // Cannot o it better. + } + } + return [eb, ed] + } else if (exp.op == "exp") { + if (maxDeg < 1) { + return [false, -1]; + } + if (imExpressions.findIndex(im => im === exp.id) !== -1) return [imExpressions, 1]; + let e,d; + if(exp.res && exp.res[absoluteMax] && exp.res[absoluteMax][JSON.stringify(imExpressions)]) { + [e,d] = exp.res[absoluteMax][JSON.stringify(imExpressions)]; + } else { + [e,d] = _calculateImPols(expressions, expressions[exp.id], imExpressions, absoluteMax); + } + if (e === false) { + return [false, -1]; + } + if (d > maxDeg) { + if (d>absMaxD) absMaxD = d; + return [[...e, exp.id], 1]; + } else { + if(!exp.res) exp.res = {}; + if(!exp.res[absoluteMax]) exp.res[absoluteMax] = {}; + exp.res[absoluteMax][JSON.stringify(imExpressions)] = [e, d]; + return exp.res[absoluteMax][JSON.stringify(imExpressions)]; + } + } else { + if(exp.expDeg === 0) { + return [imExpressions, 0]; + } else if (maxDeg < 1) { + return [false, -1]; + } else { + return [imExpressions, 1]; + } + } + } +} + +module.exports.calculateExpDeg = function calculateExpDeg(expressions, exp, imExps = [], expsDegs = []) { + if (exp.op == "exp") { + if (expsDegs[exp.id]) return expsDegs[exp.id]; + if (imExps.includes(exp.id)) return 1; + expsDegs[exp.id] = calculateExpDeg(expressions, expressions[exp.id], imExps, expsDegs); + return expsDegs[exp.id]; + } else if (["x", "const", "cm"].includes(exp.op) || (exp.op === "Zi" && exp.boundary !== "everyRow")) { + return 1; + } else if (["number", "public", "challenge", "eval", "subproofValue"].includes(exp.op) || (exp.op === "Zi" && exp.boundary === "everyRow")) { + return 0; + } else if(exp.op === "neg") { + return calculateExpDeg(expressions, exp.values[0], imExps, expsDegs); + } else if(["add", "sub", "mul"].includes(exp.op)) { + const lhsDeg = calculateExpDeg(expressions, exp.values[0], imExps, expsDegs); + const rhsDeg = calculateExpDeg(expressions, exp.values[1], imExps, expsDegs); + return exp.op === "mul" ? lhsDeg + rhsDeg : Math.max(lhsDeg, rhsDeg); + } else { + throw new Error("Exp op not defined: "+ exp.op); + } +} \ No newline at end of file diff --git a/src/pil_info/imPolsCalculation/smt_generation_pil_2.py b/src/pil_info/imPolsCalculation/smt_generation_pil_2.py new file mode 100644 index 00000000..a6a2d7c5 --- /dev/null +++ b/src/pil_info/imPolsCalculation/smt_generation_pil_2.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Fri May 26 17:51:23 2023 + +@author: clara +""" + +from z3 import * + + +def declare_minimize_keeps(number_intermediates, solver): + + aux = 0 + for s in range(number_intermediates): + aux = aux + If(Bool('k_exp_'+ str(s)), 1, 0) + solver.add(Int('needed_variables') == aux) + + +def declare_keep_variables(number_intermediates, n, solver): + for s in range(number_intermediates): + solver.add(Int('d_exp_' + str(s)) >= 0) + solver.add(Int('d_exp_' + str(s)) <= n) + +def generate_expression_declaration(tree, zero_expressions, one_expressions, position, n, solver): + possible_degrees = get_degrees_tree(tree, zero_expressions, one_expressions, "aux_" + str(position), n, solver) + if_keep = Int('d_exp_' + str(position)) == 1 + if_not_keep = Int('d_exp_' + str(position)) == possible_degrees + solver.add(If( Bool('k_exp_'+ str(position)), if_keep, if_not_keep)) + + + +def get_degrees_tree(tree, zero_expressions, one_expressions, prefix, n, solver): + if type(tree) == list: + solver.add(Int(prefix) <= n) + + or_condition = "false" + + i = 0 + for e in tree: + new_degree = get_degrees_tree(e, zero_expressions, one_expressions, prefix + '_' + str(i), n, solver) + solver.add(Int(prefix) >= new_degree) + + or_condition = or_condition or (prefix == new_degree) + i = i + 1 + #solver.add(or_condition) #check if helps + return Int(prefix) + elif type(tree) == tuple: + left_degree = get_degrees_tree(tree[0], zero_expressions, one_expressions, prefix + "_0", n, solver) + right_degree = get_degrees_tree(tree[1], zero_expressions, one_expressions, prefix + "_1", n, solver) + total_degree_var = Int(prefix + "_total_degree") + solver.add(total_degree_var <= n) # Set an upper bound constraint on the total degree + solver.add(total_degree_var == left_degree + right_degree) # Set the total degree of the tuple expression + return total_degree_var + elif type(tree) == int: + return tree + else: + if tree in zero_expressions: + return 0 + elif tree in one_expressions: + return 1 + else: + return Int('d_' + tree) + + + +def get_minimal_expressions(number_intermediates, solver): + solver.minimize(Int('needed_variables')) + if(solver.check() == sat): + m = solver.model() + print("Number of needed variables: " + str(m[z3.Int('needed_variables')])) + should_keep = set() + for s in range(number_intermediates): + if m[z3.Bool('k_exp_' + str(s))]: + should_keep.add(s) + + return should_keep + + \ No newline at end of file diff --git a/src/pil_info/libs/grandProductConnection.js b/src/pil_info/libs/grandProductConnection.js new file mode 100644 index 00000000..a014109a --- /dev/null +++ b/src/pil_info/libs/grandProductConnection.js @@ -0,0 +1,99 @@ + +const ExpressionOps = require("../../helpers/expressionops"); + +const getKs = require("pilcom").getKs; + +module.exports.grandProductConnection = function grandProductConnection(res, pil, F) { + const E = new ExpressionOps(); + + const gamma = E.challenge("gamma"); + const beta = E.challenge("beta"); + + res.ciCtx = []; + for (let i=0; i m === res.puCtx[i].fExpId)) { if ( typeof tmpExps[res.puCtx[i].fExpId] === "undefined") { tmpExps[res.puCtx[i].fExpId] = res.tmpExp_n.length; const ppf_n = addPol({ @@ -91,7 +92,7 @@ module.exports = function map(res, pil) { res.exp2pol[res.puCtx[i].fExpId] = ppf_n; } } - if (! res.imExps[res.puCtx[i].tExpId]) { + if (!res.imExpsList.find(m => m === res.puCtx[i].tExpId)) { if ( typeof tmpExps[res.puCtx[i].tExpId] === "undefined") { tmpExps[res.puCtx[i].tExpId] = res.tmpExp_n.length; const ppt_n = addPol({ @@ -126,9 +127,9 @@ module.exports = function map(res, pil) { res.cm_2ns.push(ppz_2ns); res.mapSections.cm3_n.push(ppz_n); res.mapSections.cm3_2ns.push(ppz_2ns); - pil.cmDims[res.nCm1 + res.nCm2 + i] = 3; + cmDims[res.nCm1 + res.nCm2 + i] = 3; - if (! res.imExps[o.numId]) { + if (!res.imExpsList.find(m => m === o.numId)) { if ( typeof tmpExps[o.numId] === "undefined") { tmpExps[o.numId] = res.tmpExp_n.length; const ppNum_n = addPol({ @@ -140,7 +141,7 @@ module.exports = function map(res, pil) { res.exp2pol[o.numId] = ppNum_n; } } - if (! res.imExps[o.denId]) { + if (!res.imExpsList.find(m => m === o.denId)) { if ( typeof tmpExps[o.denId] === "undefined") { tmpExps[o.denId] = res.tmpExp_n.length; const ppDen_n = addPol({ @@ -155,7 +156,7 @@ module.exports = function map(res, pil) { } for (let i=0; i { let p = 0; - for (let e of [1,3]) { - for (let i=0; imd) md=d; - } - return md; - case "cm": return pil.cmDims[exp.id]; - case "const": return 1; - case "exp": - exp.dimMap = _getExpDim(pil.expressions[exp.id]); - return exp.dimMap; - case "q": return _getExpDim(pil.expressions[pil.q2exp[exp.id]]); - case "number": return 1; - case "public": return 1; - case "challenge": return 3; - case "eval": return 3; - case "xDivXSubXi": return 3; - case "xDivXSubWXi": return 3; - case "x": return 1; - default: throw new Error("Exp op not defined: " + exp.op); - } - } -} - function setCodeDimensions(code, starkInfo, dimX) { const tmpDim = []; @@ -423,11 +385,6 @@ function setCodeDimensions(code, starkInfo, dimX) { case "tree3": d=r.dim; break; case "tree4": d=r.dim; break; case "tmpExp": d=r.dim; break; -/* - case "exp": d= starkInfo.varPolMap[starkInfo.exps_2ns[r.id]] ? - starkInfo.varPolMap[starkInfo.exps_2ns[r.id]].dim: - starkInfo.varPolMap[starkInfo.exps_n[r.id]].dim; break; -*/ case "cm": d=starkInfo.varPolMap[starkInfo.cm_2ns[r.id]].dim; break; case "q": d=starkInfo.varPolMap[starkInfo.qs[r.id]].dim; break; case "const": d=1; break; diff --git a/src/pil_info/polynomials/constraintPolynomial.js b/src/pil_info/polynomials/constraintPolynomial.js new file mode 100644 index 00000000..c6b0039d --- /dev/null +++ b/src/pil_info/polynomials/constraintPolynomial.js @@ -0,0 +1,30 @@ +const ExpressionOps = require("../../helpers/expressionops"); +const { getExpDim } = require("../helpers"); +const { calculateExpDeg } = require("../imPolsCalculation/imPolynomials"); + +module.exports.generateConstraintPolynomial = function generateConstraintPolynomial(res, expressions, constraints) { + + const E = new ExpressionOps(); + + const vc = E.challenge("vc"); + + let cExp = null; + for (let i=0; i e.op === "cm" && e.id === publicsInfo[i].polId); + if(expId === -1) { + const cm = E.cm(publicsInfo[i].polId); + cm.stage = 1; + expressions.push(cm); + expId = expressions.length-1; + } + } else { + expId = publicsInfo[i].polId; + } + + expressions[expId].dim = 1; + publics.push({name: publicsInfo[i].name, id: publicsInfo[i].id, expId, idx: publicsInfo[i].idx}); + } + return publics; +} diff --git a/src/pil_info/preparePil.js b/src/pil_info/preparePil.js new file mode 100644 index 00000000..2bc509f3 --- /dev/null +++ b/src/pil_info/preparePil.js @@ -0,0 +1,103 @@ + + +const { generatePolynomials } = require("./generatePolynomials"); +const { generateConstraintPolynomial } = require("../pil_info/polynomials/constraintPolynomial"); +const { getExpDim } = require("./helpers"); + + +module.exports.preparePil = function preparePil(F, pil, starkStruct, options = {}) { + const res = {}; + + for(let i = 0; i < pil.expressions.length; ++i) { + pil.expressions[i].stage = 1; + } + + let {expressions, constraints, publicsInfo} = generatePolynomials(F, res, pil); + + res.starkStruct = starkStruct; + if (res.starkStruct.nBits != res.pilPower) { + throw new Error(`starkStruct and pilfile have degree mismatch (starkStruct:${res.starkStruct.nBits} pilfile:${res.pilPower})`); + } + + if (res.starkStruct.nBitsExt != res.starkStruct.steps[0].nBits) { + throw new Error(`starkStruct.nBitsExt and first step of starkStruct have a mismatch (nBitsExt:${res.starkStruct.nBitsExt} pil:${res.starkStruct.steps[0].nBits})`); + } + + res.publics = publicsInfo; + + if(res.starkStruct.verificationHashType === "BN128") { + res.merkleTreeArity = options.arity || 16; + } + + res.cmDims = []; + + for(let i = 0; i < res.nCm1; ++i) { + res.cmDims[i] = 1; + } + + for(let i = 0; i < res.puCtx.length; ++i) { + const dim = Math.max(getExpDim(expressions, res.cmDims, res.puCtx[i].fExpId), getExpDim(expressions, res.cmDims, res.puCtx[i].tExpId)); + res.cmDims[res.nCm1 + i*2] = dim; + res.cmDims[res.nCm1 + i*2 + 1] = dim; + } + + for(let i = 0; i < res.nCm3; ++i) { + res.cmDims[res.nCm1 + res.nCm2 + i] = 3; + } + + for(let i = 0; i < constraints.length; ++i) { + addInfoExpressions(res, expressions, expressions[constraints[i].e]); + } + + generateConstraintPolynomial(res, expressions, constraints); + + res.nConstraints = constraints.length; + + delete res.cmDims; + + return {res, expressions, constraints} +} + + +function addInfoExpressions(res, expressions, exp) { + if("expDeg" in exp) return; + + if (exp.op == "exp") { + if (expressions[exp.id].expDeg) { + exp.expDeg = expressions[exp.id].expDeg; + exp.dim = expressions[exp.id].dim; + } + if (!exp.expDeg) { + addInfoExpressions(res, expressions, expressions[exp.id]); + exp.expDeg = expressions[exp.id].expDeg; + exp.dim = expressions[exp.id].dim; + } + } else if (["x", "const"].includes(exp.op)) { + exp.expDeg = 1; + exp.dim = 1; + } else if (exp.op === "cm") { + exp.expDeg = 1; + exp.dim = res.cmDims[exp.id]; + } else if (["number", "public"].includes(exp.op)) { + exp.expDeg = 0; + exp.dim = 1; + } else if (["challenge", "eval"].includes(exp.op)) { + exp.expDeg = 0; + exp.dim = 3; + } else if(exp.op === "neg") { + addInfoExpressions(res, expressions, exp.values[0]); + exp.expDeg = exp.values[0].expDeg; + exp.dim = exp.values[0].dim; + } else if(["add", "sub", "mul"].includes(exp.op)) { + addInfoExpressions(res, expressions, exp.values[0]); + addInfoExpressions(res, expressions, exp.values[1]); + const lhsDeg = exp.values[0].expDeg; + const rhsDeg = exp.values[1].expDeg; + exp.expDeg = exp.op === "mul" ? lhsDeg + rhsDeg : Math.max(lhsDeg, rhsDeg); + exp.dim = Math.max(exp.values[0].dim, exp.values[1].dim); + } else { + throw new Error("Exp op not defined: "+ exp.op); + } + + return; +} diff --git a/src/pil_info/publics.js b/src/pil_info/publics.js deleted file mode 100644 index 4bc40771..00000000 --- a/src/pil_info/publics.js +++ /dev/null @@ -1,42 +0,0 @@ - -const {pilCodeGen, buildCode, iterateCode} = require("./codegen.js"); - -module.exports = function generatePublicCalculators(res, pil) { - res.publicsCode = []; - for (let i=0; i Writing the chelpers file finished"); diff --git a/src/stark/chelpers/generateParser.js b/src/stark/chelpers/generateParser.js index 26ecefd2..ce1110da 100644 --- a/src/stark/chelpers/generateParser.js +++ b/src/stark/chelpers/generateParser.js @@ -1,168 +1,381 @@ const operationsMap = { "commit1": 1, + "x": 2, "const": 2, "tmp1": 3, "public": 4, - "x": 5, "number": 6, "commit3": 7, + "xDivXSubXi": 7, + "xDivXSubWXi": 7, + "q": 7, + "f": 7, "tmp3": 8, "challenge": 9, "eval": 10, - "xDivXSubXi": 11, - "xDivXSubWXi": 11, - "q": 12, - "f": 13, } -module.exports.generateParser = function generateParser(operations, operationsUsed, vectorizeEvals = false) { +module.exports.generateParser = function generateParser(operations, operationsUsed, parserType = "avx") { let c_args = 0; - - const parserCPP = [ - " uint64_t domainSize = domainExtended ? 1 << starkInfo.starkStruct.nBitsExt : 1 << starkInfo.starkStruct.nBits;", - " Polinomial &x = domainExtended ? params.x_2ns : params.x_n;", - " ConstantPolsStarks *constPols = domainExtended ? params.pConstPols2ns : params.pConstPols;", - " Goldilocks3::Element_avx challenges[params.challenges.degree()];", - " Goldilocks3::Element_avx challenges_ops[params.challenges.degree()];\n", - " uint8_t *ops = &parserArgs.ops[parserParams.opsOffset];\n", - " uint16_t *args = &parserArgs.args[parserParams.argsOffset]; \n", - " uint64_t* numbers = &parserArgs.numbers[parserParams.numbersOffset];\n", - " __m256i numbers_[parserParams.nNumbers];\n", - " uint64_t nStages = 3;", - " uint64_t nextStride = domainExtended ? 1 << (starkInfo.starkStruct.nBitsExt - starkInfo.starkStruct.nBits) : 1;", - " uint64_t nextStrides[2] = { 0, nextStride };", - ]; + if(!["avx", "avx512", "pack"].includes(parserType)) throw new Error("Invalid parser type"); + + let isAvx = ["avx", "avx512"].includes(parserType); + + let avxTypeElement; + let avxTypeExtElement; + let avxSet1Epi64; + let avxLoad; + let avxStore; + + if(isAvx) { + avxTypeElement = parserType === "avx" ? "__m256i" : "__m512i"; + avxTypeExtElement = parserType === "avx" ? "Goldilocks3::Element_avx" : "Goldilocks3::Element_avx512"; + avxSet1Epi64 = parserType === "avx" ? "_mm256_set1_epi64x" : "_mm512_set1_epi64"; + avxLoad = parserType === "avx" ? "load_avx" : "load_avx512"; + avxStore = parserType === "avx" ? "store_avx" : "store_avx512"; + } - parserCPP.push(...[ - ` uint64_t nCols = starkInfo.nConstants;`, - ` uint64_t buffTOffsetsSteps_[nStages + 2];`, - ` uint64_t nColsSteps[nStages + 2];`, - ` uint64_t offsetsSteps[nStages + 2];\n`, - ` nColsSteps[0] = starkInfo.nConstants;`, - ` buffTOffsetsSteps_[0] = 0;`, - ` offsetsSteps[1] = domainExtended ? starkInfo.mapOffsets.section[eSection::cm1_2ns] : starkInfo.mapOffsets.section[eSection::cm1_n];`, - ` nColsSteps[1] = starkInfo.mapSectionsN.section[eSection::cm1_2ns];`, - ` buffTOffsetsSteps_[1] = 2*nColsSteps[0];`, - ` nCols += nColsSteps[1];\n`, - ` offsetsSteps[2] = domainExtended ? starkInfo.mapOffsets.section[eSection::cm2_2ns] : starkInfo.mapOffsets.section[eSection::cm2_n];`, - ` nColsSteps[2] = starkInfo.mapSectionsN.section[eSection::cm2_2ns];`, - ` buffTOffsetsSteps_[2] = buffTOffsetsSteps_[1] + 2*nColsSteps[1];`, - ` nCols += nColsSteps[2];\n`, - ` offsetsSteps[3] = domainExtended ? starkInfo.mapOffsets.section[eSection::cm3_2ns] : starkInfo.mapOffsets.section[eSection::cm3_n];`, - ` nColsSteps[3] = starkInfo.mapSectionsN.section[eSection::cm3_2ns];`, - ` buffTOffsetsSteps_[3] = buffTOffsetsSteps_[2] + 2*nColsSteps[2];`, - ` nCols += nColsSteps[3];\n`, - ]); + let functionType = !operationsUsed ? "virtual void" : "void"; + const parserCPP = []; + + if(parserType === "avx") { + parserCPP.push("uint64_t nrowsPack = 4;"); + } else if (parserType === "avx512") { + parserCPP.push("uint64_t nrowsPack = 8;"); + } parserCPP.push(...[ - " if(parserParams.stage <= nStages) {", - ` offsetsSteps[4] = starkInfo.mapOffsets.section[eSection::tmpExp_n];`, - ` nColsSteps[4] = starkInfo.mapSectionsN.section[eSection::tmpExp_n];`, + "uint64_t nCols;", + "vector nColsStages;", + "vector nColsStagesAcc;", + "vector offsetsStages;\n", + `inline ${functionType} setBufferTInfo(StarkInfo& starkInfo, uint64_t stage) {`, + " bool domainExtended = stage <= 3 ? false : true;", + " nColsStagesAcc.resize(10 + 2);", + " nColsStages.resize(10 + 2);", + " offsetsStages.resize(10 + 2);\n", + " nColsStages[0] = starkInfo.nConstants + 2;", + " offsetsStages[0] = 0;\n", + " for(uint64_t s = 1; s <= 3; ++s) {", + ` nColsStages[s] = starkInfo.mapSectionsN.section[string2section("cm" + to_string(s) + "_n")];`, + " if(domainExtended) {", + ` offsetsStages[s] = starkInfo.mapOffsets.section[string2section("cm" + to_string(s) + "_2ns")];`, + " } else {", + ` offsetsStages[s] = starkInfo.mapOffsets.section[string2section("cm" + to_string(s) + "_n")];`, + " }", + " }", + " if(domainExtended) {", + " nColsStages[4] = starkInfo.mapSectionsN.section[eSection::cm4_2ns];", + " offsetsStages[4] = starkInfo.mapOffsets.section[eSection::cm4_2ns];", " } else {", - ` offsetsSteps[4] = starkInfo.mapOffsets.section[eSection::cm4_2ns];`, - ` nColsSteps[4] = starkInfo.mapSectionsN.section[eSection::cm4_2ns];`, + " nColsStages[4] = starkInfo.mapSectionsN.section[eSection::tmpExp_n];", + " offsetsStages[4] = starkInfo.mapOffsets.section[eSection::tmpExp_n];", " }", - ` buffTOffsetsSteps_[4] = buffTOffsetsSteps_[3] + 2*nColsSteps[3];`, - ` nCols += nColsSteps[4];\n`, + " for(uint64_t o = 0; o < 2; ++o) {", + " for(uint64_t s = 0; s < 5; ++s) {", + " if(s == 0) {", + " if(o == 0) {", + " nColsStagesAcc[0] = 0;", + " } else {", + " nColsStagesAcc[5*o] = nColsStagesAcc[5*o - 1] + nColsStages[4];", + " }", + " } else {", + " nColsStagesAcc[5*o + s] = nColsStagesAcc[5*o + (s - 1)] + nColsStages[(s - 1)];", + " }", + " }", + " }", + " nColsStagesAcc[10] = nColsStagesAcc[9] + nColsStages[9]; // Polinomials f & q", + " if(stage == 4) {", + " offsetsStages[10] = starkInfo.mapOffsets.section[eSection::q_2ns];", + " nColsStages[10] = starkInfo.qDim;", + " } else if(stage == 5) {", + " offsetsStages[10] = starkInfo.mapOffsets.section[eSection::f_2ns];", + " nColsStages[10] = 3;", + " }", + " nColsStagesAcc[11] = nColsStagesAcc[10] + 3; // xDivXSubXi", + " nCols = nColsStagesAcc[11] + 6;", + "}\n", ]); - + parserCPP.push(...[ - "#pragma omp parallel for", - " for(uint64_t i = 0; i < params.challenges.degree(); ++i) {", - " challenges[i][0] = _mm256_set1_epi64x(params.challenges[i][0].fe);", - " challenges[i][1] = _mm256_set1_epi64x(params.challenges[i][1].fe);", - " challenges[i][2] = _mm256_set1_epi64x(params.challenges[i][2].fe);\n", - " Goldilocks::Element challenges_aux[3];", - " challenges_aux[0] = params.challenges[i][0] + params.challenges[i][1];", - " challenges_aux[1] = params.challenges[i][0] + params.challenges[i][2];", - " challenges_aux[2] = params.challenges[i][1] + params.challenges[i][2];", - " challenges_ops[i][0] = _mm256_set1_epi64x(challenges_aux[0].fe);", - " challenges_ops[i][1] = _mm256_set1_epi64x(challenges_aux[1].fe);", - " challenges_ops[i][2] = _mm256_set1_epi64x(challenges_aux[2].fe);", + `inline ${functionType} storePolinomials(StarkInfo &starkInfo, StepsParams ¶ms, ${isAvx ? avxTypeElement : "Goldilocks::Element"} *bufferT_, uint8_t* storePol, uint64_t row, uint64_t nrowsPack, uint64_t domainExtended) {`, + " if(domainExtended) {", + " // Store either polinomial f or polinomial q", + " for(uint64_t k = 0; k < nColsStages[10]; ++k) {", + ` ${isAvx ? avxTypeElement : "Goldilocks::Element"} *buffT = &bufferT_[(nColsStagesAcc[10] + k)${!isAvx ? "* nrowsPack" : ""}];`, + ` Goldilocks::${isAvx ? avxStore : "copy_pack"}(${!isAvx ? "nrowsPack, " : ""}¶ms.pols[offsetsStages[10] + k + row * nColsStages[10]], nColsStages[10], ${!isAvx ? "buffT" : "buffT[0]"});`, + " }", + " } else {", + " uint64_t nStages = 3;", + " uint64_t domainSize = domainExtended ? 1 << starkInfo.starkStruct.nBitsExt : 1 << starkInfo.starkStruct.nBits;", + " for(uint64_t s = 2; s <= nStages + 1; ++s) {", + " bool isTmpPol = !domainExtended && s == 4;", + " for(uint64_t k = 0; k < nColsStages[s]; ++k) {", + " uint64_t dim = storePol[nColsStagesAcc[s] + k];", + " if(storePol[nColsStagesAcc[s] + k]) {", + ` ${isAvx ? avxTypeElement : "Goldilocks::Element"} *buffT = &bufferT_[(nColsStagesAcc[s] + k)${!isAvx ? "* nrowsPack" : ""}];`, + " if(isTmpPol) {", + " for(uint64_t i = 0; i < dim; ++i) {", + ` Goldilocks::${isAvx ? avxStore : "copy_pack"}(${!isAvx ? "nrowsPack, " : ""}¶ms.pols[offsetsStages[s] + k * domainSize + row * dim + i], uint64_t(dim), ${!isAvx ? "&buffT[i*nrowsPack]" : "buffT[i]"});`, + " }", + " } else {", + ` Goldilocks::${isAvx ? avxStore : "copy_pack"}(${!isAvx ? "nrowsPack, " : ""}¶ms.pols[offsetsStages[s] + k + row * nColsStages[s]], nColsStages[s], ${!isAvx ? "buffT" : "buffT[0]"});`, + " }", + " }", + " }", + " }", " }", + "}\n", ]); + if(isAvx) { + parserCPP.push(...[ + `inline ${functionType} loadPolinomials(StarkInfo &starkInfo, StepsParams ¶ms, ${avxTypeElement} *bufferT_, uint64_t row, uint64_t stage, uint64_t nrowsPack, uint64_t domainExtended) {`, + " Goldilocks::Element bufferT[2*nrowsPack];", + " ConstantPolsStarks *constPols = domainExtended ? params.pConstPols2ns : params.pConstPols;", + " Polinomial &x = domainExtended ? params.x_2ns : params.x_n;", + " uint64_t domainSize = domainExtended ? 1 << starkInfo.starkStruct.nBitsExt : 1 << starkInfo.starkStruct.nBits;", + " uint64_t nStages = 3;", + " uint64_t nextStride = domainExtended ? 1 << (starkInfo.starkStruct.nBitsExt - starkInfo.starkStruct.nBits) : 1;", + " std::vector nextStrides = {0, nextStride};", + " for(uint64_t k = 0; k < starkInfo.nConstants; ++k) {", + " for(uint64_t o = 0; o < 2; ++o) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " uint64_t l = (row + j + nextStrides[o]) % domainSize;", + " bufferT[nrowsPack*o + j] = ((Goldilocks::Element *)constPols->address())[l * starkInfo.nConstants + k];", + " }", + ` Goldilocks::${avxLoad}(bufferT_[nColsStagesAcc[5*o] + k], &bufferT[nrowsPack*o]);`, + " }", + " }\n", + " // Load x and Zi", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " bufferT[j] = x[row + j][0];", + " }", + ` Goldilocks::${avxLoad}(bufferT_[starkInfo.nConstants], &bufferT[0]);`, + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " bufferT[j] = params.zi[row + j][0];", + " }\n", + ` Goldilocks::${avxLoad}(bufferT_[starkInfo.nConstants + 1], &bufferT[0]);\n`, + " for(uint64_t s = 1; s <= nStages; ++s) {", + " if(stage < s) break;", + " for(uint64_t k = 0; k < nColsStages[s]; ++k) {", + " for(uint64_t o = 0; o < 2; ++o) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " uint64_t l = (row + j + nextStrides[o]) % domainSize;", + " bufferT[nrowsPack*o + j] = params.pols[offsetsStages[s] + l * nColsStages[s] + k];", + " }", + ` Goldilocks::${avxLoad}(bufferT_[nColsStagesAcc[5*o + s] + k], &bufferT[nrowsPack*o]);`, + " }", + " }", + " }\n", + " if(stage == 5) {", + " for(uint64_t k = 0; k < nColsStages[nStages + 1]; ++k) {", + " for(uint64_t o = 0; o < 2; ++o) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " uint64_t l = (row + j + nextStrides[o]) % domainSize;", + " bufferT[nrowsPack*o + j] = params.pols[offsetsStages[nStages + 1] + l * nColsStages[nStages + 1] + k];", + " }", + ` Goldilocks::${avxLoad}(bufferT_[nColsStagesAcc[5*o + nStages + 1] + k], &bufferT[nrowsPack*o]);`, + " }", + " }\n", + " // Load xDivXSubXi & xDivXSubWXi", + " for(uint64_t d = 0; d < 2; ++d) {", + " for(uint64_t i = 0; i < FIELD_EXTENSION; ++i) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " bufferT[j] = params.xDivXSubXi[d*domainSize + row + j][i];", + " }", + ` Goldilocks::${avxLoad}(bufferT_[nColsStagesAcc[11] + FIELD_EXTENSION*d + i], &bufferT[0]);`, + " }", + " }", + " }", + "}\n", + ]); + } else { + parserCPP.push(...[ + `inline ${functionType} loadPolinomials(StarkInfo &starkInfo, StepsParams ¶ms, Goldilocks::Element *bufferT_, uint64_t row, uint64_t stage, uint64_t nrowsPack, uint64_t domainExtended) {`, + " ConstantPolsStarks *constPols = domainExtended ? params.pConstPols2ns : params.pConstPols;", + " uint64_t domainSize = domainExtended ? 1 << starkInfo.starkStruct.nBitsExt : 1 << starkInfo.starkStruct.nBits;", + " Polinomial &x = domainExtended ? params.x_2ns : params.x_n;", + " uint64_t nStages = 3;", + " uint64_t nextStride = domainExtended ? 1 << (starkInfo.starkStruct.nBitsExt - starkInfo.starkStruct.nBits) : 1;", + " std::vector nextStrides = {0, nextStride};", + " for(uint64_t k = 0; k < starkInfo.nConstants; ++k) {", + " for(uint64_t o = 0; o < 2; ++o) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " uint64_t l = (row + j + nextStrides[o]) % domainSize;", + " bufferT_[(nColsStagesAcc[5*o] + k)*nrowsPack + j] = ((Goldilocks::Element *)constPols->address())[l * starkInfo.nConstants + k];", + " }", + " }", + " }\n", + " // Load x and Zi", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " bufferT_[starkInfo.nConstants*nrowsPack + j] = x[row + j][0];", + " }", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " bufferT_[(starkInfo.nConstants + 1)*nrowsPack + j] = params.zi[row + j][0];", + " }\n", + " for(uint64_t s = 1; s <= nStages; ++s) {", + " for(uint64_t k = 0; k < nColsStages[s]; ++k) {", + " for(uint64_t o = 0; o < 2; ++o) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " uint64_t l = (row + j + nextStrides[o]) % domainSize;", + " bufferT_[(nColsStagesAcc[5*o + s] + k)*nrowsPack + j] = params.pols[offsetsStages[s] + l * nColsStages[s] + k];", + " }", + " }", + " }", + " }\n", + " if(stage == 5) {", + " for(uint64_t k = 0; k < nColsStages[nStages + 1]; ++k) {", + " for(uint64_t o = 0; o < 2; ++o) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " uint64_t l = (row + j + nextStrides[o]) % domainSize;", + " bufferT_[(nColsStagesAcc[5*o + nStages + 1] + k)*nrowsPack + j] = params.pols[offsetsStages[nStages + 1] + l * nColsStages[nStages + 1] + k];", + " }", + " }", + " }\n", + " // Load xDivXSubXi & xDivXSubWXi", + " for(uint64_t d = 0; d < 2; ++d) {", + " for(uint64_t i = 0; i < FIELD_EXTENSION; ++i) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + " bufferT_[(nColsStagesAcc[11] + FIELD_EXTENSION*d + i)*nrowsPack + j] = params.xDivXSubXi[d*domainSize + row + j][i];", + " }", + " }", + " }", + " }", + "}\n" + ]); + } + parserCPP.push(...[ - "#pragma omp parallel for", - " for(uint64_t i = 0; i < parserParams.nNumbers; ++i) {", - " numbers_[i] = _mm256_set1_epi64x(numbers[i]);", - " }", - ]) + `${functionType} calculateExpressions(StarkInfo &starkInfo, StepsParams ¶ms, ParserArgs &parserArgs, ParserParams &parserParams) {`, + ]); + + if(parserType === "avx512" || parserType === "avx") { + parserCPP.push(` assert(nrowsPack == ${parserType === "avx512" ? 8 : 4});`); + } parserCPP.push(...[ - " __m256i publics[starkInfo.nPublics];", - "#pragma omp parallel for", - " for(uint64_t i = 0; i < starkInfo.nPublics; ++i) {", - " publics[i] = _mm256_set1_epi64x(params.publicInputs[i].fe);", - " }", + ` bool domainExtended = parserParams.stage > 3 ? true : false;`, + " uint64_t domainSize = domainExtended ? 1 << starkInfo.starkStruct.nBitsExt : 1 << starkInfo.starkStruct.nBits;", + " uint8_t *ops = &parserArgs.ops[parserParams.opsOffset];", + " uint16_t *args = &parserArgs.args[parserParams.argsOffset];", + " uint64_t *numbers = &parserArgs.numbers[parserParams.numbersOffset];", + " uint8_t *storePol = &parserArgs.storePols[parserParams.storePolsOffset];\n", + " setBufferTInfo(starkInfo, parserParams.stage);", ]); - if(vectorizeEvals) { + + if(isAvx) { + parserCPP.push(...[ + ` ${avxTypeExtElement} challenges[params.challenges.degree()];`, + ` ${avxTypeExtElement} challenges_ops[params.challenges.degree()];`, + " for(uint64_t i = 0; i < params.challenges.degree(); ++i) {", + ` challenges[i][0] = ${avxSet1Epi64}(params.challenges[i][0].fe);`, + ` challenges[i][1] = ${avxSet1Epi64}(params.challenges[i][1].fe);`, + ` challenges[i][2] = ${avxSet1Epi64}(params.challenges[i][2].fe);\n`, + " Goldilocks::Element challenges_aux[3];", + " challenges_aux[0] = params.challenges[i][0] + params.challenges[i][1];", + " challenges_aux[1] = params.challenges[i][0] + params.challenges[i][2];", + " challenges_aux[2] = params.challenges[i][1] + params.challenges[i][2];", + ` challenges_ops[i][0] = ${avxSet1Epi64}(challenges_aux[0].fe);`, + ` challenges_ops[i][1] = ${avxSet1Epi64}(challenges_aux[1].fe);`, + ` challenges_ops[i][2] = ${avxSet1Epi64}(challenges_aux[2].fe);`, + " }\n", + ]); + + parserCPP.push(...[ + ` ${avxTypeElement} numbers_[parserParams.nNumbers];`, + " for(uint64_t i = 0; i < parserParams.nNumbers; ++i) {", + ` numbers_[i] = ${avxSet1Epi64}(numbers[i]);`, + " }\n", + ]) + + parserCPP.push(...[ + ` ${avxTypeElement} publics[starkInfo.nPublics];`, + " for(uint64_t i = 0; i < starkInfo.nPublics; ++i) {", + ` publics[i] = ${avxSet1Epi64}(params.publicInputs[i].fe);`, + " }\n", + ]); + parserCPP.push(...[ - " Goldilocks3::Element_avx evals[params.evals.degree()];", - "#pragma omp parallel for", + ` ${avxTypeExtElement} evals[params.evals.degree()];`, " for(uint64_t i = 0; i < params.evals.degree(); ++i) {", - " evals[i][0] = _mm256_set1_epi64x(params.evals[i][0].fe);", - " evals[i][1] = _mm256_set1_epi64x(params.evals[i][1].fe);", - " evals[i][2] = _mm256_set1_epi64x(params.evals[i][2].fe);", - " }", + ` evals[i][0] = ${avxSet1Epi64}(params.evals[i][0].fe);`, + ` evals[i][1] = ${avxSet1Epi64}(params.evals[i][1].fe);`, + ` evals[i][2] = ${avxSet1Epi64}(params.evals[i][2].fe);`, + " }\n", + ]); + } else { + parserCPP.push(...[ + ` Goldilocks::Element challenges[params.challenges.degree()*FIELD_EXTENSION*nrowsPack];`, + ` Goldilocks::Element challenges_ops[params.challenges.degree()*FIELD_EXTENSION*nrowsPack];`, + " for(uint64_t i = 0; i < params.challenges.degree(); ++i) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + ` challenges[(i*FIELD_EXTENSION)*nrowsPack + j] = params.challenges[i][0];`, + ` challenges[(i*FIELD_EXTENSION + 1)*nrowsPack + j] = params.challenges[i][1];`, + ` challenges[(i*FIELD_EXTENSION + 2)*nrowsPack + j] = params.challenges[i][2];`, + " challenges_ops[(i*FIELD_EXTENSION)*nrowsPack + j] = params.challenges[i][0] + params.challenges[i][1];", + " challenges_ops[(i*FIELD_EXTENSION + 1)*nrowsPack + j] = params.challenges[i][0] + params.challenges[i][2];", + " challenges_ops[(i*FIELD_EXTENSION + 2)*nrowsPack + j] = params.challenges[i][1] + params.challenges[i][2];", + " }", + " }\n", + ]); + + parserCPP.push(...[ + " Goldilocks::Element numbers_[parserParams.nNumbers*nrowsPack];", + " for(uint64_t i = 0; i < parserParams.nNumbers; ++i) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + ` numbers_[i*nrowsPack + j] = Goldilocks::fromU64(numbers[i]);`, + " }", + " }\n", + ]) + + parserCPP.push(...[ + " Goldilocks::Element publics[starkInfo.nPublics*nrowsPack];", + " for(uint64_t i = 0; i < starkInfo.nPublics; ++i) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + ` publics[i*nrowsPack + j] = params.publicInputs[i];`, + " }", + " }\n", + ]) + + parserCPP.push(...[ + ` Goldilocks::Element evals[params.evals.degree()*FIELD_EXTENSION*nrowsPack];`, + " for(uint64_t i = 0; i < params.evals.degree(); ++i) {", + " for(uint64_t j = 0; j < nrowsPack; ++j) {", + ` evals[(i*FIELD_EXTENSION)*nrowsPack + j] = params.evals[i][0];`, + ` evals[(i*FIELD_EXTENSION + 1)*nrowsPack + j] = params.evals[i][1];`, + ` evals[(i*FIELD_EXTENSION + 2)*nrowsPack + j] = params.evals[i][2];`, + " }", + " }\n", ]); } - + + parserCPP.push(...[ `#pragma omp parallel for`, - ` for (uint64_t i = 0; i < domainSize; i+= nrowsBatch) {`, - " bool const needModule = i + nrowsBatch + nextStride >= domainSize;", + ` for (uint64_t i = 0; i < domainSize; i+= nrowsPack) {`, " uint64_t i_args = 0;\n", - " uint64_t offsetsDest[4];", - " __m256i tmp1[parserParams.nTemp1];", - " Goldilocks3::Element_avx tmp3[parserParams.nTemp3];", - " Goldilocks3::Element_avx tmp3_;", - " // Goldilocks3::Element_avx tmp3_0;", - " Goldilocks3::Element_avx tmp3_1;", - " // __m256i tmp1_0;", - " __m256i tmp1_1;", - " __m256i bufferT_[2*nCols];\n", - ]); - - parserCPP.push(...[ - " uint64_t kk = 0;", - " Goldilocks::Element bufferT[2*nrowsBatch];\n", - " for(uint64_t k = 0; k < nColsSteps[0]; ++k) {", - " for(uint64_t o = 0; o < 2; ++o) {", - " for(uint64_t j = 0; j < nrowsBatch; ++j) {", - " uint64_t l = (i + j + nextStrides[o]) % domainSize;", - " bufferT[nrowsBatch*o + j] = ((Goldilocks::Element *)constPols->address())[l * nColsSteps[0] + k];", - " }", - " Goldilocks::load_avx(bufferT_[kk++], &bufferT[nrowsBatch*o]);", - " }", - " }", - " for(uint64_t s = 1; s <= nStages; ++s) {", - " if(parserParams.stage < s) break;", - " for(uint64_t k = 0; k < nColsSteps[s]; ++k) {", - " for(uint64_t o = 0; o < 2; ++o) {", - " for(uint64_t j = 0; j < nrowsBatch; ++j) {", - " uint64_t l = (i + j + nextStrides[o]) % domainSize;", - " bufferT[nrowsBatch*o + j] = params.pols[offsetsSteps[s] + l * nColsSteps[s] + k];", - " }", - " Goldilocks::load_avx(bufferT_[kk++], &bufferT[nrowsBatch*o]);", - " }", - " }", - " }", - " for(uint64_t k = 0; k < nColsSteps[nStages + 1]; ++k) {", - " for(uint64_t o = 0; o < 2; ++o) {", - " for(uint64_t j = 0; j < nrowsBatch; ++j) {", - " uint64_t l = (i + j + nextStrides[o]) % domainSize;", - " bufferT[nrowsBatch*o + j] = params.pols[offsetsSteps[nStages + 1] + l * nColsSteps[nStages + 1] + k];", - " }", - " Goldilocks::load_avx(bufferT_[kk++], &bufferT[nrowsBatch*o]);", - " }", - " }" ]); + + if(isAvx) { + parserCPP.push(...[ + ` ${avxTypeElement} bufferT_[2*nCols];`, + ` ${avxTypeElement} tmp1[parserParams.nTemp1];`, + ` ${avxTypeExtElement} tmp3[parserParams.nTemp3];\n`, + ]); + } else { + parserCPP.push(...[ + ` Goldilocks::Element bufferT_[2*nCols*nrowsPack];`, + ` Goldilocks::Element tmp1[parserParams.nTemp1*nrowsPack];`, + ` Goldilocks::Element tmp3[parserParams.nTemp3*nrowsPack*FIELD_EXTENSION];\n`, + ]); + } + + parserCPP.push(" loadPolinomials(starkInfo, params, bufferT_, i, parserParams.stage, nrowsPack, domainExtended);\n"); parserCPP.push(...[ - "\n", " for (uint64_t kk = 0; kk < parserParams.nOps; ++kk) {", ` switch (ops[kk]) {`, ]); @@ -192,19 +405,19 @@ module.exports.generateParser = function generateParser(operations, operationsUs let opr = operations[op.ops[j]]; operationCase.push(writeOperation(opr)); let numberArgs = numberOfArgs(opr.dest_type) + numberOfArgs(opr.src0_type); - if(opr.src1_type && opr.dest_type !== "q") numberArgs += numberOfArgs(opr.src1_type) + 1; + if(opr.src1_type) numberArgs += numberOfArgs(opr.src1_type) + 1; operationCase.push(` i_args += ${numberArgs};`); } } else { operationCase.push(writeOperation(op)); let numberArgs = numberOfArgs(op.dest_type) + numberOfArgs(op.src0_type); - if(op.src1_type && op.dest_type !== "q") numberArgs += numberOfArgs(op.src1_type) + 1; + if(op.src1_type) numberArgs += numberOfArgs(op.src1_type) + 1; operationCase.push(` i_args += ${numberArgs};`); } operationCase.push(...[ " break;", - " }", + " }", ]) parserCPP.push(operationCase.join("\n")); @@ -219,6 +432,8 @@ module.exports.generateParser = function generateParser(operations, operationsUs " }", ]); + parserCPP.push(" storePolinomials(starkInfo, params, bufferT_, storePol, i, nrowsPack, domainExtended);"); + parserCPP.push(...[ ` if (i_args != parserParams.nArgs) std::cout << " " << i_args << " - " << parserParams.nArgs << std::endl;`, " assert(i_args == parserParams.nArgs);", @@ -233,31 +448,7 @@ module.exports.generateParser = function generateParser(operations, operationsUs return parserCPPCode; function writeOperation(operation) { - if(operation.dest_type === "q") { - const qOperation = [ - " Goldilocks::Element tmp_inv[3];", - " Goldilocks::Element ti0[4];", - " Goldilocks::Element ti1[4];", - " Goldilocks::Element ti2[4];", - ` Goldilocks::store_avx(ti0, tmp3[args[i_args]][0]);`, - ` Goldilocks::store_avx(ti1, tmp3[args[i_args]][1]);`, - ` Goldilocks::store_avx(ti2, tmp3[args[i_args]][2]);`, - " for (uint64_t j = 0; j < AVX_SIZE_; ++j) {", - " tmp_inv[0] = ti0[j];", - " tmp_inv[1] = ti1[j];", - " tmp_inv[2] = ti2[j];", - " Goldilocks3::mul((Goldilocks3::Element &)(params.q_2ns[(i + j) * 3]), params.zi[i + j][0],(Goldilocks3::Element &)tmp_inv);", - " }", - ].join("\n"); - return qOperation; - } else if(operation.dest_type === "f" && !operation.src1_type) { - const fOperation = [ - " Goldilocks3::copy_avx(tmp3_, tmp3[args[i_args]]);", - " Goldilocks3::store_avx(¶ms.f_2ns[i*3], uint64_t(3), tmp3_);", - ].join("\n"); - return fOperation; - } - let name = ["tmp1", "commit1"].includes(operation.dest_type) ? "Goldilocks::" : "Goldilocks3::"; + let name = ["tmp1", "commit1"].includes(operation.dest_type) ? " Goldilocks::" : " Goldilocks3::"; if(operation.op === "mul") { name += "mul"; @@ -267,11 +458,11 @@ module.exports.generateParser = function generateParser(operations, operationsUs name += "copy"; } - if(["tmp3", "commit3"].includes(operation.dest_type)) { + if(["tmp3", "commit3", "q", "f"].includes(operation.dest_type)) { if(operation.src1_type) { let dimType = ""; - let dims1 = ["public", "x", "commit1", "tmp1", "const", "number"]; - let dims3 = ["commit3", "tmp3", "challenge", "eval", "xDivXSubXi"]; + let dims1 = ["public", "x", "commit1", "tmp1", "const", "number", "Zi"]; + let dims3 = ["q", "f", "commit3", "tmp3", "challenge", "eval", "xDivXSubXi"]; if(dims1.includes(operation.src0_type)) dimType += "1"; if (dims3.includes(operation.src0_type)) dimType += "3"; if(dims1.includes(operation.src1_type)) dimType += "1"; @@ -281,7 +472,13 @@ module.exports.generateParser = function generateParser(operations, operationsUs } } - name += "_avx("; + if(parserType === "avx") { + name += "_avx("; + } else if(parserType === "avx512") { + name += "_avx512("; + } else if(parserType === "pack") { + name += "_pack(nrowsPack, "; + } c_args = 0; @@ -294,34 +491,7 @@ module.exports.generateParser = function generateParser(operations, operationsUs let typeDest = writeType(operation.dest_type); - let operationStoreAvx = []; - - if(operation.dest_type === "commit1" || operation.dest_type === "commit3") { - operationStoreAvx.push(...[ - ` if(needModule) {`, - ` uint64_t stepOffset = offsetsSteps[args[i_args + ${c_args}]] + args[i_args + ${c_args + 1}];`, - ` uint64_t nextStrideOffset = i + nextStride * args[i_args + ${c_args + 2}];`, - ` offsetsDest[0] = stepOffset + (nextStrideOffset % domainSize) * nColsSteps[args[i_args + ${c_args}]];`, - ` offsetsDest[1] = stepOffset + ((nextStrideOffset + 1) % domainSize) * nColsSteps[args[i_args + ${c_args}]];`, - ` offsetsDest[2] = stepOffset + ((nextStrideOffset + 2) % domainSize) * nColsSteps[args[i_args + ${c_args}]];`, - ` offsetsDest[3] = stepOffset + ((nextStrideOffset + 3) % domainSize) * nColsSteps[args[i_args + ${c_args}]];`, - ]); - if(operation.dest_type === "commit1") { - operationStoreAvx.push(` Goldilocks::store_avx(¶ms.pols[0], offsetsDest, ${typeDest});`); - } else { - operationStoreAvx.push(` Goldilocks3::store_avx(¶ms.pols[0], offsetsDest, &${typeDest}, 2);`); - } - operationStoreAvx.push(` } else {`); - if(operation.dest_type === "commit1") { - operationStoreAvx.push(` Goldilocks::store_avx(¶ms.pols[offsetsSteps[args[i_args + ${c_args}]] + args[i_args + ${c_args + 1}] + (i + nextStride * args[i_args + ${c_args + 2}]) * nColsSteps[args[i_args + ${c_args}]]], nColsSteps[args[i_args + ${c_args}]], ${typeDest});`); - } else { - operationStoreAvx.push(` Goldilocks3::store_avx(¶ms.pols[offsetsSteps[args[i_args + ${c_args}]] + args[i_args + ${c_args + 1}] + (i + nextStride * args[i_args + ${c_args + 2}]) * nColsSteps[args[i_args + ${c_args}]]], nColsSteps[args[i_args + ${c_args}]], &${typeDest}, 2);`); - } - operationStoreAvx.push(` }`); - } else if(operation.dest_type === "f") { - operationStoreAvx.push(` Goldilocks3::store_avx(¶ms.f_2ns[i*3], uint64_t(3), tmp3_);`,) - } - + let operationStoreAvx; c_args += numberOfArgs(operation.dest_type); @@ -329,78 +499,29 @@ module.exports.generateParser = function generateParser(operations, operationsUs c_args += numberOfArgs(operation.src0_type); let typeSrc1; - - const operationCall = []; - - if ("x" === operation.src0_type){ - operationCall.push(` Goldilocks::load_avx(tmp1_0, ${typeSrc0}, x.offset());`); - typeSrc0 = "tmp1_0"; - } else if(["xDivXSubXi"].includes(operation.src0_type)) { - operationCall.push(` Goldilocks3::load_avx(tmp3_0, ${typeSrc0}, params.${operation.src0_type}.offset());`); - typeSrc0 = "tmp3_0"; - } - if(operation.src1_type) { typeSrc1 = writeType(operation.src1_type); - - if ("x" === operation.src1_type){ - operationCall.push(` Goldilocks::load_avx(tmp1_1, ${typeSrc1}, x.offset());`); - typeSrc1 = "tmp1_1"; - } else if(["xDivXSubXi"].includes(operation.src1_type)) { - operationCall.push(` Goldilocks3::load_avx(tmp3_1, ${typeSrc1}, params.${operation.src1_type}.offset());`); - typeSrc1 = "tmp3_1"; - } - - c_args += numberOfArgs(operation.src1_type); } - - if(operation.dest_type == "commit3" || (operation.src0_type === "commit3") || (operation.src1_type && operation.src1_type === "commit3")) { - if(operation.dest_type === "commit3") { - name += `&${typeDest}, 2, \n `; - } else { - name += `&(${typeDest}[0]), 1, \n `; - } - - if(operation.src0_type === "commit3") { - name += `&${typeSrc0}, 2, \n `; - } else if(["tmp3", "challenge", "eval"].includes(operation.src0_type)) { - name += `&(${typeSrc0}[0]), 1, \n `; + + const operationCall = []; + + name += typeDest + ", "; + name += typeSrc0 + ", "; + if(operation.src1_type) { + if(operation.op === "mul" && operation.src1_type === "challenge") { + name += `${typeSrc1}, ${typeSrc1.replace("challenges", "challenges_ops")}, \n `; } else { - name += typeSrc0 + ", "; - } - if(operation.src1_type) { - if(operation.src1_type === "commit3") { - name += `&${typeSrc1}, 2, \n `; - } else if(["tmp3", "eval"].includes(operation.src1_type) || (!operation.op && operation.src1_type === "challenge")) { - name += `&(${typeSrc1}[0]), 1, \n `; - } else if(operation.op === "mul" && operation.src1_type === "challenge") { - name += `${typeSrc1}, ${typeSrc1.replace("challenges", "challenges_ops")}, \n `; - } else { - name += typeSrc1 + ", "; - } - } - } else { - if(operation.dest_type === "f") { - name += "tmp3_, "; - } else { - name += typeDest + ", "; - } - name += typeSrc0 + ", "; - if(operation.src1_type) { - if(operation.op === "mul" && operation.src1_type === "challenge") { - name += `${typeSrc1}, ${typeSrc1.replace("challenges", "challenges_ops")}, \n `; - } else { - name += typeSrc1 + ", "; - } + name += typeSrc1 + ", "; } } - name = name.substring(0, name.lastIndexOf(", ")) + ");"; - operationCall.push(` ${name}`); - operationCall.push(...operationStoreAvx); + operationCall.push(` ${name}`); + if(operationStoreAvx) { + operationCall.push(operationStoreAvx); + } return operationCall.join("\n").replace(/i_args \+ 0/g, "i_args"); } @@ -408,27 +529,26 @@ module.exports.generateParser = function generateParser(operations, operationsUs function writeType(type) { switch (type) { case "public": - return `publics[args[i_args + ${c_args}]]`; + return parserType === "pack" ? `&publics[args[i_args + ${c_args}] * nrowsPack]` : `publics[args[i_args + ${c_args}]]`; case "tmp1": - return `tmp1[args[i_args + ${c_args}]]`; + return parserType === "pack" ? `&tmp1[args[i_args + ${c_args}] * nrowsPack]` : `tmp1[args[i_args + ${c_args}]]`; case "tmp3": - return `tmp3[args[i_args + ${c_args}]]`; + return parserType === "pack" ? `&tmp3[args[i_args + ${c_args}] * nrowsPack * FIELD_EXTENSION]` : `tmp3[args[i_args + ${c_args}]]`; case "commit1": case "commit3": case "const": - return `bufferT_[buffTOffsetsSteps_[args[i_args + ${c_args}]] + 2 * args[i_args + ${c_args + 1}] + args[i_args + ${c_args + 2}]]`; + case "xDivXSubXi": + case "x": + case "Zi": + return parserType === "pack" + ? `&bufferT_[(nColsStagesAcc[args[i_args + ${c_args}]] + args[i_args + ${c_args + 1}]) * nrowsPack]` + : `${type === "commit3" ? `(${avxTypeExtElement} &)` : ""}bufferT_[nColsStagesAcc[args[i_args + ${c_args}]] + args[i_args + ${c_args + 1}]]` case "challenge": - return `challenges[args[i_args + ${c_args}]]`; + return parserType === "pack" ? `&challenges[args[i_args + ${c_args}]*FIELD_EXTENSION*nrowsPack]` : `challenges[args[i_args + ${c_args}]]`; case "eval": - return `evals[args[i_args + ${c_args}]]`; + return parserType === "pack" ? `&evals[args[i_args + ${c_args}]*FIELD_EXTENSION*nrowsPack]` : `evals[args[i_args + ${c_args}]]`; case "number": - return `numbers_[args[i_args + ${c_args}]]`; - case "x": - return `x[i]`; - case "xDivXSubXi": - return `params.xDivXSubXi[i + args[i_args + ${c_args}]*domainSize]`; - case "f": - return "¶ms.f_2ns[i*3]"; + return parserType === "pack" ? `&numbers_[args[i_args + ${c_args}]*nrowsPack]` : `numbers_[args[i_args + ${c_args}]]`; default: throw new Error("Invalid type: " + type); } @@ -436,23 +556,22 @@ module.exports.generateParser = function generateParser(operations, operationsUs function numberOfArgs(type) { switch (type) { - case "x": - case "Zi": - case "q": - case "f": - return 0; case "public": case "tmp1": case "tmp3": case "challenge": case "eval": case "number": - case "xDivXSubXi": return 1; + case "x": + case "Zi": + case "f": + case "q": + case "xDivXSubXi": case "const": case "commit1": case "commit3": - return 3; + return 2; default: throw new Error("Invalid type: " + type); } @@ -465,7 +584,7 @@ module.exports.getAllOperations = function getAllOperations() { const possibleDestinationsDim1 = [ "commit1", "tmp1" ]; const possibleDestinationsDim3 = [ "commit3", "tmp3" ]; - const possibleSrcDim1 = [ "commit1", "tmp1", "public", "x", "number" ]; + const possibleSrcDim1 = [ "commit1", "tmp1", "public", "number" ]; const possibleSrcDim3 = [ "commit3", "tmp3", "challenge" ]; // Dim1 destinations @@ -474,10 +593,8 @@ module.exports.getAllOperations = function getAllOperations() { for(let k = 0; k < possibleSrcDim1.length; ++k) { let src0_type = possibleSrcDim1[k]; possibleOps.push({dest_type, src0_type}); // Copy operation - if(src0_type === "x") continue; for (let l = k; l < possibleSrcDim1.length; ++l) { let src1_type = possibleSrcDim1[l]; - if(src1_type === "x") continue; possibleOps.push({dest_type, src0_type, src1_type}) } } @@ -522,19 +639,13 @@ module.exports.getAllOperations = function getAllOperations() { possibleOps.push({ dest_type: "tmp3", src0_type: "eval", src1_type: "commit1"}); possibleOps.push({ dest_type: "tmp3", src0_type: "commit3", src1_type: "eval"}); - possibleOps.push({ dest_type: "tmp3", src0_type: "tmp3", src1_type: "xDivXSubXi"}); - - possibleOps.push({ dest_type: "q", src0_type: "tmp3", src1_type: "Zi"}); - possibleOps.push({ dest_type: "f", src0_type: "tmp3", src1_type: "tmp3"}); - possibleOps.push({ dest_type: "f", src0_type: "tmp3"}); - return possibleOps; } module.exports.getOperation = function getOperation(r) { const _op = {}; _op.op = r.op; - if(["cm", "tmpExp"].includes(r.dest.type)) { + if(["cm", "tmpExp", "q", "f", "x", "Zi"].includes(r.dest.type)) { _op.dest_type = `commit${r.dest.dim}`; } else if(r.dest.type === "tmp") { _op.dest_type = `tmp${r.dest.dim}`; @@ -542,8 +653,13 @@ module.exports.getOperation = function getOperation(r) { _op.dest_type = r.dest.type; } + for(let i = 0; i < r.src.length; ++i) { + if(["xDivXSubXi", "xDivXSubWXi"].includes(r.src[i].type)) r.src[i].dim = 3; + } + + let src = [...r.src]; if(r.op !== "copy") { - r.src.sort((a, b) => { + src.sort((a, b) => { let opA = ["cm", "tmpExp"].includes(a.type) ? operationsMap[`commit${a.dim}`] : a.type === "tmp" ? operationsMap[`tmp${a.dim}`] : operationsMap[a.type]; let opB = ["cm", "tmpExp"].includes(b.type) ? operationsMap[`commit${b.dim}`] : b.type === "tmp" ? operationsMap[`tmp${b.dim}`] : operationsMap[b.type]; let swap = a.dim !== b.dim ? b.dim - a.dim : opA - opB; @@ -552,19 +668,21 @@ module.exports.getOperation = function getOperation(r) { }); } - for(let i = 0; i < r.src.length; i++) { - if(["cm", "tmpExp"].includes(r.src[i].type)) { - _op[`src${i}_type`] = `commit${r.src[i].dim}`; - } else if(r.src[i].type === "const") { + for(let i = 0; i < src.length; i++) { + if(["cm", "tmpExp"].includes(src[i].type)) { + _op[`src${i}_type`] = `commit${src[i].dim}`; + } else if(["const", "x", "Zi"].includes(src[i].type)) { _op[[`src${i}_type`]] = "commit1"; - } else if(r.src[i].type === "tmp") { - _op[`src${i}_type`] = `tmp${r.src[i].dim}`; - } else if(["xDivXSubXi", "xDivXSubWXi"].includes(r.src[i].type)) { - _op[`src${i}_type`] = "xDivXSubXi"; + } else if(src[i].type === "tmp") { + _op[`src${i}_type`] = `tmp${src[i].dim}`; + } else if(["xDivXSubXi", "xDivXSubWXi"].includes(src[i].type)) { + _op[`src${i}_type`] = "commit3"; } else { - _op[`src${i}_type`] = r.src[i].type; + _op[`src${i}_type`] = src[i].type; } } + _op.src = src; + return _op; } diff --git a/src/stark/chelpers/getParserArgs.js b/src/stark/chelpers/getParserArgs.js index bf29ed10..d1e97ad9 100644 --- a/src/stark/chelpers/getParserArgs.js +++ b/src/stark/chelpers/getParserArgs.js @@ -14,13 +14,24 @@ module.exports.getParserArgs = function getParserArgs(starkInfo, operations, cod var ops = []; var args = []; var numbers = []; + + let nConstants = (starkInfo.nConstants + 2); + let nCols = nConstants + starkInfo.mapSectionsN["cm1_n"] + starkInfo.mapSectionsN["cm2_n"] + starkInfo.mapSectionsN["cm3_n"]; + if(stage <= 3) { + nCols += starkInfo.mapSectionsN["tmpExp_n"]; + } else { + nCols += starkInfo.mapSectionsN["cm4_n"]; + } - var counters_ops = new Array(operations.length).fill(0); + let nColsStagesAcc = new Array(10).fill(0); + nColsStagesAcc[1] = nColsStagesAcc[0] + nConstants; + nColsStagesAcc[2] = nColsStagesAcc[1] + starkInfo.mapSectionsN["cm1_n"]; + nColsStagesAcc[3] = nColsStagesAcc[2] + starkInfo.mapSectionsN["cm2_n"]; + nColsStagesAcc[4] = nColsStagesAcc[3] + starkInfo.mapSectionsN["cm3_n"]; - const nBits = starkInfo.starkStruct.nBits; - const nBitsExt = starkInfo.starkStruct.nBitsExt; + let storePols = new Array(nCols).fill(0); - const next = (dom == "n" ? 1 : 1 << (nBitsExt - nBits)); + var counters_ops = new Array(operations.length).fill(0); // Evaluate max and min temporal variable for tmp_ and tmp3_ let maxid = 100000; @@ -38,8 +49,8 @@ module.exports.getParserArgs = function getParserArgs(starkInfo, operations, cod } pushResArg(r, r.dest.type); - for(let i = 0; i < r.src.length; i++) { - pushSrcArg(r.src[i], r.src[i].type); + for(let i = 0; i < operation.src.length; i++) { + pushSrcArg(operation.src[i], operation.src[i].type); } @@ -66,6 +77,7 @@ module.exports.getParserArgs = function getParserArgs(starkInfo, operations, cod nTemp3: count3d, ops, numbers, + storePols, args, } @@ -95,14 +107,17 @@ module.exports.getParserArgs = function getParserArgs(starkInfo, operations, cod } break; } - case "q": { + case "q": + case "f": { + args.push(10); + args.push(0); break; } case "cm": { if (dom == "n") { - evalMap_(starkInfo.cm_n[r.dest.id], r.dest.prime) + evalMap_(starkInfo.cm_n[r.dest.id], r.dest.prime, true) } else if (dom == "2ns") { - evalMap_(starkInfo.cm_2ns[r.dest.id], r.dest.prime) + evalMap_(starkInfo.cm_2ns[r.dest.id], r.dest.prime, true) } else { throw new Error("Invalid dom"); } @@ -110,7 +125,7 @@ module.exports.getParserArgs = function getParserArgs(starkInfo, operations, cod } case "tmpExp": { if (dom == "n") { - evalMap_(starkInfo.tmpExp_n[r.dest.id], r.dest.prime) + evalMap_(starkInfo.tmpExp_n[r.dest.id], r.dest.prime, true) } else if (dom == "2ns") { throw new Error("Invalid dom"); } else { @@ -118,9 +133,6 @@ module.exports.getParserArgs = function getParserArgs(starkInfo, operations, cod } break; } - case "f": { - break; - } default: throw new Error("Invalid reference type set: " + r.dest.type); } } @@ -140,9 +152,8 @@ module.exports.getParserArgs = function getParserArgs(starkInfo, operations, cod case "const": { let offset_prime = r.prime ? 1 : 0; - args.push(0); + args.push(5*offset_prime); args.push(r.id); - args.push(offset_prime); break; } @@ -166,27 +177,19 @@ module.exports.getParserArgs = function getParserArgs(starkInfo, operations, cod } break; } - case "q": { - if (dom == "n") { - throw new Error("Accessing q in domain n"); - } else if (dom == "2ns") { - evalMap_(starkInfo.qs[r.id], r.prime) - } else { - throw new Error("Invalid dom"); - } - break; - } case "number": { let numString = `${BigInt(r.value).toString()}`; if(!numbers.includes(numString)) numbers.push(numString); args.push(numbers.indexOf(numString)); break; } - case "xDivXSubXi": + case "xDivXSubXi": + args.push(11); args.push(0); break; case "xDivXSubWXi": - args.push(1); + args.push(11); + args.push(3); break; case "public": case "challenge": @@ -195,10 +198,18 @@ module.exports.getParserArgs = function getParserArgs(starkInfo, operations, cod args.push(r.id); break; } + case "x": + args.push(0); + args.push(starkInfo.nConstants); + break; + case "Zi": + args.push(0); + args.push(starkInfo.nConstants + 1); + break; } } - function evalMap_(polId, prime) { + function evalMap_(polId, prime, isDest = false) { let p = starkInfo.varPolMap[polId]; let offset_prime = prime ? 1 : 0; @@ -213,8 +224,18 @@ module.exports.getParserArgs = function getParserArgs(starkInfo, operations, cod } else if(["tmpExp_n", "cm4_2ns"].includes(p.section)) { step = 4; } - args.push(Number(step)); + + if(isDest && stage < 4) { + if(p.section === "tmpExp_n") { + if(!prime) storePols[nColsStagesAcc[step] + p.sectionPos] = p.dim; + } else { + for(let i = 0; i < p.dim; ++i) { + storePols[nColsStagesAcc[step] + p.sectionPos + i] = 1; + } + } + } + + args.push(Number(offset_prime * 5 + step)); args.push(Number(p.sectionPos)); - args.push(Number(offset_prime)); } } diff --git a/src/stark/chelpers/stark_chelpers.js b/src/stark/chelpers/stark_chelpers.js index 40d663a2..01e691d0 100644 --- a/src/stark/chelpers/stark_chelpers.js +++ b/src/stark/chelpers/stark_chelpers.js @@ -6,7 +6,7 @@ const path = require("path"); const fs = require("fs"); const { mkdir } = require("fs-extra"); -module.exports.buildCHelpers = async function buildCHelpers(starkInfo, cHelpersFile, binFile, className = "") { +module.exports.buildCHelpers = async function buildCHelpers(starkInfo, cHelpersFile, className = "", binFile, genericBinFile) { if(className === "") className = "Stark"; className = className[0].toUpperCase() + className.slice(1) + "Steps"; @@ -14,6 +14,8 @@ module.exports.buildCHelpers = async function buildCHelpers(starkInfo, cHelpersF let result = {}; const cHelpersInfo = []; + + const cHelpersInfoGeneric = []; const nStages = 3; @@ -21,13 +23,11 @@ module.exports.buildCHelpers = async function buildCHelpers(starkInfo, cHelpersF `#include "chelpers_steps.hpp"\n\n`, `class ${className} : public CHelpersSteps {`, "public:", - " void calculateExpressions(StarkInfo &starkInfo, StepsParams ¶ms, ParserArgs &parserArgs, ParserParams &parserParams) {", - ` uint32_t nrowsBatch = 4;`, - ` bool domainExtended = parserParams.stage > 3 ? true : false;`, ]; - + let operations = getAllOperations(); - let operationsUsed = {}; + + let operationsWithPatterns = getAllOperations(); let totalSubsetOperationsUsed = []; @@ -39,10 +39,7 @@ module.exports.buildCHelpers = async function buildCHelpers(starkInfo, cHelpersF let code = starkInfo[`step${nStages}prev`].code; getParserArgsStage(nStages, `step${nStages}`, code, "n"); - - code = starkInfo[`step${nStages}`].code; - getParserArgsStage(nStages, `step${nStages}_after`, code, "n", false); - + code = starkInfo[`step${nStages + 1}2ns`].code; getParserArgsStage(nStages + 1, `step${nStages + 1}`, code, "2ns"); @@ -54,7 +51,7 @@ module.exports.buildCHelpers = async function buildCHelpers(starkInfo, cHelpersF console.log("Total subset of operations used: " + totalSubsetOperationsUsed.join(", ")); console.log("--------------------------------"); - const genericParser = generateParser(operations, totalSubsetOperationsUsed, true); + const genericParser = generateParser(operationsWithPatterns, totalSubsetOperationsUsed); cHelpersStepsHpp.push(genericParser); cHelpersStepsHpp.push("};"); @@ -62,7 +59,7 @@ module.exports.buildCHelpers = async function buildCHelpers(starkInfo, cHelpersF result[`${className}_hpp`] = cHelpersStepsHpp.join("\n"); - const operationsPatterns = operations.filter(op => op.isGroupOps); + const operationsPatterns = operationsWithPatterns.filter(op => op.isGroupOps); console.log("Number of patterns used: " + operationsPatterns.length); for(let i = 0; i < operationsPatterns.length; ++i) { console.log("case " + operationsPatterns[i].opIndex + " -> " + operationsPatterns[i].ops.join(", ")); @@ -97,26 +94,31 @@ module.exports.buildCHelpers = async function buildCHelpers(starkInfo, cHelpersF } await writeCHelpersFile(binFile, cHelpersInfo); + if(genericBinFile) { + await writeCHelpersFile(genericBinFile, cHelpersInfoGeneric); + } return; function getParserArgsStage(stage, stageName, stageCode, dom, executeBefore = true) { console.log(`Getting parser args for ${stageName}`); - const {stageInfo, operationsUsed: opsUsed} = getParserArgs(starkInfo, operations, stageCode, dom, stage, executeBefore); + const {stageInfo: stageInfo2} = getParserArgs(starkInfo, operations, stageCode, dom, stage, executeBefore); + cHelpersInfoGeneric.push(stageInfo2); + const {stageInfo, operationsUsed: opsUsed} = getParserArgs(starkInfo, operationsWithPatterns, stageCode, dom, stage, executeBefore); + console.log("Number of operations before join: " + stageInfo.ops.length); - const patternOps = findPatterns(stageInfo.ops, operations); + const patternOps = findPatterns(stageInfo.ops, operationsWithPatterns); opsUsed.push(...patternOps); - console.log("Number of operations after join: " + stageInfo.ops.length); + console.log("Number of operations after join: " + stageInfo.ops.length); cHelpersInfo.push(stageInfo); + for(let j = 0; j < opsUsed.length; ++j) { if(!totalSubsetOperationsUsed.includes(opsUsed[j])) totalSubsetOperationsUsed.push(opsUsed[j]); } - - operationsUsed[stageName] = opsUsed; } } diff --git a/src/stark/stark_buildConstTree.js b/src/stark/stark_buildConstTree.js index 16b2155f..27ef5137 100644 --- a/src/stark/stark_buildConstTree.js +++ b/src/stark/stark_buildConstTree.js @@ -3,7 +3,8 @@ const buildMerkleHashGL = require("../helpers/hash/merklehash/merklehash_p.js"); const buildMerkleHashBN128 = require("../helpers/hash/merklehash/merklehash_bn128_p.js"); const {interpolate} = require("../helpers/fft/fft_p"); -module.exports.buildConstTree = async function buildConstTree(starkStruct, pil, constPols, arity = 16) { +module.exports.buildConstTree = async function buildConstTree(starkInfo, pil, constPols) { + const starkStruct = starkInfo.starkStruct; const nBits = starkStruct.nBits; const nBitsExt = starkStruct.nBitsExt; const extN = 1 << nBitsExt; @@ -18,8 +19,8 @@ module.exports.buildConstTree = async function buildConstTree(starkStruct, pil, if (starkStruct.verificationHashType == "GL") { MH = await buildMerkleHashGL(starkStruct.splitLinearHash); } else if (starkStruct.verificationHashType == "BN128") { - console.log(`Arity: ${arity}`); - MH = await buildMerkleHashBN128(arity); + console.log(`Merkle tree Arity: ${starkInfo.merkleTreeArity}`); + MH = await buildMerkleHashBN128(starkInfo.merkleTreeArity); } else { throw new Error("Invalid Hash Type: "+ starkStruct.verificationHashType); } diff --git a/src/stark/stark_gen.js b/src/stark/stark_gen.js index 59e608b4..f8e9ec45 100644 --- a/src/stark/stark_gen.js +++ b/src/stark/stark_gen.js @@ -22,7 +22,7 @@ const maxNperThread = 1<<18; const minNperThread = 1<<12; -module.exports = async function starkGen(cmPols, constPols, constTree, starkInfo, options) { +module.exports = async function starkGen(cmPols, constPols, constTree, starkInfo) { const starkStruct = starkInfo.starkStruct; const N = 1 << starkStruct.nBits; const extendBits = starkStruct.nBitsExt - starkStruct.nBits; @@ -40,9 +40,8 @@ module.exports = async function starkGen(cmPols, constPols, constTree, starkInfo transcript = new Transcript(poseidon); } else if (starkStruct.verificationHashType == "BN128") { const poseidonBN128 = await buildPoseidonBN128(); - let arity = options.arity || 16; - console.log(`Arity: ${arity}`); - MH = await buildMerkleHashBN128(arity); + console.log(`Merkle Tree Arity: ${starkInfo.merkleTreeArity}`); + MH = await buildMerkleHashBN128(starkInfo.merkleTreeArity); transcript = new TranscriptBN128(poseidonBN128, 16); } else { throw new Error("Invalid Hash Type: "+ starkStruct.verificationHashType); @@ -117,7 +116,6 @@ module.exports = async function starkGen(cmPols, constPols, constTree, starkInfo // EDU: Do not implement this in the firs version. // we will not use it. ctx.publics[i] = calculateExpAtPoint(ctx, starkInfo.publicsCode[i], starkInfo.publics[i].idx); -// ctx.publics[i] = ctx.exps[starkInfo.publics[i].polId][starkInfo.publics[i].idx]; } else { throw new Error(`Invalid public type: ${polType.type}`); } @@ -197,12 +195,6 @@ module.exports = async function starkGen(cmPols, constPols, constTree, starkInfo setPol(ctx, starkInfo, starkInfo.cm_n[nCm++], z); } - if (parallelExec) { - await calculateExpsParallel(pool, ctx, "step3", starkInfo); - } else { - calculateExps(ctx, starkInfo.step3, "n"); - } - console.log("Merkelizing 3...."); if (global.gc) {global.gc();} const tree3 = await extendAndMerkelize(MH, ctx.cm3_n, ctx.cm3_2ns, starkInfo.mapSectionsN.cm3_n, ctx.nBits, ctx.nBitsExt ); diff --git a/src/stark/stark_info.js b/src/stark/stark_info.js index c45e828a..e9481955 100644 --- a/src/stark/stark_info.js +++ b/src/stark/stark_info.js @@ -1,78 +1,28 @@ +const { generatePilCode } = require("../pil_info/generatePilCode"); +const { addIntermediatePolynomials, calculateIntermediatePolynomials } = require("../pil_info/imPolsCalculation/imPolynomials"); +const { preparePil } = require("../pil_info/preparePil"); -const generatePublicCalculators = require("../pil_info/publics.js"); -const generateStep2 = require("../pil_info/step2"); -const generateStep3 = require("../pil_info/step3"); -const generateConstraintPolynomial = require("../pil_info/cp_prover"); -const generateFRIPolynomial = require("../pil_info/fri_prover"); - -const generateConstraintPolynomialVerifier = require("../pil_info/cp_ver"); -const generateVerifierQuery = require("../pil_info/fri_verifier"); const map = require("../pil_info/map"); +const F3g = require("../helpers/f3g"); -module.exports = function starkInfoGen(_pil, starkStruct) { - const pil = JSON.parse(JSON.stringify(_pil)); // Make a copy as we are going to destroy pil - const pilDeg = Object.values(pil.references)[0].polDeg; - const starkDeg = 2 ** starkStruct.nBits; - - if ( starkDeg != pilDeg) { - throw new Error(`Starkpil and pil have degree mismatch (starkpil:${starkDeg} pil:${pilDeg})`); - } - - if ( starkStruct.nBitsExt != starkStruct.steps[0].nBits) { - throw new Error(`Starkpil.nBitsExt and first step of Starkpil have a mismatch (nBitsExt:${starkStruct.nBitsExt} pil:${starkStruct.steps[0].nBits})`); - } - - const res = { - varPolMap: [], - puCtx: [], - peCtx: [], - ciCtx: [] - }; - - res.starkStruct = starkStruct; - res.nConstants = pil.nConstants; - res.nPublics = pil.publics.length; - - generatePublicCalculators(res, pil); - res.nCm1 = pil.nCommitments; - - const ctx = { - pil: pil, - calculated: { - exps: {}, - expsPrime: {} - }, - tmpUsed: 0, - code: [] - }; +module.exports = function starkInfoGen(pil, starkStruct, options) { + const F = new F3g(); - const ctx2ns = { - pil: pil, - calculated: { - exps: {}, - expsPrime: {} - }, - tmpUsed: 0, - code: [] - }; + const infoPil = preparePil(F, pil, starkStruct, options); - const addMul = starkStruct.verificationHashType == "GL" ? true : false; + const expressions = infoPil.expressions; - generateStep2(res, pil, ctx); // H1, H2 + const res = infoPil.res; + + let newExpressions; + let maxDeg = (1 << (res.starkStruct.nBitsExt- res.starkStruct.nBits)) + 1; + const imInfo = calculateIntermediatePolynomials(expressions, res.cExpId, maxDeg, res.qDim); + addIntermediatePolynomials(res, expressions, imInfo.imExps, imInfo.qDeg); + newExpressions = imInfo.newExpressions; + + generatePilCode(res, pil, newExpressions); - generateStep3(res, pil, ctx); // Z Polynomials and LC of permutation chcks. - - generateConstraintPolynomial(res, pil, ctx, ctx2ns); // Step4 - - generateConstraintPolynomialVerifier(res, pil, addMul); - - generateFRIPolynomial(res, pil, ctx2ns); - - generateVerifierQuery(res, pil, addMul); - - map(res, pil); - - res.publics = pil.publics; + map(res, newExpressions); console.log("--------------------- POLINOMIALS INFO ---------------------") console.log(`Columns stage 1: ${res.nCm1} -> Columns in the basefield: ${res.mapSectionsN.cm1_2ns}`); @@ -83,7 +33,7 @@ module.exports = function starkInfoGen(_pil, starkStruct) { console.log(`Total Constraints: ${res.nConstraints}`) console.log(`Number of evaluations: ${res.evMap.length}`) console.log("------------------------------------------------------------") - + return res; } diff --git a/src/stark/stark_setup.js b/src/stark/stark_setup.js index e58af48c..1e87924a 100644 --- a/src/stark/stark_setup.js +++ b/src/stark/stark_setup.js @@ -1,11 +1,12 @@ const {BigBuffer} = require("pilcom"); const buildMerklehashGL = require("../helpers/hash/merklehash/merklehash_p.js"); +const buildMerkleHashBN128 = require("../helpers/hash/merklehash/merklehash_bn128_p.js"); const starkInfoGen = require("./stark_info.js") const { interpolate } = require("../helpers/fft/fft_p"); -module.exports = async function starkSetup(constPols, pil, starkStruct, options = {}) { +module.exports = async function starkSetup(constPols, pil, starkStruct) { const nBits = starkStruct.nBits; const nBitsExt = starkStruct.nBitsExt; @@ -15,12 +16,11 @@ module.exports = async function starkSetup(constPols, pil, starkStruct, options const constBuff = constPols.writeToBuff(); await interpolate(constBuff, pil.nConstants, nBits, constPolsArrayE, nBitsExt ); - let arity = options.arity || 16; let MH; if (starkStruct.verificationHashType == "GL") { MH = await buildMerklehashGL(); } else if (starkStruct.verificationHashType == "BN128") { - MH = await buildMerkleHashBN128(arity); + MH = await buildMerkleHashBN128(starkStruct.merkleTreeArity); } else { throw new Error("Invalid Hash Type: "+ starkStruct.verificationHashType); } diff --git a/src/stark/stark_verify.js b/src/stark/stark_verify.js index c861080f..a484e564 100644 --- a/src/stark/stark_verify.js +++ b/src/stark/stark_verify.js @@ -7,7 +7,7 @@ const { assert } = require("chai"); const buildPoseidonGL = require("../helpers/hash/poseidon/poseidon"); const buildPoseidonBN128 = require("circomlibjs").buildPoseidon; -module.exports = async function starkVerify(proof, publics, constRoot, starkInfo, options) { +module.exports = async function starkVerify(proof, publics, constRoot, starkInfo) { const starkStruct = starkInfo.starkStruct; @@ -21,8 +21,7 @@ module.exports = async function starkVerify(proof, publics, constRoot, starkInfo transcript = new Transcript(poseidonGL); } else if (starkStruct.verificationHashType == "BN128") { const poseidonBN128 = await buildPoseidonBN128(); - let arity = options.arity || 16; - MH = await buildMerkleHashBN128(arity); + MH = await buildMerkleHashBN128(starkInfo.merkleTreeArity); transcript = new TranscriptBN128(poseidonBN128, 16); } else { throw new Error("Invalid Hash Type: "+ starkStruct.verificationHashType); diff --git a/test/stark/all_gl_verifier.circuit.test.js b/test/stark/all_gl_verifier.circuit.test.js index 49bb230f..a7b294ec 100644 --- a/test/stark/all_gl_verifier.circuit.test.js +++ b/test/stark/all_gl_verifier.circuit.test.js @@ -24,11 +24,10 @@ describe("Stark Verification Circuit Test", function () { const circomFile = path.join(__dirname, "../../", "tmp", "all.verifier.circom"); const verKeyFile = path.join(__dirname, "../../","tmp", "all.verkey.json"); - const starkStructFile = path.join(__dirname, "../state_machines/sm_all", "all.starkstruct.json"); + const starkInfoFile = path.join(__dirname, "../../", "tmp", "all.starkinfo.json"); const pilFile = path.join(__dirname, "../state_machines/sm_all", "all_main.pil"); const proofFile = path.join(__dirname, "../../", "tmp", "all.proof.json"); const publicsFile = path.join(__dirname, "../../", "tmp", "all.public.json") - const zkInputFile = path.join(__dirname, "../../", "tmp", "all.zkinput.json") const F = new F3g("0xFFFFFFFF00000001"); @@ -38,10 +37,10 @@ describe("Stark Verification Circuit Test", function () { for (let i=0; i<4; i++) { constRoot[i] = BigInt(verKey.constRoot[i]); } - const starkStruct = JSON.parse(await fs.promises.readFile(starkStructFile, "utf8")); + const starkInfo = JSON.parse(await fs.promises.readFile(starkInfoFile, "utf8")); + const publics = JSONbig.parse(await fs.promises.readFile(publicsFile, "utf8")); - const starkInfo = starkInfoGen(pil, starkStruct); const circuitSrc = await pil2circom(constRoot, starkInfo) await fs.promises.writeFile(circomFile, circuitSrc, "utf8"); diff --git a/test/state_machines/sm_all/all.c18.pil b/test/state_machines/sm_all/all.c18.pil new file mode 100644 index 00000000..f535a205 --- /dev/null +++ b/test/state_machines/sm_all/all.c18.pil @@ -0,0 +1,817 @@ +constant %N = 2**13; + +// THIS FILE IS A TEST EXAMPLE! IT MAY NOT BE THE LAST VERSION! + +// Global state machine +// It is used to store various polynomials representing small lookup tables +namespace Global(%N); + pol constant L1; + +namespace Compressor(%N); + pol constant S[18]; + pol constant C[18]; + pol constant POSEIDONM; + pol constant POSEIDONCUSTFIRST; + pol constant POSEIDONP; + pol constant POSEIDONFIRST; + pol constant PARTIALROUND; + pol constant POSEIDONAFTERPART; + pol constant GATE; + pol constant GATE2; + pol constant CMUL; + pol constant EVPOL4; + pol constant FFT4; + pol constant TREESELECTOR4; + pol commit a[18]; + + public pub0 = a[0](0); + public pub1 = a[1](0); + public pub2 = a[2](0); + Global.L1 * (a[0] - :pub0) = 0; + Global.L1 * (a[1] - :pub1) = 0; + Global.L1 * (a[2] - :pub2) = 0; + + // Normal plonk gates + + // C[0] -> Qm1 + // C[1] -> Ql1 + // C[2] -> Qr1 + // C[3] -> Qo1 + // C[4] -> Qc1 + + // C[6] -> Qm2 + // C[7] -> Ql2 + // C[8] -> Qr2 + // C[9] -> Qo2 + // C[10]-> Qc2 + + // C[12] -> Qm3 + // C[13] -> Ql3 + // C[14] -> Qr3 + // C[15] -> Qo3 + // C[16] -> Qc3 + + + pol a01 = a[0]*a[1]; + pol g012 = C[0]*a01 + C[1]*a[0] + C[2]*a[1] + C[3]*a[2] + C[4]; + g012*GATE = 0; + + pol a34 = a[3]*a[4]; + pol g345 = C[0]*a34 + C[1]*a[3] + C[2]*a[4] + C[3]*a[5] + C[4]; + g345*GATE = 0; + + pol a67 = a[6]*a[7]; + pol g678 = C[6]*a67 + C[7]*a[6] + C[8]*a[7] + C[9]*a[8] + C[10]; + g678*GATE = 0; + + pol a910 = a[9]*a[10]; + pol g91011 = C[6]*a910 + C[7]*a[9] + C[8]*a[10] + C[9]*a[11] + C[10]; + g91011*GATE = 0; + + pol a1213 = a[12]*a[13]; + pol g121314 = C[12]*a1213 + C[13]*a[12] + C[14]*a[13] + C[15]*a[14] + C[16]; + g121314*GATE2 = 0; + + pol a1516 = a[15]*a[16]; + pol g151617 = C[12]*a1516 + C[13]*a[15] + C[14]*a[16] + C[15]*a[17] + C[16]; + g151617*GATE2 = 0; + + + // POSEIDON GATE - Check that a GL Poseidon round implemented with Neptune optimization is valid + + // Each Poseidon hash is verified in 6 rows. Inputs -> Round 2 -> Round 4 -> Round 26 -> Round 28 -> Output. + // At each row we verify two full rounds, and all the partial rounds are verified in a single step + + // There are two diferent Poseidon custom gates: Poseidon and CustPoseidon. The first one is a regular hash of + // three inputs, while the second one hashes two inputs (the third one is zero). However, in CustPoseidon custom + // gate the two values to hash (value and sibling) are sent unordered and the key specifying which element is the + // first one and which is the second one is also provided. + + // Order the each of the GL Poseidon inputs according to the key, which is stored in a[8] + + pol custPoseidonInput0 = a[8] * (a[0] - a[4]) + a[4]; + pol custPoseidonInput1 = a[8] * (a[1] - a[5]) + a[5]; + pol custPoseidonInput2 = a[8] * (a[2] - a[6]) + a[6]; + pol custPoseidonInput3 = a[8] * (a[3] - a[7]) + a[7]; + pol custPoseidonInput4 = a[8] * (a[4] - a[0]) + a[0]; + pol custPoseidonInput5 = a[8] * (a[5] - a[1]) + a[1]; + pol custPoseidonInput6 = a[8] * (a[6] - a[2]) + a[2]; + pol custPoseidonInput7 = a[8] * (a[7] - a[3]) + a[3]; + + pol checkBinary = a[8] * (a[8] - 1); + POSEIDONCUSTFIRST * checkBinary = 0; + + // Calculate the 7th power of the 0th element + pol inp0 = POSEIDONCUSTFIRST * (custPoseidonInput0 - a[0]) + a[0] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xb585f766f2144405; + // Calculate the 7th power of the 0th element + pol constC0 = PARTIALROUND * (0x315f63f4fec360ba - C[0]) + C[0]; + pol a0_2 = inp0 * inp0; + pol a0_4 = a0_2 * a0_2; + pol a0_6 = a0_4 * a0_2; + pol a0_R = a0_6 * inp0 + constC0; + + pol s0_R0 = 0x19 * a0_R + 0x3d999c961b7c63b0 * a[1] + 0x814e82efcd172529 * a[2] + 0x2421e5d236704588 * a[3] + 0x887af7d4dd482328 * a[4] + 0xa5e9c291f6119b27 * a[5] + 0xbdc52b2676a4b4aa * a[6] + 0x64832009d29bcf57 * a[7] + 0x9c4155174a552cc * a[8] + 0x463f9ee03d290810 * a[9] + 0xc810936e64982542 * a[10] + 0x43b1c289f7bc3ac * a[11]; + pol s1_R0 = a[1] + a0_R * 0x94877900674181c3; + pol s2_R0 = a[2] + a0_R * 0xc6c67cc37a2a2bbd; + pol s3_R0 = a[3] + a0_R * 0xd667c2055387940f; + pol s4_R0 = a[4] + a0_R * 0xba63a63e94b5ff0; + pol s5_R0 = a[5] + a0_R * 0x99460cc41b8f079f; + pol s6_R0 = a[6] + a0_R * 0x7ff02375ed524bb3; + pol s7_R0 = a[7] + a0_R * 0xea0870b47a8caf0e; + pol s8_R0 = a[8] + a0_R * 0xabcad82633b7bc9d; + pol s9_R0 = a[9] + a0_R * 0x3b8d135261052241; + pol s10_R0 = a[10] + a0_R * 0xfb4515f5e5b0d539; + pol s11_R0 = a[11] + a0_R * 0x3ee8011c2b37f77c; + // Calculate the 7th power of the 1th element + pol inp1 = POSEIDONCUSTFIRST * (custPoseidonInput1 - a[1]) + a[1] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0x7746a55f43921ad7; + pol inputP1 = PARTIALROUND * (s0_R0 - inp1) + inp1; + pol constC1 = PARTIALROUND * (0xf3009795713abcf1 - C[1]) + C[1]; + pol a1_2 = inputP1 * inputP1; + pol a1_4 = a1_2 * a1_2; + pol a1_6 = a1_4 * a1_2; + pol a1_R = a1_6 * inputP1 + constC1; + + pol s0_R1 = 0x19 * a1_R + 0x673655aae8be5a8b * s1_R0 + 0xd510fe714f39fa10 * s2_R0 + 0x2c68a099b51c9e73 * s3_R0 + 0xa667bfa9aa96999d * s4_R0 + 0x4d67e72f063e2108 * s5_R0 + 0xf84dde3e6acda179 * s6_R0 + 0x40f9cc8c08f80981 * s7_R0 + 0x5ead032050097142 * s8_R0 + 0x6591b02092d671bb * s9_R0 + 0xe18c71963dd1b7 * s10_R0 + 0x8a21bcd24a14218a * s11_R0; + pol s1_R1 = s1_R0 + a1_R * 0xadef3740e71c726; + pol s2_R1 = s2_R0 + a1_R * 0xa37bf67c6f986559; + pol s3_R1 = s3_R0 + a1_R * 0xc6b16f7ed4fa1b00; + pol s4_R1 = s4_R0 + a1_R * 0x6a065da88d8bfc3c; + pol s5_R1 = s5_R0 + a1_R * 0x4cabc0916844b46f; + pol s6_R1 = s6_R0 + a1_R * 0x407faac0f02e78d1; + pol s7_R1 = s7_R0 + a1_R * 0x7a786d9cf0852cf; + pol s8_R1 = s8_R0 + a1_R * 0x42433fb6949a629a; + pol s9_R1 = s9_R0 + a1_R * 0x891682a147ce43b0; + pol s10_R1 = s10_R0 + a1_R * 0x26cfd58e7b003b55; + pol s11_R1 = s11_R0 + a1_R * 0x2bbf0ed7b657acb3; + // Calculate the 7th power of the 2th element + pol inp2 = POSEIDONCUSTFIRST * (custPoseidonInput2 - a[2]) + a[2] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xb2fb0d31cee799b4; + pol inputP2 = PARTIALROUND * (s0_R1 - inp2) + inp2; + pol constC2 = PARTIALROUND * (0xf4decc3fb00765ee - C[2]) + C[2]; + pol a2_2 = inputP2 * inputP2; + pol a2_4 = a2_2 * a2_2; + pol a2_6 = a2_4 * a2_2; + pol a2_R = a2_6 * inputP2 + constC2; + + pol s0_R2 = 0x19 * a2_R + 0x202800f4addbdc87 * s1_R1 + 0xe4b5bdb1cc3504ff * s2_R1 + 0xbe32b32a825596e7 * s3_R1 + 0x8e0f68c5dc223b9a * s4_R1 + 0x58022d9e1c256ce3 * s5_R1 + 0x584d29227aa073ac * s6_R1 + 0x8b9352ad04bef9e7 * s7_R1 + 0xaead42a3f445ecbf * s8_R1 + 0x3c667a1d833a3cca * s9_R1 + 0xda6f61838efa1ffe * s10_R1 + 0xe8f749470bd7c446 * s11_R1; + pol s1_R2 = s1_R1 + a2_R * 0x481ac7746b159c67; + pol s2_R2 = s2_R1 + a2_R * 0xe367de32f108e278; + pol s3_R2 = s3_R1 + a2_R * 0x73f260087ad28bec; + pol s4_R2 = s4_R1 + a2_R * 0x5cfc82216bc1bdca; + pol s5_R2 = s5_R1 + a2_R * 0xcaccc870a2663a0e; + pol s6_R2 = s6_R1 + a2_R * 0xdb69cd7b4298c45d; + pol s7_R2 = s7_R1 + a2_R * 0x7bc9e0c57243e62d; + pol s8_R2 = s8_R1 + a2_R * 0x3cc51c5d368693ae; + pol s9_R2 = s9_R1 + a2_R * 0x366b4e8cc068895b; + pol s10_R2 = s10_R1 + a2_R * 0x2bd18715cdabbca4; + pol s11_R2 = s11_R1 + a2_R * 0xa752061c4f33b8cf; + // Calculate the 7th power of the 3th element + pol inp3 = POSEIDONCUSTFIRST * (custPoseidonInput3 - a[3]) + a[3] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xf6760a4803427d7; + pol inputP3 = PARTIALROUND * (s0_R2 - inp3) + inp3; + pol constC3 = PARTIALROUND * (0x32620ac918682d50 - C[3]) + C[3]; + pol a3_2 = inputP3 * inputP3; + pol a3_4 = a3_2 * a3_2; + pol a3_6 = a3_4 * a3_2; + pol a3_R = a3_6 * inputP3 + constC3; + + pol s0_R3 = 0x19 * a3_R + 0xc5b85bab9e5b3869 * s1_R2 + 0x45245258aec51cf7 * s2_R2 + 0x16e6b8e68b931830 * s3_R2 + 0xe2ae0f051418112c * s4_R2 + 0x470e26a0093a65b * s5_R2 + 0x6bef71973a8146ed * s6_R2 + 0x119265be51812daf * s7_R2 + 0xb0be7356254bea2e * s8_R2 + 0x8584defff7589bd7 * s9_R2 + 0x3c5fe4aeb1fb52ba * s10_R2 + 0x9e7cd88acf543a5e * s11_R2; + pol s1_R3 = s1_R2 + a3_R * 0xb22d2432b72d5098; + pol s2_R3 = s2_R2 + a3_R * 0x9e18a487f44d2fe4; + pol s3_R3 = s3_R2 + a3_R * 0x4b39e14ce22abd3c; + pol s4_R3 = s4_R2 + a3_R * 0x9e77fde2eb315e0d; + pol s5_R3 = s5_R2 + a3_R * 0xca5e0385fe67014d; + pol s6_R3 = s6_R2 + a3_R * 0xc2cb99bf1b6bddb; + pol s7_R3 = s7_R2 + a3_R * 0x99ec1cd2a4460bfe; + pol s8_R3 = s8_R2 + a3_R * 0x8577a815a2ff843f; + pol s9_R3 = s9_R2 + a3_R * 0x7d80a6b4fd6518a5; + pol s10_R3 = s10_R2 + a3_R * 0xeb6c67123eab62cb; + pol s11_R3 = s11_R2 + a3_R * 0x8f7851650eca21a5; + // Calculate the 7th power of the 4th element + pol inp4 = POSEIDONCUSTFIRST * (custPoseidonInput4 - a[4]) + a[4] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xe10d666650f4e012; + pol inputP4 = PARTIALROUND * (s0_R3 - inp4) + inp4; + pol constC4 = PARTIALROUND * (0x49717d63a5fc742e - C[4]) + C[4]; + pol a4_2 = inputP4 * inputP4; + pol a4_4 = a4_2 * a4_2; + pol a4_6 = a4_4 * a4_2; + pol a4_R = a4_6 * inputP4 + constC4; + + pol s0_R4 = 0x19 * a4_R + 0x179be4bba87f0a8c * s1_R3 + 0xacf63d95d8887355 * s2_R3 + 0x6696670196b0074f * s3_R3 + 0xd99ddf1fe75085f9 * s4_R3 + 0xc2597881fef0283b * s5_R3 + 0xcf48395ee6c54f14 * s6_R3 + 0x15226a8e4cd8d3b6 * s7_R3 + 0xc053297389af5d3b * s8_R3 + 0x2c08893f0d1580e2 * s9_R3 + 0xed3cbcff6fcc5ba * s10_R3 + 0xc82f510ecf81f6d0 * s11_R3; + pol s1_R4 = s1_R3 + a4_R * 0x11ba9a1b81718c2a; + pol s2_R4 = s2_R3 + a4_R * 0x9f7d798a3323410c; + pol s3_R4 = s3_R3 + a4_R * 0xa821855c8c1cf5e5; + pol s4_R4 = s4_R3 + a4_R * 0x535e8d6fac0031b2; + pol s5_R4 = s5_R3 + a4_R * 0x404e7c751b634320; + pol s6_R4 = s6_R3 + a4_R * 0xa729353f6e55d354; + pol s7_R4 = s7_R3 + a4_R * 0x4db97d92e58bb831; + pol s8_R4 = s8_R3 + a4_R * 0xb53926c27897bf7d; + pol s9_R4 = s9_R3 + a4_R * 0x965040d52fe115c5; + pol s10_R4 = s10_R3 + a4_R * 0x9565fa41ebd31fd7; + pol s11_R4 = s11_R3 + a4_R * 0xaae4438c877ea8f4; + // Calculate the 7th power of the 5th element + pol inp5 = POSEIDONCUSTFIRST * (custPoseidonInput5 - a[5]) + a[5] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0x8cae14cb07d09bf1; + pol inputP5 = PARTIALROUND * (s0_R4 - inp5) + inp5; + pol constC5 = PARTIALROUND * (0x153516f22014ea2d - C[5]) + C[5]; + pol a5_2 = inputP5 * inputP5; + pol a5_4 = a5_2 * a5_2; + pol a5_6 = a5_4 * a5_2; + pol a5_R = a5_6 * inputP5 + constC5; + + pol s0_R5 = 0x19 * a5_R + 0x94b06183acb715cc * s1_R4 + 0x500392ed0d431137 * s2_R4 + 0x861cc95ad5c86323 * s3_R4 + 0x5830a443f86c4ac * s4_R4 + 0x3b68225874a20a7c * s5_R4 + 0x10b3309838e236fb * s6_R4 + 0x9b77fc8bcd559e2c * s7_R4 + 0xbdecf5e0cb9cb213 * s8_R4 + 0x30276f1221ace5fa * s9_R4 + 0x7935dd342764a144 * s10_R4 + 0xeac6db520bb03708 * s11_R4; + pol s1_R5 = s1_R4 + a5_R * 0x37f4e36af6073c6e; + pol s2_R5 = s2_R4 + a5_R * 0x4edc0918210800e9; + pol s3_R5 = s3_R4 + a5_R * 0xc44998e99eae4188; + pol s4_R5 = s4_R4 + a5_R * 0x9f4310d05d068338; + pol s5_R5 = s5_R4 + a5_R * 0x9ec7fe4350680f29; + pol s6_R5 = s6_R4 + a5_R * 0xc5b2c1fdc0b50874; + pol s7_R5 = s7_R4 + a5_R * 0xa01920c5ef8b2ebe; + pol s8_R5 = s8_R4 + a5_R * 0x59fa6f8bd91d58ba; + pol s9_R5 = s9_R4 + a5_R * 0x8bfc9eb89b515a82; + pol s10_R5 = s10_R4 + a5_R * 0xbe86a7a2555ae775; + pol s11_R5 = s11_R4 + a5_R * 0xcbb8bbaa3810babf; + // Calculate the 7th power of the 6th element + pol inp6 = POSEIDONCUSTFIRST * (custPoseidonInput6 - a[6]) + a[6] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xd438539c95f63e9f; + pol inputP6 = PARTIALROUND * (s0_R5 - inp6) + inp6; + pol constC6 = PARTIALROUND * (0xcc316380a2761fe4 - C[6]) + C[6]; + pol a6_2 = inputP6 * inputP6; + pol a6_4 = a6_2 * a6_2; + pol a6_6 = a6_4 * a6_2; + pol a6_R = a6_6 * inputP6 + constC6; + + pol s0_R6 = 0x19 * a6_R + 0x7186a80551025f8f * s1_R5 + 0x622247557e9b5371 * s2_R5 + 0xc4cbe326d1ad9742 * s3_R5 + 0x55f1523ac6a23ea2 * s4_R5 + 0xa13dfe77a3d52f53 * s5_R5 + 0xe30750b6301c0452 * s6_R5 + 0x8bd488070a3a32b * s7_R5 + 0xcd800caef5b72ae3 * s8_R5 + 0x83329c90f04233ce * s9_R5 + 0xb5b99e6664a0a3ee * s10_R5 + 0x6b0731849e200a7f * s11_R5; + pol s1_R6 = s1_R5 + a6_R * 0x577f9a9e7ee3f9c2; + pol s2_R6 = s2_R5 + a6_R * 0x88c522b949ace7b1; + pol s3_R6 = s3_R5 + a6_R * 0x82f07007c8b72106; + pol s4_R6 = s4_R5 + a6_R * 0x8283d37c6675b50e; + pol s5_R6 = s5_R5 + a6_R * 0x98b074d9bbac1123; + pol s6_R6 = s6_R5 + a6_R * 0x75c56fb7758317c1; + pol s7_R6 = s7_R5 + a6_R * 0xfed24e206052bc72; + pol s8_R6 = s8_R5 + a6_R * 0x26d7c3d1bc07dae5; + pol s9_R6 = s9_R5 + a6_R * 0xf88c5e441e28dbb4; + pol s10_R6 = s10_R5 + a6_R * 0x4fe27f9f96615270; + pol s11_R6 = s11_R5 + a6_R * 0x514d4ba49c2b14fe; + // Calculate the 7th power of the 7th element + pol inp7 = POSEIDONCUSTFIRST * (custPoseidonInput7 - a[7]) + a[7] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xef781c7ce35b4c3d; + pol inputP7 = PARTIALROUND * (s0_R6 - inp7) + inp7; + pol constC7 = PARTIALROUND * (0x2e49b3f7076d203d - C[7]) + C[7]; + pol a7_2 = inputP7 * inputP7; + pol a7_4 = a7_2 * a7_2; + pol a7_6 = a7_4 * a7_2; + pol a7_R = a7_6 * inputP7 + constC7; + + pol s0_R7 = 0x19 * a7_R + 0xec3fabc192b01799 * s1_R6 + 0x382b38cee8ee5375 * s2_R6 + 0x3bfb6c3f0e616572 * s3_R6 + 0x514abd0cf6c7bc86 * s4_R6 + 0x47521b1361dcc546 * s5_R6 + 0x178093843f863d14 * s6_R6 + 0xad1003c5d28918e7 * s7_R6 + 0x738450e42495bc81 * s8_R6 + 0xaf947c59af5e4047 * s9_R6 + 0x4653fb0685084ef2 * s10_R6 + 0x57fde2062ae35bf * s11_R6; + pol s1_R7 = s1_R6 + a7_R * 0xf02a3ac068ee110b; + pol s2_R7 = s2_R6 + a7_R * 0xa3630dafb8ae2d7; + pol s3_R7 = s3_R6 + a7_R * 0xce0dc874eaf9b55c; + pol s4_R7 = s4_R6 + a7_R * 0x9a95f6cff5b55c7e; + pol s5_R7 = s5_R6 + a7_R * 0x626d76abfed00c7b; + pol s6_R7 = s6_R6 + a7_R * 0xa0c1cf1251c204ad; + pol s7_R7 = s7_R6 + a7_R * 0xdaebd3006321052c; + pol s8_R7 = s8_R6 + a7_R * 0x3d4bd48b625a8065; + pol s9_R7 = s9_R6 + a7_R * 0x7f1e584e071f6ed2; + pol s10_R7 = s10_R6 + a7_R * 0x720574f0501caed3; + pol s11_R7 = s11_R6 + a7_R * 0xe3260ba93d23540a; + // Calculate the 7th power of the 8th element + pol inp8 = POSEIDONCUSTFIRST * (-a[8]) + a[8] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xcdc4a239b0c44426; + pol inputP8 = PARTIALROUND * (s0_R7 - inp8) + inp8; + pol constC8 = PARTIALROUND * (0x44ac3e9bf0a2dc89 - C[8]) + C[8]; + pol a8_2 = inputP8 * inputP8; + pol a8_4 = a8_2 * a8_2; + pol a8_6 = a8_4 * a8_2; + pol a8_R = a8_6 * inputP8 + constC8; + + pol s0_R8 = 0x19 * a8_R + 0xe376678d843ce55e * s1_R7 + 0x66f3860d7514e7fc * s2_R7 + 0x7817f3dfff8b4ffa * s3_R7 + 0x3929624a9def725b * s4_R7 + 0x126ca37f215a80a * s5_R7 + 0xfce2f5d02762a303 * s6_R7 + 0x1bc927375febbad7 * s7_R7 + 0x85b481e5243f60bf * s8_R7 + 0x2d3c5f42a39c91a0 * s9_R7 + 0x811719919351ae8 * s10_R7 + 0xf669de0add993131 * s11_R7; + pol s1_R8 = s1_R7 + a8_R * 0xab1cbd41d8c1e335; + pol s2_R8 = s2_R7 + a8_R * 0x9322ed4c0bc2df01; + pol s3_R8 = s3_R7 + a8_R * 0x51c3c0983d4284e5; + pol s4_R8 = s4_R7 + a8_R * 0x94178e291145c231; + pol s5_R8 = s5_R7 + a8_R * 0xfd0f1a973d6b2085; + pol s6_R8 = s6_R7 + a8_R * 0xd427ad96e2b39719; + pol s7_R8 = s7_R7 + a8_R * 0x8a52437fecaac06b; + pol s8_R8 = s8_R7 + a8_R * 0xdc20ee4b8c4c9a80; + pol s9_R8 = s9_R7 + a8_R * 0xa2c98e9549da2100; + pol s10_R8 = s10_R7 + a8_R * 0x1603fe12613db5b6; + pol s11_R8 = s11_R7 + a8_R * 0xe174929433c5505; + // Calculate the 7th power of the 9th element + pol inp9 = POSEIDONCUSTFIRST * (-a[9]) + a[9] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0x277fa208bf337bff; + pol inputP9 = PARTIALROUND * (s0_R8 - inp9) + inp9; + pol constC9 = PARTIALROUND * (0x49d1e388d8e35c - C[9]) + C[9]; + pol a9_2 = inputP9 * inputP9; + pol a9_4 = a9_2 * a9_2; + pol a9_6 = a9_4 * a9_2; + pol a9_R = a9_6 * inputP9 + constC9; + + pol s0_R9 = 0x19 * a9_R + 0x7de38bae084da92d * s1_R8 + 0x5b848442237e8a9b * s2_R8 + 0xf6c705da84d57310 * s3_R8 + 0x31e6a4bdb6a49017 * s4_R8 + 0x889489706e5c5c0f * s5_R8 + 0xe4a205459692a1b * s6_R8 + 0xbac3fa75ee26f299 * s7_R8 + 0x5f5894f4057d755e * s8_R8 + 0xb0dc3ecd724bb076 * s9_R8 + 0x5e34d8554a6452ba * s10_R8 + 0x4f78fd8c1fdcc5f * s11_R8; + pol s1_R9 = s1_R8 + a9_R * 0x3d4eab2b8ef5f796; + pol s2_R9 = s2_R8 + a9_R * 0xcfff421583896e22; + pol s3_R9 = s3_R8 + a9_R * 0x4143cb32d39ac3d9; + pol s4_R9 = s4_R8 + a9_R * 0x22365051b78a5b65; + pol s5_R9 = s5_R8 + a9_R * 0x6f7fd010d027c9b6; + pol s6_R9 = s6_R8 + a9_R * 0xd9dd36fba77522ab; + pol s7_R9 = s7_R8 + a9_R * 0xa44cf1cb33e37165; + pol s8_R9 = s8_R8 + a9_R * 0x3fc83d3038c86417; + pol s9_R9 = s9_R8 + a9_R * 0xc4588d418e88d270; + pol s10_R9 = s10_R8 + a9_R * 0xce1320f10ab80fe2; + pol s11_R9 = s11_R8 + a9_R * 0xdb5eadbbec18de5d; + // Calculate the 7th power of the 10th element + pol inp10 = POSEIDONCUSTFIRST * (-a[10]) + a[10] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xe17653a29da578a1; + pol inputP10 = PARTIALROUND * (s0_R9 - inp10) + inp10; + pol constC10 = PARTIALROUND * (0x53ec867cb39989fa - C[10]) + C[10]; + pol a10_2 = inputP10 * inputP10; + pol a10_4 = a10_2 * a10_2; + pol a10_6 = a10_4 * a10_2; + pol a10_R = a10_6 * inputP10 + constC10; + + pol s0_R10 = 0x19 * a10_R + 0x4dd19c38779512ea * s1_R9 + 0xdb79ba02704620e9 * s2_R9 + 0x92a29a3675a5d2be * s3_R9 + 0xd5177029fe495166 * s4_R9 + 0xd32b3298a13330c1 * s5_R9 + 0x251c4a3eb2c5f8fd * s6_R9 + 0xe1c48b26e0d98825 * s7_R9 + 0x3301d3362a4ffccb * s8_R9 + 0x9bb6c88de8cd178 * s9_R9 + 0xdc05b676564f538a * s10_R9 + 0x60192d883e473fee * s11_R9; + pol s1_R10 = s1_R9 + a10_R * 0x1183dfce7c454afd; + pol s2_R10 = s2_R9 + a10_R * 0x21cea4aa3d3ed949; + pol s3_R10 = s3_R9 + a10_R * 0xfce6f70303f2304; + pol s4_R10 = s4_R9 + a10_R * 0x19557d34b55551be; + pol s5_R10 = s5_R9 + a10_R * 0x4c56f689afc5bbc9; + pol s6_R10 = s6_R9 + a10_R * 0xa1e920844334f944; + pol s7_R10 = s7_R9 + a10_R * 0xbad66d423d2ec861; + pol s8_R10 = s8_R9 + a10_R * 0xf318c785dc9e0479; + pol s9_R10 = s9_R9 + a10_R * 0x99e2032e765ddd81; + pol s10_R10 = s10_R9 + a10_R * 0x400ccc9906d66f45; + pol s11_R10 = s11_R9 + a10_R * 0xe1197454db2e0dd9; + // Calculate the 7th power of the 11th element + pol inp11 = POSEIDONCUSTFIRST * (-a[11]) + a[11] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xc54302f225db2c76; + pol inputP11 = PARTIALROUND * (s0_R10 - inp11) + inp11; + pol constC11 = PARTIALROUND * (0xd2c9bcc8d65f5a62 - C[11]) + C[11]; + pol a11_2 = inputP11 * inputP11; + pol a11_4 = a11_2 * a11_2; + pol a11_6 = a11_4 * a11_2; + pol a11_R = a11_6 * inputP11 + constC11; + + pol s0_R11 = 0x19 * a11_R + 0x16b9774801ac44a0 * s1_R10 + 0x3cb8411e786d3c8e * s2_R10 + 0xa86e9cf505072491 * s3_R10 + 0x178928152e109ae * s4_R10 + 0x5317b905a6e1ab7b * s5_R10 + 0xda20b3be7f53d59f * s6_R10 + 0xcb97dedecebee9ad * s7_R10 + 0x4bd545218c59f58d * s8_R10 + 0x77dc8d856c05a44a * s9_R10 + 0x87948589e4f243fd * s10_R10 + 0x7e5217af969952c2 * s11_R10; + pol s1_R11 = s1_R10 + a11_R * 0x84d1ecc4d53d2ff1; + pol s2_R11 = s2_R10 + a11_R * 0xd8af8b9ceb4e11b6; + pol s3_R11 = s3_R10 + a11_R * 0x335856bb527b52f4; + pol s4_R11 = s4_R10 + a11_R * 0xc756f17fb59be595; + pol s5_R11 = s5_R10 + a11_R * 0xc0654e4ea5553a78; + pol s6_R11 = s6_R10 + a11_R * 0x9e9a46b61f2ea942; + pol s7_R11 = s7_R10 + a11_R * 0x14fc8b5b3b809127; + pol s8_R11 = s8_R10 + a11_R * 0xd7009f0f103be413; + pol s9_R11 = s9_R10 + a11_R * 0x3e0ee7b7a9fb4601; + pol s10_R11 = s10_R10 + a11_R * 0xa74e888922085ed7; + pol s11_R11 = s11_R10 + a11_R * 0xe80a7cde3d4ac526; + pol poseidonM0 = 0x19 * a0_R + 0xf * a1_R + 0x29 * a2_R + 0x10 * a3_R + 0x2 * a4_R + 0x1c * a5_R + 0xd * a6_R + 0xd * a7_R + 0x27 * a8_R + 0x12 * a9_R + 0x22 * a10_R + 0x14 * a11_R; + pol poseidonM1 = 0x14 * a0_R + 0x11 * a1_R + 0xf * a2_R + 0x29 * a3_R + 0x10 * a4_R + 0x2 * a5_R + 0x1c * a6_R + 0xd * a7_R + 0xd * a8_R + 0x27 * a9_R + 0x12 * a10_R + 0x22 * a11_R; + pol poseidonM2 = 0x22 * a0_R + 0x14 * a1_R + 0x11 * a2_R + 0xf * a3_R + 0x29 * a4_R + 0x10 * a5_R + 0x2 * a6_R + 0x1c * a7_R + 0xd * a8_R + 0xd * a9_R + 0x27 * a10_R + 0x12 * a11_R; + pol poseidonM3 = 0x12 * a0_R + 0x22 * a1_R + 0x14 * a2_R + 0x11 * a3_R + 0xf * a4_R + 0x29 * a5_R + 0x10 * a6_R + 0x2 * a7_R + 0x1c * a8_R + 0xd * a9_R + 0xd * a10_R + 0x27 * a11_R; + pol poseidonM4 = 0x27 * a0_R + 0x12 * a1_R + 0x22 * a2_R + 0x14 * a3_R + 0x11 * a4_R + 0xf * a5_R + 0x29 * a6_R + 0x10 * a7_R + 0x2 * a8_R + 0x1c * a9_R + 0xd * a10_R + 0xd * a11_R; + pol poseidonM5 = 0xd * a0_R + 0x27 * a1_R + 0x12 * a2_R + 0x22 * a3_R + 0x14 * a4_R + 0x11 * a5_R + 0xf * a6_R + 0x29 * a7_R + 0x10 * a8_R + 0x2 * a9_R + 0x1c * a10_R + 0xd * a11_R; + pol poseidonM6 = 0xd * a0_R + 0xd * a1_R + 0x27 * a2_R + 0x12 * a3_R + 0x22 * a4_R + 0x14 * a5_R + 0x11 * a6_R + 0xf * a7_R + 0x29 * a8_R + 0x10 * a9_R + 0x2 * a10_R + 0x1c * a11_R; + pol poseidonM7 = 0x1c * a0_R + 0xd * a1_R + 0xd * a2_R + 0x27 * a3_R + 0x12 * a4_R + 0x22 * a5_R + 0x14 * a6_R + 0x11 * a7_R + 0xf * a8_R + 0x29 * a9_R + 0x10 * a10_R + 0x2 * a11_R; + pol poseidonM8 = 0x2 * a0_R + 0x1c * a1_R + 0xd * a2_R + 0xd * a3_R + 0x27 * a4_R + 0x12 * a5_R + 0x22 * a6_R + 0x14 * a7_R + 0x11 * a8_R + 0xf * a9_R + 0x29 * a10_R + 0x10 * a11_R; + pol poseidonM9 = 0x10 * a0_R + 0x2 * a1_R + 0x1c * a2_R + 0xd * a3_R + 0xd * a4_R + 0x27 * a5_R + 0x12 * a6_R + 0x22 * a7_R + 0x14 * a8_R + 0x11 * a9_R + 0xf * a10_R + 0x29 * a11_R; + pol poseidonM10 = 0x29 * a0_R + 0x10 * a1_R + 0x2 * a2_R + 0x1c * a3_R + 0xd * a4_R + 0xd * a5_R + 0x27 * a6_R + 0x12 * a7_R + 0x22 * a8_R + 0x14 * a9_R + 0x11 * a10_R + 0xf * a11_R; + pol poseidonM11 = 0xf * a0_R + 0x29 * a1_R + 0x10 * a2_R + 0x2 * a3_R + 0x1c * a4_R + 0xd * a5_R + 0xd * a6_R + 0x27 * a7_R + 0x12 * a8_R + 0x22 * a9_R + 0x14 * a10_R + 0x11 * a11_R; + + // Calculate the 7th power of the 12th element + pol inputP12 = PARTIALROUND * (s0_R11 - poseidonM0) + poseidonM0; + pol constC_12 = PARTIALROUND * 0xc0cc930ee8540455 + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xcd09dea180de4f2c + POSEIDONP * 0x8aa35b97a0e03c04 + POSEIDONAFTERPART * 0x76133eecfd9bd1ff; + pol a12_2 = inputP12 * inputP12; + pol a12_4 = a12_2 * a12_2; + pol a12_6 = a12_4 * a12_2; + pol a12_R = a12_6 * inputP12 + constC_12; + + + pol s0_R12 = 0x19 * a12_R + 0xbc58987d06a84e4d * s1_R11 + 0xb5d420244c9cae3 * s2_R11 + 0xa3c4711b938c02c0 * s3_R11 + 0x3aace640a3e03990 * s4_R11 + 0x865a0f3249aacd8a * s5_R11 + 0x8d00b2a7dbed06c7 * s6_R11 + 0x6eacb905beb7e2f8 * s7_R11 + 0x45322b216ec3ec7 * s8_R11 + 0xeb9de00d594828e6 * s9_R11 + 0x88c5f20df9e5c26 * s10_R11 + 0xf555f4112b19781f * s11_R11; + pol s1_R12 = s1_R11 + a12_R * 0x238aa6daa612186d; + pol s2_R12 = s2_R11 + a12_R * 0x9137a5c630bad4b4; + pol s3_R12 = s3_R11 + a12_R * 0xc7db3817870c5eda; + pol s4_R12 = s4_R11 + a12_R * 0x217e4f04e5718dc9; + pol s5_R12 = s5_R11 + a12_R * 0xcae814e2817bd99d; + pol s6_R12 = s6_R11 + a12_R * 0xe3292e7ab770a8ba; + pol s7_R12 = s7_R11 + a12_R * 0x7bb36ef70b6b9482; + pol s8_R12 = s8_R11 + a12_R * 0x3c7835fb85bca2d3; + pol s9_R12 = s9_R11 + a12_R * 0xfe2cdf8ee3c25e86; + pol s10_R12 = s10_R11 + a12_R * 0x61b3915ad7274b20; + pol s11_R12 = s11_R11 + a12_R * 0xeab75ca7c918e4ef; + + // Calculate the 7th power of the 13th element + pol inputP13 = PARTIALROUND * (s0_R12 - poseidonM1) + poseidonM1; + pol constC_13 = PARTIALROUND * 0x40651e0872505e8 + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xadb069225c93e4e6 + POSEIDONP * 0xcf42a59addbd1f0c + POSEIDONAFTERPART * 0x3fb0fd5381054812; + pol a13_2 = inputP13 * inputP13; + pol a13_4 = a13_2 * a13_2; + pol a13_6 = a13_4 * a13_2; + pol a13_R = a13_6 * inputP13 + constC_13; + + + pol s0_R13 = 0x19 * a13_R + 0xa8cedbff1813d3a7 * s1_R12 + 0x50dcaee0fd27d164 * s2_R12 + 0xf1cb02417e23bd82 * s3_R12 + 0xfaf322786e2abe8b * s4_R12 + 0x937a4315beb5d9b6 * s5_R12 + 0x1b18992921a11d85 * s6_R12 + 0x7d66c4368b3c497b * s7_R12 + 0xe7946317a6b4e99 * s8_R12 + 0xbe4430134182978b * s9_R12 + 0x3771e82493ab262d * s10_R12 + 0xa671690d8095ce82 * s11_R12; + pol s1_R13 = s1_R12 + a13_R * 0xd6e15ffc055e154e; + pol s2_R13 = s2_R12 + a13_R * 0xec67881f381a32bf; + pol s3_R13 = s3_R12 + a13_R * 0xfbb1196092bf409c; + pol s4_R13 = s4_R12 + a13_R * 0xdc9d2e07830ba226; + pol s5_R13 = s5_R12 + a13_R * 0x698ef3245ff7988; + pol s6_R13 = s6_R12 + a13_R * 0x194fae2974f8b576; + pol s7_R13 = s7_R12 + a13_R * 0x7a5d9bea6ca4910e; + pol s8_R13 = s8_R12 + a13_R * 0x7aebfea95ccdd1c9; + pol s9_R13 = s9_R12 + a13_R * 0xf9bd38a67d5f0e86; + pol s10_R13 = s10_R12 + a13_R * 0xfa65539de65492d8; + pol s11_R13 = s11_R12 + a13_R * 0xf0dfcbe7653ff787; + + // Calculate the 7th power of the 14th element + pol inputP14 = PARTIALROUND * (s0_R13 - poseidonM2) + poseidonM2; + pol constC_14 = PARTIALROUND * 0x168973b2ebafbe6c + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xbf01209b8a7c8534 + POSEIDONP * 0xa43ace89f8fdbd79 + POSEIDONAFTERPART * 0xf15925978dbd52ff; + pol a14_2 = inputP14 * inputP14; + pol a14_4 = a14_2 * a14_2; + pol a14_6 = a14_4 * a14_2; + pol a14_R = a14_6 * inputP14 + constC_14; + + + pol s0_R14 = 0x19 * a14_R + 0xb035585f6e929d9d * s1_R13 + 0xba1579c7e219b954 * s2_R13 + 0xcb201cf846db4ba3 * s3_R13 + 0x287bf9177372cf45 * s4_R13 + 0xa350e4f61147d0a6 * s5_R13 + 0xd5d0ecfb50bcff99 * s6_R13 + 0x2e166aa6c776ed21 * s7_R13 + 0xe1e66c991990e282 * s8_R13 + 0x662b329b01e7bb38 * s9_R13 + 0x8aa674b36144d9a9 * s10_R13 + 0xcbabf78f97f95e65 * s11_R13; + pol s1_R14 = s1_R13 + a14_R * 0xbd87ad390420258; + pol s2_R14 = s2_R13 + a14_R * 0xad8617bca9e33c8; + pol s3_R14 = s3_R13 + a14_R * 0xc00ad377a1e2666; + pol s4_R14 = s4_R13 + a14_R * 0xac6fc58b3f0518f; + pol s5_R14 = s5_R13 + a14_R * 0xc0cc8a892cc4173; + pol s6_R14 = s6_R13 + a14_R * 0xc210accb117bc21; + pol s7_R14 = s7_R13 + a14_R * 0xb73630dbb46ca18; + pol s8_R14 = s8_R13 + a14_R * 0xc8be4920cbd4a54; + pol s9_R14 = s9_R13 + a14_R * 0xbfe877a21be1690; + pol s10_R14 = s10_R13 + a14_R * 0xae790559b0ded81; + pol s11_R14 = s11_R13 + a14_R * 0xbf50db2f8d6ce31; + + // Calculate the 7th power of the 15th element + pol inputP15 = PARTIALROUND * (s0_R14 - poseidonM3) + poseidonM3; + pol constC_15 = PARTIALROUND * 0x9c7eecb3b40581c2 + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xb1eb37d319913823 + POSEIDONP * 0x37585d8c243870c + POSEIDONAFTERPART * 0x2ee289ac37f0e879; + pol a15_2 = inputP15 * inputP15; + pol a15_4 = a15_2 * a15_2; + pol a15_6 = a15_4 * a15_2; + pol a15_R = a15_6 * inputP15 + constC_15; + + + pol s0_R15 = 0x19 * a15_R + 0xeec24b15a06b53fe * s1_R14 + 0xc8a7aa07c5633533 * s2_R14 + 0xefe9c6fa4311ad51 * s3_R14 + 0xb9173f13977109a1 * s4_R14 + 0x69ce43c9cc94aedc * s5_R14 + 0xecf623c9cd118815 * s6_R14 + 0x28625def198c33c7 * s7_R14 + 0xccfc5f7de5c3636a * s8_R14 + 0xf5e6c40f1621c299 * s9_R14 + 0xcec0e58c34cb64b1 * s10_R14 + 0xa868ea113387939f * s11_R14; + pol s1_R15 = s1_R14 + a15_R * 0xcf29427ff7c58; + pol s2_R15 = s2_R14 + a15_R * 0xbd9b3cf49eec8; + pol s3_R15 = s3_R14 + a15_R * 0xd1dc8aa81fb26; + pol s4_R15 = s4_R14 + a15_R * 0xbc792d5c394ef; + pol s5_R15 = s5_R14 + a15_R * 0xd2ae0b2266453; + pol s6_R15 = s6_R14 + a15_R * 0xd413f12c496c1; + pol s7_R15 = s7_R14 + a15_R * 0xc84128cfed618; + pol s8_R15 = s8_R14 + a15_R * 0xdb5ebd48fc0d4; + pol s9_R15 = s9_R14 + a15_R * 0xd1b77326dcb90; + pol s10_R15 = s10_R14 + a15_R * 0xbeb0ccc145421; + pol s11_R15 = s11_R14 + a15_R * 0xd10e5b22b11d1; + + // Calculate the 7th power of the 16th element + pol inputP16 = PARTIALROUND * (s0_R15 - poseidonM4) + poseidonM4; + pol constC_16 = PARTIALROUND * 0x389473bcdfca97a2 + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xdadf943b8d3e5a0d + POSEIDONP * 0x4ab94ee3e26596fe + POSEIDONAFTERPART * 0xd8af8654e9a2e659; + pol a16_2 = inputP16 * inputP16; + pol a16_4 = a16_2 * a16_2; + pol a16_6 = a16_4 * a16_2; + pol a16_R = a16_6 * inputP16 + constC_16; + + + pol s0_R16 = 0x19 * a16_R + 0xd8dddbdc5ce4ef45 * s1_R15 + 0xacfc51de8131458c * s2_R15 + 0x146bb3c0fe499ac0 * s3_R15 + 0x9e65309f15943903 * s4_R15 + 0x80d0ad980773aa70 * s5_R15 + 0xf97817d4ddbf0607 * s6_R15 + 0xe4626620a75ba276 * s7_R15 + 0xdfdc7fd6fc74f66 * s8_R15 + 0xf464864ad6f2bb93 * s9_R15 + 0x2d55e52a5d44414 * s10_R15 + 0xdd8de62487c40925 * s11_R15; + pol s1_R16 = s1_R15 + a16_R * 0xe24c99adad8; + pol s2_R16 = s2_R15 + a16_R * 0xcf389ed4bc8; + pol s3_R16 = s3_R15 + a16_R * 0xe580cbf6966; + pol s4_R16 = s4_R15 + a16_R * 0xcde5fd7e04f; + pol s5_R16 = s5_R15 + a16_R * 0xe63628041b3; + pol s6_R16 = s6_R15 + a16_R * 0xe7e81a87361; + pol s7_R16 = s7_R15 + a16_R * 0xdabe78f6d98; + pol s8_R16 = s8_R15 + a16_R * 0xefb14cac554; + pol s9_R16 = s9_R15 + a16_R * 0xe5574743b10; + pol s10_R16 = s10_R15 + a16_R * 0xd05709f42c1; + pol s11_R16 = s11_R15 + a16_R * 0xe4690c96af1; + + // Calculate the 7th power of the 17th element + pol inputP17 = PARTIALROUND * (s0_R16 - poseidonM5) + poseidonM5; + pol constC_17 = PARTIALROUND * 0xb1cb0b3abe9753ad + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0x6d15f3cb7a3520ba + POSEIDONP * 0xcee3abbb50d57b23 + POSEIDONAFTERPART * 0x8595bbd7f34c5e8a; + pol a17_2 = inputP17 * inputP17; + pol a17_4 = a17_2 * a17_2; + pol a17_6 = a17_4 * a17_2; + pol a17_R = a17_6 * inputP17 + constC_17; + + + pol s0_R17 = 0x19 * a17_R + 0xc15acf44759545a3 * s1_R16 + 0xcbfdcf39869719d4 * s2_R16 + 0x33f62042e2f80225 * s3_R16 + 0x2599c5ead81d8fa3 * s4_R16 + 0xb306cb6c1d7c8d0 * s5_R16 + 0x658c80d3df3729b1 * s6_R16 + 0xe8d1b2b21b41429c * s7_R16 + 0xa1b67f09d4b3ccb8 * s8_R16 + 0xe1adf8b84437180 * s9_R16 + 0xd593a5e584af47b * s10_R16 + 0xa023d94c56e151c7 * s11_R16; + pol s1_R17 = s1_R16 + a17_R * 0xf7157bc98; + pol s2_R17 = s2_R16 + a17_R * 0xe3006d948; + pol s3_R17 = s3_R16 + a17_R * 0xfa65811e6; + pol s4_R17 = s4_R16 + a17_R * 0xe0d127e2f; + pol s5_R17 = s5_R16 + a17_R * 0xfc18bfe53; + pol s6_R17 = s6_R16 + a17_R * 0xfd002d901; + pol s7_R17 = s7_R16 + a17_R * 0xeed6461d8; + pol s8_R17 = s8_R16 + a17_R * 0x1068562754; + pol s9_R17 = s9_R16 + a17_R * 0xfa0236f50; + pol s10_R17 = s10_R16 + a17_R * 0xe3af13ee1; + pol s11_R17 = s11_R16 + a17_R * 0xfa460f6d1; + + // Calculate the 7th power of the 18th element + pol inputP18 = PARTIALROUND * (s0_R17 - poseidonM6) + poseidonM6; + pol constC_18 = PARTIALROUND * 0x41afceccffdb18e6 + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xf07af62b134ef181 + POSEIDONP * 0xac91a7101a5ec55b + POSEIDONAFTERPART * 0x206ddbf781e47b2; + pol a18_2 = inputP18 * inputP18; + pol a18_4 = a18_2 * a18_2; + pol a18_6 = a18_4 * a18_2; + pol a18_R = a18_6 * inputP18 + constC_18; + + + pol s0_R18 = 0x19 * a18_R + 0x49026cc3a4afc5a6 * s1_R17 + 0xe06dff00ab25b91b * s2_R17 + 0xab38c561e8850ff * s3_R17 + 0x92c3c8275e105eeb * s4_R17 + 0xb65256e546889bd0 * s5_R17 + 0x3c0468236ea142f6 * s6_R17 + 0xee61766b889e18f2 * s7_R17 + 0xa206f41b12c30415 * s8_R17 + 0x2fe9d756c9f12d1 * s9_R17 + 0xe9633210630cbf12 * s10_R17 + 0x1ffea9fe85a0b0b1 * s11_R17; + pol s1_R18 = s1_R17 + a18_R * 0x11131738; + pol s2_R18 = s2_R17 + a18_R * 0xf56d588; + pol s3_R18 = s3_R17 + a18_R * 0x11050f86; + pol s4_R18 = s4_R17 + a18_R * 0xf848f4f; + pol s5_R18 = s5_R17 + a18_R * 0x111527d3; + pol s6_R18 = s6_R17 + a18_R * 0x114369a1; + pol s7_R18 = s7_R17 + a18_R * 0x106f2f38; + pol s8_R18 = s8_R17 + a18_R * 0x11e2ca94; + pol s9_R18 = s9_R17 + a18_R * 0x110a29f0; + pol s10_R18 = s10_R17 + a18_R * 0xfa9f5c1; + pol s11_R18 = s11_R17 + a18_R * 0x10f625d1; + + // Calculate the 7th power of the 19th element + pol inputP19 = PARTIALROUND * (s0_R18 - poseidonM7) + poseidonM7; + pol constC_19 = PARTIALROUND * 0x7bf841e237ccd6c9 + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0x568355076c6b0de6 + POSEIDONP * 0x9173aa8462280d2d + POSEIDONAFTERPART * 0xe101a767854a2f97; + pol a19_2 = inputP19 * inputP19; + pol a19_4 = a19_2 * a19_2; + pol a19_6 = a19_4 * a19_2; + pol a19_R = a19_6 * inputP19 + constC_19; + + + pol s0_R19 = 0x19 * a19_R + 0x81d1ae8cc50240f3 * s1_R18 + 0xf4c77a079a4607d7 * s2_R18 + 0xed446b2315e3efc1 * s3_R18 + 0xb0a6b70915178c3 * s4_R18 + 0xb11ff3e089f15d9a * s5_R18 + 0x1d4dba0b7ae9cc18 * s6_R18 + 0x65d74e2f43b48d05 * s7_R18 + 0xa2df8c6b8ae0804a * s8_R18 + 0xa4e6f0a8c33348a6 * s9_R18 + 0xc0a26efc7be5669b * s10_R18 + 0xa6b6582c547d0d60 * s11_R18; + pol s1_R19 = s1_R18 + a19_R * 0x11f718; + pol s2_R19 = s2_R18 + a19_R * 0x10b6c8; + pol s3_R19 = s3_R18 + a19_R * 0x134a96; + pol s4_R19 = s4_R18 + a19_R * 0x10cf7f; + pol s5_R19 = s5_R18 + a19_R * 0x124d03; + pol s6_R19 = s6_R18 + a19_R * 0x13f8a1; + pol s7_R19 = s7_R18 + a19_R * 0x117c58; + pol s8_R19 = s8_R18 + a19_R * 0x132c94; + pol s9_R19 = s9_R18 + a19_R * 0x134fc0; + pol s10_R19 = s10_R18 + a19_R * 0x10a091; + pol s11_R19 = s11_R18 + a19_R * 0x128961; + + // Calculate the 7th power of the 20th element + pol inputP20 = PARTIALROUND * (s0_R19 - poseidonM8) + poseidonM8; + pol constC_20 = PARTIALROUND * 0x6082a3f101fb888 + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0x31ca4bf93cab68b8 + POSEIDONP * 0xaec1ca46ccb95105 + POSEIDONAFTERPART * 0xf4d4f0a01072c996; + pol a20_2 = inputP20 * inputP20; + pol a20_4 = a20_2 * a20_2; + pol a20_6 = a20_4 * a20_2; + pol a20_R = a20_6 * inputP20 + constC_20; + + + pol s0_R20 = 0x19 * a20_R + 0x84afc741f1c13213 * s1_R19 + 0x2f8f43734fc906f3 * s2_R19 + 0xde682d72da0a02d9 * s3_R19 + 0xbb005236adb9ef2 * s4_R19 + 0x5bdf35c10a8b5624 * s5_R19 + 0x739a8a343950010 * s6_R19 + 0x52f515f44785cfbc * s7_R19 + 0xcbaf4e5d82856c60 * s8_R19 + 0xac9ea09074e3e150 * s9_R19 + 0x8f0fa011a2035fb0 * s10_R19 + 0x1a37905d8450904a * s11_R19; + pol s1_R20 = s1_R19 + a20_R * 0x1300; + pol s2_R20 = s2_R19 + a20_R * 0x1750; + pol s3_R20 = s3_R19 + a20_R * 0x114e; + pol s4_R20 = s4_R19 + a20_R * 0x131f; + pol s5_R20 = s5_R19 + a20_R * 0x167b; + pol s6_R20 = s6_R19 + a20_R * 0x1371; + pol s7_R20 = s7_R19 + a20_R * 0x1230; + pol s8_R20 = s8_R19 + a20_R * 0x182c; + pol s9_R20 = s9_R19 + a20_R * 0x1368; + pol s10_R20 = s10_R19 + a20_R * 0xf31; + pol s11_R20 = s11_R19 + a20_R * 0x15c9; + + // Calculate the 7th power of the 21th element + pol inputP21 = PARTIALROUND * (s0_R20 - poseidonM9) + poseidonM9; + pol constC_21 = PARTIALROUND * 0x8c1a39196f4163cc + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xfbad37a125735ba + POSEIDONP * 0x57b2f2845db61e4a + POSEIDONAFTERPART * 0x197aec2894aab642; + pol a21_2 = inputP21 * inputP21; + pol a21_4 = a21_2 * a21_2; + pol a21_6 = a21_4 * a21_2; + pol a21_R = a21_6 * inputP21 + constC_21; + + + PARTIALROUND * (a[0]' - (0x19 * a21_R + 0x3abeb80def61cc85 * s1_R20 + 0x9d19c9dd4eac4133 * s2_R20 + 0x75a652d9641a985 * s3_R20 + 0x9daf69ae1b67e667 * s4_R20 + 0x364f71da77920a18 * s5_R20 + 0x50bd769f745c95b1 * s6_R20 + 0xf223d1180dbbf3fc * s7_R20 + 0x2f885e584e04aa99 * s8_R20 + 0xb69a0fa70aea684a * s9_R20 + 0x9584acaa6e062a0 * s10_R20 + 0xbc051640145b19b * s11_R20)) = 0; + PARTIALROUND * (a[1]' - ( s1_R20 + a21_R * 0x14)) = 0; + PARTIALROUND * (a[2]' - ( s2_R20 + a21_R * 0x22)) = 0; + PARTIALROUND * (a[3]' - ( s3_R20 + a21_R * 0x12)) = 0; + PARTIALROUND * (a[4]' - ( s4_R20 + a21_R * 0x27)) = 0; + PARTIALROUND * (a[5]' - ( s5_R20 + a21_R * 0xd)) = 0; + PARTIALROUND * (a[6]' - ( s6_R20 + a21_R * 0xd)) = 0; + PARTIALROUND * (a[7]' - ( s7_R20 + a21_R * 0x1c)) = 0; + PARTIALROUND * (a[8]' - ( s8_R20 + a21_R * 0x2)) = 0; + PARTIALROUND * (a[9]' - ( s9_R20 + a21_R * 0x10)) = 0; + PARTIALROUND * (a[10]' - ( s10_R20 + a21_R * 0x29)) = 0; + PARTIALROUND * (a[11]' - ( s11_R20 + a21_R * 0xf)) = 0; + + pol constC_22 = POSEIDONAFTERPART * 0x8d0c3911220db49b + POSEIDONP * 0x95704158500c90c6 + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0x9d3a9caaf1ac9e0a; + pol a22_2 = poseidonM10 * poseidonM10; + pol a22_4 = a22_2 * a22_2; + pol a22_6 = a22_4 * a22_2; + pol a22_R = a22_6 * poseidonM10 + constC_22; + + + pol constC_23 = POSEIDONAFTERPART * 0xa62a8bad609227ca + POSEIDONP * 0x66e023b0e6c9df5f + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0x4f265810f020c095; + pol a23_2 = poseidonM11 * poseidonM11; + pol a23_4 = a23_2 * a23_2; + pol a23_6 = a23_4 * a23_2; + pol a23_R = a23_6 * poseidonM11 + constC_23; + + + POSEIDONP * (a[0]' - (0x19 * a12_R + 0xf * a13_R + 0x29 * a14_R + 0x10 * a15_R + 0x2 * a16_R + 0x1c * a17_R + 0xd * a18_R + 0xd * a19_R + 0x27 * a20_R + 0x12 * a21_R + 0x22 * a22_R + 0x14 * a23_R)) = 0; + POSEIDONP * (a[1]' - (0x78566230aa7cc5d0 * a12_R + 0x817bd8a7869ed1b5 * a13_R + 0xd267254bea1097f4 * a14_R + 0x60c33ebd1e023f0a * a15_R + 0xa89ef32ae1462322 * a16_R + 0x6250f5f176d483e7 * a17_R + 0xe16a6c1dee3ba347 * a18_R + 0xec9730136b7c2c05 * a19_R + 0x3cf7c3a39d94c236 * a20_R + 0xb4707207455f57e3 * a21_R + 0xaadb39e83e76a9e0 * a22_R + 0x32f8ae916e567d39 * a23_R)) = 0; + POSEIDONP * (a[2]' - (0xdbf23e50005e7f24 * a12_R + 0x819f2c14a8366b1f * a13_R + 0x2dc10fce3233f443 * a14_R + 0xdb6945a20d277091 * a15_R + 0x77c1a153e73659e8 * a16_R + 0xaad1255d46e78f07 * a17_R + 0x13d316e45539aef4 * a18_R + 0xe1ecc5c21eec0646 * a19_R + 0x9e62c7d7b000cb0b * a20_R + 0x8e1de42b665c6706 * a21_R + 0xcd9bf0bd292c5fda * a22_R + 0xaadb39e83e76a9e0 * a23_R)) = 0; + POSEIDONP * (a[3]' - (0xb4a02c5c826d523e * a12_R + 0x7a5cf5b7b922e946 * a13_R + 0xfa9db0de2d852e7a * a14_R + 0x383dd77e07998487 * a15_R + 0x2aec981be4b62ed5 * a16_R + 0x8a00c7c83c762584 * a17_R + 0x577e0472764f061d * a18_R + 0x956d3c8b5528e064 * a19_R + 0xe202be7ad7265af6 * a20_R + 0xee7b04568203481 * a21_R + 0x8e1de42b665c6706 * a22_R + 0xb4707207455f57e3 * a23_R)) = 0; + POSEIDONP * (a[4]' - (0x466d8f66a8f9fed5 * a12_R + 0x727eca45c8d7bb71 * a13_R + 0xde2a0516f8c9d943 * a14_R + 0xe04ea1957ad8305c * a15_R + 0xb70fb5f2b4f1f85f * a16_R + 0xc734f3829ed30b0c * a17_R + 0x226a4dcf5db3316d * a18_R + 0x6df1d31fa84398f4 * a19_R + 0x82178371fa5fff69 * a20_R + 0xe202be7ad7265af6 * a21_R + 0x9e62c7d7b000cb0b * a22_R + 0x3cf7c3a39d94c236 * a23_R)) = 0; + POSEIDONP * (a[5]' - (0x68da2264f65ec3e * a12_R + 0x605a82c52b5ad2f1 * a13_R + 0xe6fdf23648931b99 * a14_R + 0xd499fcbf63fbd266 * a15_R + 0x7c66d474cd2087cb * a16_R + 0xb1a0132288b1619b * a17_R + 0x3373035a3ca3dac6 * a18_R + 0xf4898a1a3554ee49 * a19_R + 0x6df1d31fa84398f4 * a20_R + 0x956d3c8b5528e064 * a21_R + 0xe1ecc5c21eec0646 * a22_R + 0xec9730136b7c2c05 * a23_R)) = 0; + POSEIDONP * (a[6]' - (0xb59f9ff0ac6d5d78 * a12_R + 0x59ccc4d5184bc93a * a13_R + 0x3743057c07a5dbfa * a14_R + 0x462269e4b04620a5 * a15_R + 0x39302966be7df654 * a16_R + 0x88685b4f0798dfd1 * a17_R + 0x441f3a3747b5adb7 * a18_R + 0x3373035a3ca3dac6 * a19_R + 0x226a4dcf5db3316d * a20_R + 0x577e0472764f061d * a21_R + 0x13d316e45539aef4 * a22_R + 0xe16a6c1dee3ba347 * a23_R)) = 0; + POSEIDONP * (a[7]' - (0xcfb03c902d447551 * a12_R + 0x66c8bab2096cfd38 * a13_R + 0xa6fdb8ebccc51667 * a14_R + 0x63c9679d8572a867 * a15_R + 0xb827c807875511c0 * a16_R + 0xfc02e869e21b72f8 * a17_R + 0x88685b4f0798dfd1 * a18_R + 0xb1a0132288b1619b * a19_R + 0xc734f3829ed30b0c * a20_R + 0x8a00c7c83c762584 * a21_R + 0xaad1255d46e78f07 * a22_R + 0x6250f5f176d483e7 * a23_R)) = 0; + POSEIDONP * (a[8]' - (0x2044ce14eaf8f5d9 * a12_R + 0xeb4c0ce280c3e935 * a13_R + 0x2c4916605e3dea58 * a14_R + 0x81c44e9699915693 * a15_R + 0xa4daffb3ffd0e78f * a16_R + 0xb827c807875511c0 * a17_R + 0x39302966be7df654 * a18_R + 0x7c66d474cd2087cb * a19_R + 0xb70fb5f2b4f1f85f * a20_R + 0x2aec981be4b62ed5 * a21_R + 0x77c1a153e73659e8 * a22_R + 0xa89ef32ae1462322 * a23_R)) = 0; + POSEIDONP * (a[9]' - (0xfb9373c8481e0f0d * a12_R + 0x17f9202c16676b2f * a13_R + 0xe95c10ae32e05085 * a14_R + 0x62ecbe05e02433fc * a15_R + 0x81c44e9699915693 * a16_R + 0x63c9679d8572a867 * a17_R + 0x462269e4b04620a5 * a18_R + 0xd499fcbf63fbd266 * a19_R + 0xe04ea1957ad8305c * a20_R + 0x383dd77e07998487 * a21_R + 0xdb6945a20d277091 * a22_R + 0x60c33ebd1e023f0a * a23_R)) = 0; + POSEIDONP * (a[10]' - (0x72af70cdcb99214f * a12_R + 0x9b6e5164ed35d878 * a13_R + 0x97f9b7d2cfc2ade5 * a14_R + 0xe95c10ae32e05085 * a15_R + 0x2c4916605e3dea58 * a16_R + 0xa6fdb8ebccc51667 * a17_R + 0x3743057c07a5dbfa * a18_R + 0xe6fdf23648931b99 * a19_R + 0xde2a0516f8c9d943 * a20_R + 0xfa9db0de2d852e7a * a21_R + 0x2dc10fce3233f443 * a22_R + 0xd267254bea1097f4 * a23_R)) = 0; + POSEIDONP * (a[11]' - (0xe3ef40eacc6ff78d * a12_R + 0x6fadc9347faeee81 * a13_R + 0x9b6e5164ed35d878 * a14_R + 0x17f9202c16676b2f * a15_R + 0xeb4c0ce280c3e935 * a16_R + 0x66c8bab2096cfd38 * a17_R + 0x59ccc4d5184bc93a * a18_R + 0x605a82c52b5ad2f1 * a19_R + 0x727eca45c8d7bb71 * a20_R + 0x7a5cf5b7b922e946 * a21_R + 0x819f2c14a8366b1f * a22_R + 0x817bd8a7869ed1b5 * a23_R)) = 0; + + POSEIDONM * (a[0]' - (0x19 * a12_R + 0xf * a13_R + 0x29 * a14_R + 0x10 * a15_R + 0x2 * a16_R + 0x1c * a17_R + 0xd * a18_R + 0xd * a19_R + 0x27 * a20_R + 0x12 * a21_R + 0x22 * a22_R + 0x14 * a23_R)) = 0; + POSEIDONM * (a[1]' - (0x14 * a12_R + 0x11 * a13_R + 0xf * a14_R + 0x29 * a15_R + 0x10 * a16_R + 0x2 * a17_R + 0x1c * a18_R + 0xd * a19_R + 0xd * a20_R + 0x27 * a21_R + 0x12 * a22_R + 0x22 * a23_R)) = 0; + POSEIDONM * (a[2]' - (0x22 * a12_R + 0x14 * a13_R + 0x11 * a14_R + 0xf * a15_R + 0x29 * a16_R + 0x10 * a17_R + 0x2 * a18_R + 0x1c * a19_R + 0xd * a20_R + 0xd * a21_R + 0x27 * a22_R + 0x12 * a23_R)) = 0; + POSEIDONM * (a[3]' - (0x12 * a12_R + 0x22 * a13_R + 0x14 * a14_R + 0x11 * a15_R + 0xf * a16_R + 0x29 * a17_R + 0x10 * a18_R + 0x2 * a19_R + 0x1c * a20_R + 0xd * a21_R + 0xd * a22_R + 0x27 * a23_R)) = 0; + POSEIDONM * (a[4]' - (0x27 * a12_R + 0x12 * a13_R + 0x22 * a14_R + 0x14 * a15_R + 0x11 * a16_R + 0xf * a17_R + 0x29 * a18_R + 0x10 * a19_R + 0x2 * a20_R + 0x1c * a21_R + 0xd * a22_R + 0xd * a23_R)) = 0; + POSEIDONM * (a[5]' - (0xd * a12_R + 0x27 * a13_R + 0x12 * a14_R + 0x22 * a15_R + 0x14 * a16_R + 0x11 * a17_R + 0xf * a18_R + 0x29 * a19_R + 0x10 * a20_R + 0x2 * a21_R + 0x1c * a22_R + 0xd * a23_R)) = 0; + POSEIDONM * (a[6]' - (0xd * a12_R + 0xd * a13_R + 0x27 * a14_R + 0x12 * a15_R + 0x22 * a16_R + 0x14 * a17_R + 0x11 * a18_R + 0xf * a19_R + 0x29 * a20_R + 0x10 * a21_R + 0x2 * a22_R + 0x1c * a23_R)) = 0; + POSEIDONM * (a[7]' - (0x1c * a12_R + 0xd * a13_R + 0xd * a14_R + 0x27 * a15_R + 0x12 * a16_R + 0x22 * a17_R + 0x14 * a18_R + 0x11 * a19_R + 0xf * a20_R + 0x29 * a21_R + 0x10 * a22_R + 0x2 * a23_R)) = 0; + POSEIDONM * (a[8]' - (0x2 * a12_R + 0x1c * a13_R + 0xd * a14_R + 0xd * a15_R + 0x27 * a16_R + 0x12 * a17_R + 0x22 * a18_R + 0x14 * a19_R + 0x11 * a20_R + 0xf * a21_R + 0x29 * a22_R + 0x10 * a23_R)) = 0; + POSEIDONM * (a[9]' - (0x10 * a12_R + 0x2 * a13_R + 0x1c * a14_R + 0xd * a15_R + 0xd * a16_R + 0x27 * a17_R + 0x12 * a18_R + 0x22 * a19_R + 0x14 * a20_R + 0x11 * a21_R + 0xf * a22_R + 0x29 * a23_R)) = 0; + POSEIDONM * (a[10]' - (0x29 * a12_R + 0x10 * a13_R + 0x2 * a14_R + 0x1c * a15_R + 0xd * a16_R + 0xd * a17_R + 0x27 * a18_R + 0x12 * a19_R + 0x22 * a20_R + 0x14 * a21_R + 0x11 * a22_R + 0xf * a23_R)) = 0; + POSEIDONM * (a[11]' - (0xf * a12_R + 0x29 * a13_R + 0x10 * a14_R + 0x2 * a15_R + 0x1c * a16_R + 0xd * a17_R + 0xd * a18_R + 0x27 * a19_R + 0x12 * a20_R + 0x22 * a21_R + 0x14 * a22_R + 0x11 * a23_R)) = 0; + + // CMUL GATE - Check that a * b in Fp³ using (X³ - X - 1) as a generator is performed correctly + // In this particular case, + // a = [a[0], a[1], a[2]] + // b = [a[3], a[4], a[5]] + // and this must be equal to [ a[6], a[7], a[8] ] + + // Since the modulo is known (X³ - X - 1) we can calculate the coefficients in general form by calculating + // (a0 + a1*x + a2*x²)*(b0 + b1*x + b2*x²) and then using long division to get the residue when dividing by the modulo + // We get the following result: (a0*b0 + a1*b2 + a2*b1) + (a0*b1 + a1*b0 + a1*b2 + a2*b1 + a2*b2)x + (a0*b2 + a2*b2 + a2*b0 + a1*b1)x² + // This result can be expressed using this intermediate polyonials A,B,C,D,E,F that have less than degree 2 + pol cA1 = (a[0] + a[1]) * (a[3] + a[4]); + pol cB1 = (a[0] + a[2]) * (a[3] + a[5]); + pol cC1 = (a[1] + a[2]) * (a[4] + a[5]); + pol cD1 = a[0]*a[3]; + pol cE1 = a[1]*a[4]; + pol cF1 = a[2]*a[5]; + + // Whenever CMUL = 1, check that the CMul result matches with the values stored in a[6], a[7] and a[8] respectively + CMUL * (a[6] - (cC1 + cD1 - cE1 - cF1)) = 0; + CMUL * (a[7] - (cA1 + cC1 - 2*cE1 - cD1)) = 0; + CMUL * (a[8] - (cB1 - cD1 + cE1)) = 0; + + // CMUL GATE - Check that a * b in Fp³ using (X³ - X - 1) as a generator is performed correctly + // In this particular case, + // a = [a[9], a[10], a[11]] + // b = [a[12], a[13], a[14]] + // and this must be equal to [ a[15], a[16], a[17] ] + + pol cA2 = (a[9] + a[10]) * (a[12] + a[13]); + pol cB2 = (a[9] + a[11]) * (a[12] + a[14]); + pol cC2 = (a[10] + a[11]) * (a[13] + a[14]); + pol cD2 = a[9]*a[12]; + pol cE2 = a[10]*a[13]; + pol cF2 = a[11]*a[14]; + + // Whenever CMUL = 1, check that the CMul result matches with the values stored in a[15], a[16] and a[17] respectively + CMUL * (a[15] - (cC2 + cD2 - cE2 - cF2)) = 0; + CMUL * (a[16] - (cA2 + cC2 - 2*cE2 - cD2)) = 0; + CMUL * (a[17] - (cB2 - cD2 + cE2)) = 0; + + // FFT4 + + pol g0 = C[0]*a[0] + C[1]*a[3] + C[2]*a[6] + C[3]*a[9] + C[6]*a[0] + C[7]*a[3]; + pol g3 = C[0]*a[0] - C[1]*a[3] + C[4]*a[6] - C[5]*a[9] + C[6]*a[0] - C[7]*a[3]; + pol g6 = C[0]*a[0] + C[1]*a[3] - C[2]*a[6] - C[3]*a[9] + C[6]*a[6] + C[8]*a[9]; + pol g9 = C[0]*a[0] - C[1]*a[3] - C[4]*a[6] + C[5]*a[9] + C[6]*a[6] - C[8]*a[9]; + + pol g1 = C[0]*a[1] + C[1]*a[4] + C[2]*a[7] + C[3]*a[10] + C[6]*a[1] + C[7]*a[4]; + pol g4 = C[0]*a[1] - C[1]*a[4] + C[4]*a[7] - C[5]*a[10] + C[6]*a[1] - C[7]*a[4]; + pol g7 = C[0]*a[1] + C[1]*a[4] - C[2]*a[7] - C[3]*a[10] + C[6]*a[7] + C[8]*a[10]; + pol g10 = C[0]*a[1] - C[1]*a[4] - C[4]*a[7] + C[5]*a[10] + C[6]*a[7] - C[8]*a[10]; + + pol g2 = C[0]*a[2] + C[1]*a[5] + C[2]*a[8] + C[3]*a[11] + C[6]*a[2] + C[7]*a[5]; + pol g5 = C[0]*a[2] - C[1]*a[5] + C[4]*a[8] - C[5]*a[11] + C[6]*a[2] - C[7]*a[5]; + pol g8 = C[0]*a[2] + C[1]*a[5] - C[2]*a[8] - C[3]*a[11] + C[6]*a[8] + C[8]*a[11]; + pol g11 = C[0]*a[2] - C[1]*a[5] - C[4]*a[8] + C[5]*a[11] + C[6]*a[8] - C[8]*a[11]; + + FFT4 * (a[0]' - g0) = 0; + FFT4 * (a[1]' - g1) = 0; + FFT4 * (a[2]' - g2) = 0; + FFT4 * (a[3]' - g3) = 0; + FFT4 * (a[4]' - g4) = 0; + FFT4 * (a[5]' - g5) = 0; + FFT4 * (a[6]' - g6) = 0; + FFT4 * (a[7]' - g7) = 0; + FFT4 * (a[8]' - g8) = 0; + FFT4 * (a[9]' - g9) = 0; + FFT4 * (a[10]' - g10) = 0; + FFT4 * (a[11]' - g11) = 0; + + // EVPOL4 - Check that the polynomial evaluation is valid + // Evaluate p(x) = d0*x⁴ + d1*x³ + d2*x²+ d3*x + d4 at point z = a[3]' + a[4]'x + a[5]'x² where + // d0 = a[0]' + a[1]' * x + a[2]' * x² + // d1 = a[9] + a[10] * x + a[11] * x² + // d2 = a[6] + a[7] * x + a[8] * x² + // d3 = a[3] + a[4] * x + a[5] * x² + // d4 = a[0] + a[1] * x + a[2] * x² + // The result must be equal to a[6]' + a[7]' * x + a[8]' * x² + // The evaluation is performed using the Horner's rule, which means that p(x) is rewritten as + // p(x) = (d0 * x + d1)*x + d2)*x + d3)*x + d4 + // Note: All operations are performed in Fp³ and so multiplications are performed using CMulAdd + + + // Calculate acc = d0 * x + d1 + pol A1 = (a[0]' + a[1]') * (a[3]' + a[4]'); + pol B1 = (a[0]' + a[2]') * (a[3]' + a[5]'); + pol C1 = (a[1]' + a[2]') * (a[4]' + a[5]'); + pol D1 = a[0]' * a[3]'; + pol E1 = a[1]' * a[4]'; + pol F1 = a[2]' * a[5]'; + pol acc1_0 = C1+ D1 - E1 - F1 + a[9]; + pol acc1_1 = A1+ C1- 2*E1 - D1 + a[10]; + pol acc1_2 = B1- D1 + E1 + a[11]; + + // Calculate acc2 = acc * x + d2 + pol A2 = (acc1_0 + acc1_1) * (a[3]' + a[4]'); + pol B2 = (acc1_0 + acc1_2) * (a[3]' + a[5]'); + pol C2 = (acc1_1 + acc1_2) * (a[4]' + a[5]'); + pol D2 = acc1_0 * a[3]'; + pol E2 = acc1_1 * a[4]'; + pol F2 = acc1_2 * a[5]'; + pol acc2_0 = C2+ D2 - E2 - F2 + a[6]; + pol acc2_1 = A2+ C2- 2*E2 - D2 + a[7]; + pol acc2_2 = B2- D2 + E2 + a[8]; + + // Calculate acc3 = acc2 * x + d3 + pol A3 = (acc2_0 + acc2_1) * (a[3]' + a[4]'); + pol B3 = (acc2_0 + acc2_2) * (a[3]' + a[5]'); + pol C3 = (acc2_1 + acc2_2) * (a[4]' + a[5]'); + pol D3 = acc2_0 * a[3]'; + pol E3 = acc2_1 * a[4]'; + pol F3 = acc2_2 * a[5]'; + pol acc3_0 = C3+ D3 - E3 - F3 + a[3]; + pol acc3_1 = A3+ C3- 2*E3 - D3 + a[4]; + pol acc3_2 = B3- D3 + E3 + a[5]; + + // Calculate p = acc4 * x + d4 + pol A4 = (acc3_0 + acc3_1) * (a[3]' + a[4]'); + pol B4 = (acc3_0 + acc3_2) * (a[3]' + a[5]'); + pol C4 = (acc3_1 + acc3_2) * (a[4]' + a[5]'); + pol D4 = acc3_0 * a[3]'; + pol E4 = acc3_1 * a[4]'; + pol F4 = acc3_2 * a[5]'; + pol acc4_0 = C4+ D4 - E4 - F4 + a[0]; + pol acc4_1 = A4+ C4- 2*E4 - D4 + a[1]; + pol acc4_2 = B4- D4 + E4 + a[2]; + + + // Whenever EVPOL4 = 1, check that the evaluation result matches with the values stored in a[6]', a[7]' and a[8]' respectively + EVPOL4 * (a[6]' - acc4_0) = 0; + EVPOL4 * (a[7]' - acc4_1) = 0; + EVPOL4 * (a[8]' - acc4_2) = 0; + + // TREESELECTOR4 GATE - Check that given 4 values and a key, checks that the output is correct + // The tree is created as follows: if key = 0, even values are pushed up the tree, if the key = 1 the odd ones are pushed. + // Therefore, we need to check that + // key == [0,0] -> [value1, value2, value3, value4] -> [value1, value3] -> [value1] + // key == [1,0] -> [value1, value2, value3, value4] -> [value2, value4] -> [value2] + // key == [0,1] -> [value1, value2, value3, value4] -> [value1, value3] -> [value3] + // key == [1,1] -> [value1, value2, value3, value4] -> [value2, value4] -> [value4] + + // The values are stored from a[0], a[1], a[2] // a[3], a[4], a[5] // a[6], a[7], a[8] // a[9], a[10], a[11] + // The key is stored in [a[12], a[13]] + // The output is stored in [a[14], a[15], a[16]] + + pol checkBinaryKey1 = a[12]*(1 - a[12]); + pol checkBinaryKey2 = a[13]*(1 - a[13]); + TREESELECTOR4 * checkBinaryKey1 = 0; + TREESELECTOR4 * checkBinaryKey2 = 0; + + // keys1 will only be 1 if both a[12], a[13] are zero + pol keys1 = (1 - a[12])*(1 - a[13]); + pol treeSelect1_1 = keys1 * (a[0] - a[14]); + pol treeSelect1_2 = keys1 * (a[1] - a[15]); + pol treeSelect1_3 = keys1 * (a[2] - a[16]); + TREESELECTOR4 * treeSelect1_1 = 0; + TREESELECTOR4 * treeSelect1_2 = 0; + TREESELECTOR4 * treeSelect1_3 = 0; + + // keys2 will only be 1 if a[12] equals 1 and a[13] equals 0 + pol keys2 = (a[12])*(1 - a[13]); + pol treeSelect2_1 = keys2 * (a[3] - a[14]); + pol treeSelect2_2 = keys2 * (a[4] - a[15]); + pol treeSelect2_3 = keys2 * (a[5] - a[16]); + TREESELECTOR4 * treeSelect2_1 = 0; + TREESELECTOR4 * treeSelect2_2 = 0; + TREESELECTOR4 * treeSelect2_3 = 0; + + // keys3 will only be 1 if a[12] equals 0 and a[13] equals 1 + pol keys3 = (1 - a[12])*(a[13]); + pol treeSelect3_1 = keys3 * (a[6] - a[14]); + pol treeSelect3_2 = keys3 * (a[7] - a[15]); + pol treeSelect3_3 = keys3 * (a[8] - a[16]); + TREESELECTOR4 * treeSelect3_1 = 0; + TREESELECTOR4 * treeSelect3_2 = 0; + TREESELECTOR4 * treeSelect3_3 = 0; + + // keys4 will only be 1 if a[12] and a[13] equals 1 + pol keys4 = (a[12])*(a[13]); + pol treeSelect4_1 = keys4 * (a[9] - a[14]); + pol treeSelect4_2 = keys4 * (a[10] - a[15]); + pol treeSelect4_3 = keys4 * (a[11] - a[16]); + TREESELECTOR4 * treeSelect4_1 = 0; + TREESELECTOR4 * treeSelect4_2 = 0; + TREESELECTOR4 * treeSelect4_3 = 0; + + + // Check connection equations of Plonk + { a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15],a[16],a[17] } connect { S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[8],S[9],S[10],S[11],S[12],S[13],S[14],S[15],S[16],S[17] } \ No newline at end of file diff --git a/test/state_machines/sm_fibonacci/fibonacci.c12.pil b/test/state_machines/sm_fibonacci/fibonacci.c12.pil new file mode 100644 index 00000000..35db5d57 --- /dev/null +++ b/test/state_machines/sm_fibonacci/fibonacci.c12.pil @@ -0,0 +1,783 @@ +constant %N = 2**13; + +// THIS FILE IS A TEST EXAMPLE! IT MAY NOT BE THE LAST VERSION! + +// Global state machine +// It is used to store various polynomials representing small lookup tables +namespace Global(%N); + pol constant L1; + +namespace Compressor(%N); + pol constant S[12]; + pol constant C[12]; + pol constant POSEIDONM; + pol constant POSEIDONCUSTFIRST; + pol constant POSEIDONP; + pol constant POSEIDONFIRST; + pol constant PARTIALROUND; + pol constant PARTIALROUND2; + pol constant GATE; + pol constant CMUL; + pol constant EVPOL4; + pol constant FFT4; + pol constant TREESELECTOR4; + pol commit a[12]; + + public pub0 = a[0](0); + public pub1 = a[1](0); + public pub2 = a[2](0); + Global.L1 * (a[0] - :pub0) = 0; + Global.L1 * (a[1] - :pub1) = 0; + Global.L1 * (a[2] - :pub2) = 0; + + // Normal plonk gates + + // C[0] -> Qm1 + // C[1] -> Ql1 + // C[2] -> Qr1 + // C[3] -> Qo1 + // C[4] -> Qc1 + + // C[6] -> Qm2 + // C[7] -> Ql2 + // C[8] -> Qr2 + // C[9] -> Qo2 + // C[10]-> Qc2 + + + pol a01 = a[0]*a[1]; + pol g012 = C[0]*a01 + C[1]*a[0] + C[2]*a[1] + C[3]*a[2] + C[4]; + g012*GATE = 0; + + pol a34 = a[3]*a[4]; + pol g345 = C[0]*a34 + C[1]*a[3] + C[2]*a[4] + C[3]*a[5] + C[4]; + g345*GATE = 0; + + pol a67 = a[6]*a[7]; + pol g678 = C[6]*a67 + C[7]*a[6] + C[8]*a[7] + C[9]*a[8] + C[10]; + g678*GATE = 0; + + pol a910 = a[9]*a[10]; + pol g91011 = C[6]*a910 + C[7]*a[9] + C[8]*a[10] + C[9]*a[11] + C[10]; + g91011*GATE = 0; + + // POSEIDON GATE - Check that a GL Poseidon round implemented with Neptune optimization is valid + + // Each Poseidon hash is verified in 11 rows. Inputs -> Round 1 -> Round 2 -> Round 3 -> Round 4 + // -> Round 15 -> Round 26 -> Round 27 -> Round 28 -> Round 29 -> Output. + // At each row we verify one full rounds, and all the partial rows are verified in two rows (in the + // first one we check the first 11 rounds and in the second one the other 11) + + // There are two diferent Poseidon custom gates: Poseidon and CustPoseidon. The first one is a regular hash of + // three inputs, while the second one hashes two inputs (the third one is zero). However, in CustPoseidon custom + // gate the two values to hash (value and sibling) are sent unordered and the key specifying which element is the + // first one and which is the second one is also provided. + + // Order the each of the GL Poseidon inputs according to the key, which is stored in a[8] + + pol custPoseidonInput0 = a[8] * (a[0] - a[4]) + a[4]; + pol custPoseidonInput1 = a[8] * (a[1] - a[5]) + a[5]; + pol custPoseidonInput2 = a[8] * (a[2] - a[6]) + a[6]; + pol custPoseidonInput3 = a[8] * (a[3] - a[7]) + a[7]; + pol custPoseidonInput4 = a[8] * (a[4] - a[0]) + a[0]; + pol custPoseidonInput5 = a[8] * (a[5] - a[1]) + a[1]; + pol custPoseidonInput6 = a[8] * (a[6] - a[2]) + a[2]; + pol custPoseidonInput7 = a[8] * (a[7] - a[3]) + a[3]; + + pol checkBinary = a[8] * (a[8] - 1); + POSEIDONCUSTFIRST * checkBinary = 0; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp0 = POSEIDONCUSTFIRST * (custPoseidonInput0 - a[0]) + a[0] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xb585f766f2144405; + // Calculate the 7th power of the 0th element + pol a0_2 = inp0 * inp0; + pol a0_4 = a0_2 * a0_2; + pol a0_6 = a0_4 * a0_2; + pol a0_R = a0_6 * inp0 + C[0]; + + + // Partial round 0 + pol s0_R0 = 0x19 * a0_R + 0x3d999c961b7c63b0 * a[1] + 0x814e82efcd172529 * a[2] + 0x2421e5d236704588 * a[3] + 0x887af7d4dd482328 * a[4] + 0xa5e9c291f6119b27 * a[5] + 0xbdc52b2676a4b4aa * a[6] + 0x64832009d29bcf57 * a[7] + 0x9c4155174a552cc * a[8] + 0x463f9ee03d290810 * a[9] + 0xc810936e64982542 * a[10] + 0x43b1c289f7bc3ac * a[11]; + pol s1_R0 = a[1] + a0_R * 0x94877900674181c3; + pol s2_R0 = a[2] + a0_R * 0xc6c67cc37a2a2bbd; + pol s3_R0 = a[3] + a0_R * 0xd667c2055387940f; + pol s4_R0 = a[4] + a0_R * 0xba63a63e94b5ff0; + pol s5_R0 = a[5] + a0_R * 0x99460cc41b8f079f; + pol s6_R0 = a[6] + a0_R * 0x7ff02375ed524bb3; + pol s7_R0 = a[7] + a0_R * 0xea0870b47a8caf0e; + pol s8_R0 = a[8] + a0_R * 0xabcad82633b7bc9d; + pol s9_R0 = a[9] + a0_R * 0x3b8d135261052241; + pol s10_R0 = a[10] + a0_R * 0xfb4515f5e5b0d539; + pol s11_R0 = a[11] + a0_R * 0x3ee8011c2b37f77c; + + + + // Partial round 11 + pol s0_R11 = 0x19 * a0_R + 0x16b9774801ac44a0 * a[1] + 0x3cb8411e786d3c8e * a[2] + 0xa86e9cf505072491 * a[3] + 0x178928152e109ae * a[4] + 0x5317b905a6e1ab7b * a[5] + 0xda20b3be7f53d59f * a[6] + 0xcb97dedecebee9ad * a[7] + 0x4bd545218c59f58d * a[8] + 0x77dc8d856c05a44a * a[9] + 0x87948589e4f243fd * a[10] + 0x7e5217af969952c2 * a[11]; + pol s1_R11 = a[1] + a0_R * 0x84d1ecc4d53d2ff1; + pol s2_R11 = a[2] + a0_R * 0xd8af8b9ceb4e11b6; + pol s3_R11 = a[3] + a0_R * 0x335856bb527b52f4; + pol s4_R11 = a[4] + a0_R * 0xc756f17fb59be595; + pol s5_R11 = a[5] + a0_R * 0xc0654e4ea5553a78; + pol s6_R11 = a[6] + a0_R * 0x9e9a46b61f2ea942; + pol s7_R11 = a[7] + a0_R * 0x14fc8b5b3b809127; + pol s8_R11 = a[8] + a0_R * 0xd7009f0f103be413; + pol s9_R11 = a[9] + a0_R * 0x3e0ee7b7a9fb4601; + pol s10_R11 = a[10] + a0_R * 0xa74e888922085ed7; + pol s11_R11 = a[11] + a0_R * 0xe80a7cde3d4ac526; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp1 = POSEIDONCUSTFIRST * (custPoseidonInput1 - a[1]) + a[1] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0x7746a55f43921ad7; + // Calculate the 7th power of the 1th element + pol inpP1 = PARTIALROUND * s0_R0 + PARTIALROUND2 * s0_R11 + (POSEIDONM + POSEIDONP) * inp1; + pol a1_2 = inpP1 * inpP1; + pol a1_4 = a1_2 * a1_2; + pol a1_6 = a1_4 * a1_2; + pol a1_R = a1_6 * inpP1 + C[1]; + + + // Partial round 1 + pol s0_R1 = 0x19 * a1_R + 0x673655aae8be5a8b * s1_R0 + 0xd510fe714f39fa10 * s2_R0 + 0x2c68a099b51c9e73 * s3_R0 + 0xa667bfa9aa96999d * s4_R0 + 0x4d67e72f063e2108 * s5_R0 + 0xf84dde3e6acda179 * s6_R0 + 0x40f9cc8c08f80981 * s7_R0 + 0x5ead032050097142 * s8_R0 + 0x6591b02092d671bb * s9_R0 + 0xe18c71963dd1b7 * s10_R0 + 0x8a21bcd24a14218a * s11_R0; + pol s1_R1 = s1_R0 + a1_R * 0xadef3740e71c726; + pol s2_R1 = s2_R0 + a1_R * 0xa37bf67c6f986559; + pol s3_R1 = s3_R0 + a1_R * 0xc6b16f7ed4fa1b00; + pol s4_R1 = s4_R0 + a1_R * 0x6a065da88d8bfc3c; + pol s5_R1 = s5_R0 + a1_R * 0x4cabc0916844b46f; + pol s6_R1 = s6_R0 + a1_R * 0x407faac0f02e78d1; + pol s7_R1 = s7_R0 + a1_R * 0x7a786d9cf0852cf; + pol s8_R1 = s8_R0 + a1_R * 0x42433fb6949a629a; + pol s9_R1 = s9_R0 + a1_R * 0x891682a147ce43b0; + pol s10_R1 = s10_R0 + a1_R * 0x26cfd58e7b003b55; + pol s11_R1 = s11_R0 + a1_R * 0x2bbf0ed7b657acb3; + + + + // Partial round 12 + pol s0_R12 = 0x19 * a1_R + 0xbc58987d06a84e4d * s1_R11 + 0xb5d420244c9cae3 * s2_R11 + 0xa3c4711b938c02c0 * s3_R11 + 0x3aace640a3e03990 * s4_R11 + 0x865a0f3249aacd8a * s5_R11 + 0x8d00b2a7dbed06c7 * s6_R11 + 0x6eacb905beb7e2f8 * s7_R11 + 0x45322b216ec3ec7 * s8_R11 + 0xeb9de00d594828e6 * s9_R11 + 0x88c5f20df9e5c26 * s10_R11 + 0xf555f4112b19781f * s11_R11; + pol s1_R12 = s1_R11 + a1_R * 0x238aa6daa612186d; + pol s2_R12 = s2_R11 + a1_R * 0x9137a5c630bad4b4; + pol s3_R12 = s3_R11 + a1_R * 0xc7db3817870c5eda; + pol s4_R12 = s4_R11 + a1_R * 0x217e4f04e5718dc9; + pol s5_R12 = s5_R11 + a1_R * 0xcae814e2817bd99d; + pol s6_R12 = s6_R11 + a1_R * 0xe3292e7ab770a8ba; + pol s7_R12 = s7_R11 + a1_R * 0x7bb36ef70b6b9482; + pol s8_R12 = s8_R11 + a1_R * 0x3c7835fb85bca2d3; + pol s9_R12 = s9_R11 + a1_R * 0xfe2cdf8ee3c25e86; + pol s10_R12 = s10_R11 + a1_R * 0x61b3915ad7274b20; + pol s11_R12 = s11_R11 + a1_R * 0xeab75ca7c918e4ef; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp2 = POSEIDONCUSTFIRST * (custPoseidonInput2 - a[2]) + a[2] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xb2fb0d31cee799b4; + // Calculate the 7th power of the 2th element + pol inpP2 = PARTIALROUND * s0_R1 + PARTIALROUND2 * s0_R12 + (POSEIDONM + POSEIDONP) * inp2; + pol a2_2 = inpP2 * inpP2; + pol a2_4 = a2_2 * a2_2; + pol a2_6 = a2_4 * a2_2; + pol a2_R = a2_6 * inpP2 + C[2]; + + + // Partial round 2 + pol s0_R2 = 0x19 * a2_R + 0x202800f4addbdc87 * s1_R1 + 0xe4b5bdb1cc3504ff * s2_R1 + 0xbe32b32a825596e7 * s3_R1 + 0x8e0f68c5dc223b9a * s4_R1 + 0x58022d9e1c256ce3 * s5_R1 + 0x584d29227aa073ac * s6_R1 + 0x8b9352ad04bef9e7 * s7_R1 + 0xaead42a3f445ecbf * s8_R1 + 0x3c667a1d833a3cca * s9_R1 + 0xda6f61838efa1ffe * s10_R1 + 0xe8f749470bd7c446 * s11_R1; + pol s1_R2 = s1_R1 + a2_R * 0x481ac7746b159c67; + pol s2_R2 = s2_R1 + a2_R * 0xe367de32f108e278; + pol s3_R2 = s3_R1 + a2_R * 0x73f260087ad28bec; + pol s4_R2 = s4_R1 + a2_R * 0x5cfc82216bc1bdca; + pol s5_R2 = s5_R1 + a2_R * 0xcaccc870a2663a0e; + pol s6_R2 = s6_R1 + a2_R * 0xdb69cd7b4298c45d; + pol s7_R2 = s7_R1 + a2_R * 0x7bc9e0c57243e62d; + pol s8_R2 = s8_R1 + a2_R * 0x3cc51c5d368693ae; + pol s9_R2 = s9_R1 + a2_R * 0x366b4e8cc068895b; + pol s10_R2 = s10_R1 + a2_R * 0x2bd18715cdabbca4; + pol s11_R2 = s11_R1 + a2_R * 0xa752061c4f33b8cf; + + + + // Partial round 13 + pol s0_R13 = 0x19 * a2_R + 0xa8cedbff1813d3a7 * s1_R12 + 0x50dcaee0fd27d164 * s2_R12 + 0xf1cb02417e23bd82 * s3_R12 + 0xfaf322786e2abe8b * s4_R12 + 0x937a4315beb5d9b6 * s5_R12 + 0x1b18992921a11d85 * s6_R12 + 0x7d66c4368b3c497b * s7_R12 + 0xe7946317a6b4e99 * s8_R12 + 0xbe4430134182978b * s9_R12 + 0x3771e82493ab262d * s10_R12 + 0xa671690d8095ce82 * s11_R12; + pol s1_R13 = s1_R12 + a2_R * 0xd6e15ffc055e154e; + pol s2_R13 = s2_R12 + a2_R * 0xec67881f381a32bf; + pol s3_R13 = s3_R12 + a2_R * 0xfbb1196092bf409c; + pol s4_R13 = s4_R12 + a2_R * 0xdc9d2e07830ba226; + pol s5_R13 = s5_R12 + a2_R * 0x698ef3245ff7988; + pol s6_R13 = s6_R12 + a2_R * 0x194fae2974f8b576; + pol s7_R13 = s7_R12 + a2_R * 0x7a5d9bea6ca4910e; + pol s8_R13 = s8_R12 + a2_R * 0x7aebfea95ccdd1c9; + pol s9_R13 = s9_R12 + a2_R * 0xf9bd38a67d5f0e86; + pol s10_R13 = s10_R12 + a2_R * 0xfa65539de65492d8; + pol s11_R13 = s11_R12 + a2_R * 0xf0dfcbe7653ff787; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp3 = POSEIDONCUSTFIRST * (custPoseidonInput3 - a[3]) + a[3] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xf6760a4803427d7; + // Calculate the 7th power of the 3th element + pol inpP3 = PARTIALROUND * s0_R2 + PARTIALROUND2 * s0_R13 + (POSEIDONM + POSEIDONP) * inp3; + pol a3_2 = inpP3 * inpP3; + pol a3_4 = a3_2 * a3_2; + pol a3_6 = a3_4 * a3_2; + pol a3_R = a3_6 * inpP3 + C[3]; + + + // Partial round 3 + pol s0_R3 = 0x19 * a3_R + 0xc5b85bab9e5b3869 * s1_R2 + 0x45245258aec51cf7 * s2_R2 + 0x16e6b8e68b931830 * s3_R2 + 0xe2ae0f051418112c * s4_R2 + 0x470e26a0093a65b * s5_R2 + 0x6bef71973a8146ed * s6_R2 + 0x119265be51812daf * s7_R2 + 0xb0be7356254bea2e * s8_R2 + 0x8584defff7589bd7 * s9_R2 + 0x3c5fe4aeb1fb52ba * s10_R2 + 0x9e7cd88acf543a5e * s11_R2; + pol s1_R3 = s1_R2 + a3_R * 0xb22d2432b72d5098; + pol s2_R3 = s2_R2 + a3_R * 0x9e18a487f44d2fe4; + pol s3_R3 = s3_R2 + a3_R * 0x4b39e14ce22abd3c; + pol s4_R3 = s4_R2 + a3_R * 0x9e77fde2eb315e0d; + pol s5_R3 = s5_R2 + a3_R * 0xca5e0385fe67014d; + pol s6_R3 = s6_R2 + a3_R * 0xc2cb99bf1b6bddb; + pol s7_R3 = s7_R2 + a3_R * 0x99ec1cd2a4460bfe; + pol s8_R3 = s8_R2 + a3_R * 0x8577a815a2ff843f; + pol s9_R3 = s9_R2 + a3_R * 0x7d80a6b4fd6518a5; + pol s10_R3 = s10_R2 + a3_R * 0xeb6c67123eab62cb; + pol s11_R3 = s11_R2 + a3_R * 0x8f7851650eca21a5; + + + + // Partial round 14 + pol s0_R14 = 0x19 * a3_R + 0xb035585f6e929d9d * s1_R13 + 0xba1579c7e219b954 * s2_R13 + 0xcb201cf846db4ba3 * s3_R13 + 0x287bf9177372cf45 * s4_R13 + 0xa350e4f61147d0a6 * s5_R13 + 0xd5d0ecfb50bcff99 * s6_R13 + 0x2e166aa6c776ed21 * s7_R13 + 0xe1e66c991990e282 * s8_R13 + 0x662b329b01e7bb38 * s9_R13 + 0x8aa674b36144d9a9 * s10_R13 + 0xcbabf78f97f95e65 * s11_R13; + pol s1_R14 = s1_R13 + a3_R * 0xbd87ad390420258; + pol s2_R14 = s2_R13 + a3_R * 0xad8617bca9e33c8; + pol s3_R14 = s3_R13 + a3_R * 0xc00ad377a1e2666; + pol s4_R14 = s4_R13 + a3_R * 0xac6fc58b3f0518f; + pol s5_R14 = s5_R13 + a3_R * 0xc0cc8a892cc4173; + pol s6_R14 = s6_R13 + a3_R * 0xc210accb117bc21; + pol s7_R14 = s7_R13 + a3_R * 0xb73630dbb46ca18; + pol s8_R14 = s8_R13 + a3_R * 0xc8be4920cbd4a54; + pol s9_R14 = s9_R13 + a3_R * 0xbfe877a21be1690; + pol s10_R14 = s10_R13 + a3_R * 0xae790559b0ded81; + pol s11_R14 = s11_R13 + a3_R * 0xbf50db2f8d6ce31; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp4 = POSEIDONCUSTFIRST * (custPoseidonInput4 - a[4]) + a[4] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xe10d666650f4e012; + // Calculate the 7th power of the 4th element + pol inpP4 = PARTIALROUND * s0_R3 + PARTIALROUND2 * s0_R14 + (POSEIDONM + POSEIDONP) * inp4; + pol a4_2 = inpP4 * inpP4; + pol a4_4 = a4_2 * a4_2; + pol a4_6 = a4_4 * a4_2; + pol a4_R = a4_6 * inpP4 + C[4]; + + + // Partial round 4 + pol s0_R4 = 0x19 * a4_R + 0x179be4bba87f0a8c * s1_R3 + 0xacf63d95d8887355 * s2_R3 + 0x6696670196b0074f * s3_R3 + 0xd99ddf1fe75085f9 * s4_R3 + 0xc2597881fef0283b * s5_R3 + 0xcf48395ee6c54f14 * s6_R3 + 0x15226a8e4cd8d3b6 * s7_R3 + 0xc053297389af5d3b * s8_R3 + 0x2c08893f0d1580e2 * s9_R3 + 0xed3cbcff6fcc5ba * s10_R3 + 0xc82f510ecf81f6d0 * s11_R3; + pol s1_R4 = s1_R3 + a4_R * 0x11ba9a1b81718c2a; + pol s2_R4 = s2_R3 + a4_R * 0x9f7d798a3323410c; + pol s3_R4 = s3_R3 + a4_R * 0xa821855c8c1cf5e5; + pol s4_R4 = s4_R3 + a4_R * 0x535e8d6fac0031b2; + pol s5_R4 = s5_R3 + a4_R * 0x404e7c751b634320; + pol s6_R4 = s6_R3 + a4_R * 0xa729353f6e55d354; + pol s7_R4 = s7_R3 + a4_R * 0x4db97d92e58bb831; + pol s8_R4 = s8_R3 + a4_R * 0xb53926c27897bf7d; + pol s9_R4 = s9_R3 + a4_R * 0x965040d52fe115c5; + pol s10_R4 = s10_R3 + a4_R * 0x9565fa41ebd31fd7; + pol s11_R4 = s11_R3 + a4_R * 0xaae4438c877ea8f4; + + + + // Partial round 15 + pol s0_R15 = 0x19 * a4_R + 0xeec24b15a06b53fe * s1_R14 + 0xc8a7aa07c5633533 * s2_R14 + 0xefe9c6fa4311ad51 * s3_R14 + 0xb9173f13977109a1 * s4_R14 + 0x69ce43c9cc94aedc * s5_R14 + 0xecf623c9cd118815 * s6_R14 + 0x28625def198c33c7 * s7_R14 + 0xccfc5f7de5c3636a * s8_R14 + 0xf5e6c40f1621c299 * s9_R14 + 0xcec0e58c34cb64b1 * s10_R14 + 0xa868ea113387939f * s11_R14; + pol s1_R15 = s1_R14 + a4_R * 0xcf29427ff7c58; + pol s2_R15 = s2_R14 + a4_R * 0xbd9b3cf49eec8; + pol s3_R15 = s3_R14 + a4_R * 0xd1dc8aa81fb26; + pol s4_R15 = s4_R14 + a4_R * 0xbc792d5c394ef; + pol s5_R15 = s5_R14 + a4_R * 0xd2ae0b2266453; + pol s6_R15 = s6_R14 + a4_R * 0xd413f12c496c1; + pol s7_R15 = s7_R14 + a4_R * 0xc84128cfed618; + pol s8_R15 = s8_R14 + a4_R * 0xdb5ebd48fc0d4; + pol s9_R15 = s9_R14 + a4_R * 0xd1b77326dcb90; + pol s10_R15 = s10_R14 + a4_R * 0xbeb0ccc145421; + pol s11_R15 = s11_R14 + a4_R * 0xd10e5b22b11d1; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp5 = POSEIDONCUSTFIRST * (custPoseidonInput5 - a[5]) + a[5] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0x8cae14cb07d09bf1; + // Calculate the 7th power of the 5th element + pol inpP5 = PARTIALROUND * s0_R4 + PARTIALROUND2 * s0_R15 + (POSEIDONM + POSEIDONP) * inp5; + pol a5_2 = inpP5 * inpP5; + pol a5_4 = a5_2 * a5_2; + pol a5_6 = a5_4 * a5_2; + pol a5_R = a5_6 * inpP5 + C[5]; + + + // Partial round 5 + pol s0_R5 = 0x19 * a5_R + 0x94b06183acb715cc * s1_R4 + 0x500392ed0d431137 * s2_R4 + 0x861cc95ad5c86323 * s3_R4 + 0x5830a443f86c4ac * s4_R4 + 0x3b68225874a20a7c * s5_R4 + 0x10b3309838e236fb * s6_R4 + 0x9b77fc8bcd559e2c * s7_R4 + 0xbdecf5e0cb9cb213 * s8_R4 + 0x30276f1221ace5fa * s9_R4 + 0x7935dd342764a144 * s10_R4 + 0xeac6db520bb03708 * s11_R4; + pol s1_R5 = s1_R4 + a5_R * 0x37f4e36af6073c6e; + pol s2_R5 = s2_R4 + a5_R * 0x4edc0918210800e9; + pol s3_R5 = s3_R4 + a5_R * 0xc44998e99eae4188; + pol s4_R5 = s4_R4 + a5_R * 0x9f4310d05d068338; + pol s5_R5 = s5_R4 + a5_R * 0x9ec7fe4350680f29; + pol s6_R5 = s6_R4 + a5_R * 0xc5b2c1fdc0b50874; + pol s7_R5 = s7_R4 + a5_R * 0xa01920c5ef8b2ebe; + pol s8_R5 = s8_R4 + a5_R * 0x59fa6f8bd91d58ba; + pol s9_R5 = s9_R4 + a5_R * 0x8bfc9eb89b515a82; + pol s10_R5 = s10_R4 + a5_R * 0xbe86a7a2555ae775; + pol s11_R5 = s11_R4 + a5_R * 0xcbb8bbaa3810babf; + + + + // Partial round 16 + pol s0_R16 = 0x19 * a5_R + 0xd8dddbdc5ce4ef45 * s1_R15 + 0xacfc51de8131458c * s2_R15 + 0x146bb3c0fe499ac0 * s3_R15 + 0x9e65309f15943903 * s4_R15 + 0x80d0ad980773aa70 * s5_R15 + 0xf97817d4ddbf0607 * s6_R15 + 0xe4626620a75ba276 * s7_R15 + 0xdfdc7fd6fc74f66 * s8_R15 + 0xf464864ad6f2bb93 * s9_R15 + 0x2d55e52a5d44414 * s10_R15 + 0xdd8de62487c40925 * s11_R15; + pol s1_R16 = s1_R15 + a5_R * 0xe24c99adad8; + pol s2_R16 = s2_R15 + a5_R * 0xcf389ed4bc8; + pol s3_R16 = s3_R15 + a5_R * 0xe580cbf6966; + pol s4_R16 = s4_R15 + a5_R * 0xcde5fd7e04f; + pol s5_R16 = s5_R15 + a5_R * 0xe63628041b3; + pol s6_R16 = s6_R15 + a5_R * 0xe7e81a87361; + pol s7_R16 = s7_R15 + a5_R * 0xdabe78f6d98; + pol s8_R16 = s8_R15 + a5_R * 0xefb14cac554; + pol s9_R16 = s9_R15 + a5_R * 0xe5574743b10; + pol s10_R16 = s10_R15 + a5_R * 0xd05709f42c1; + pol s11_R16 = s11_R15 + a5_R * 0xe4690c96af1; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp6 = POSEIDONCUSTFIRST * (custPoseidonInput6 - a[6]) + a[6] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xd438539c95f63e9f; + // Calculate the 7th power of the 6th element + pol inpP6 = PARTIALROUND * s0_R5 + PARTIALROUND2 * s0_R16 + (POSEIDONM + POSEIDONP) * inp6; + pol a6_2 = inpP6 * inpP6; + pol a6_4 = a6_2 * a6_2; + pol a6_6 = a6_4 * a6_2; + pol a6_R = a6_6 * inpP6 + C[6]; + + + // Partial round 6 + pol s0_R6 = 0x19 * a6_R + 0x7186a80551025f8f * s1_R5 + 0x622247557e9b5371 * s2_R5 + 0xc4cbe326d1ad9742 * s3_R5 + 0x55f1523ac6a23ea2 * s4_R5 + 0xa13dfe77a3d52f53 * s5_R5 + 0xe30750b6301c0452 * s6_R5 + 0x8bd488070a3a32b * s7_R5 + 0xcd800caef5b72ae3 * s8_R5 + 0x83329c90f04233ce * s9_R5 + 0xb5b99e6664a0a3ee * s10_R5 + 0x6b0731849e200a7f * s11_R5; + pol s1_R6 = s1_R5 + a6_R * 0x577f9a9e7ee3f9c2; + pol s2_R6 = s2_R5 + a6_R * 0x88c522b949ace7b1; + pol s3_R6 = s3_R5 + a6_R * 0x82f07007c8b72106; + pol s4_R6 = s4_R5 + a6_R * 0x8283d37c6675b50e; + pol s5_R6 = s5_R5 + a6_R * 0x98b074d9bbac1123; + pol s6_R6 = s6_R5 + a6_R * 0x75c56fb7758317c1; + pol s7_R6 = s7_R5 + a6_R * 0xfed24e206052bc72; + pol s8_R6 = s8_R5 + a6_R * 0x26d7c3d1bc07dae5; + pol s9_R6 = s9_R5 + a6_R * 0xf88c5e441e28dbb4; + pol s10_R6 = s10_R5 + a6_R * 0x4fe27f9f96615270; + pol s11_R6 = s11_R5 + a6_R * 0x514d4ba49c2b14fe; + + + + // Partial round 17 + pol s0_R17 = 0x19 * a6_R + 0xc15acf44759545a3 * s1_R16 + 0xcbfdcf39869719d4 * s2_R16 + 0x33f62042e2f80225 * s3_R16 + 0x2599c5ead81d8fa3 * s4_R16 + 0xb306cb6c1d7c8d0 * s5_R16 + 0x658c80d3df3729b1 * s6_R16 + 0xe8d1b2b21b41429c * s7_R16 + 0xa1b67f09d4b3ccb8 * s8_R16 + 0xe1adf8b84437180 * s9_R16 + 0xd593a5e584af47b * s10_R16 + 0xa023d94c56e151c7 * s11_R16; + pol s1_R17 = s1_R16 + a6_R * 0xf7157bc98; + pol s2_R17 = s2_R16 + a6_R * 0xe3006d948; + pol s3_R17 = s3_R16 + a6_R * 0xfa65811e6; + pol s4_R17 = s4_R16 + a6_R * 0xe0d127e2f; + pol s5_R17 = s5_R16 + a6_R * 0xfc18bfe53; + pol s6_R17 = s6_R16 + a6_R * 0xfd002d901; + pol s7_R17 = s7_R16 + a6_R * 0xeed6461d8; + pol s8_R17 = s8_R16 + a6_R * 0x1068562754; + pol s9_R17 = s9_R16 + a6_R * 0xfa0236f50; + pol s10_R17 = s10_R16 + a6_R * 0xe3af13ee1; + pol s11_R17 = s11_R16 + a6_R * 0xfa460f6d1; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp7 = POSEIDONCUSTFIRST * (custPoseidonInput7 - a[7]) + a[7] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xef781c7ce35b4c3d; + // Calculate the 7th power of the 7th element + pol inpP7 = PARTIALROUND * s0_R6 + PARTIALROUND2 * s0_R17 + (POSEIDONM + POSEIDONP) * inp7; + pol a7_2 = inpP7 * inpP7; + pol a7_4 = a7_2 * a7_2; + pol a7_6 = a7_4 * a7_2; + pol a7_R = a7_6 * inpP7 + C[7]; + + + // Partial round 7 + pol s0_R7 = 0x19 * a7_R + 0xec3fabc192b01799 * s1_R6 + 0x382b38cee8ee5375 * s2_R6 + 0x3bfb6c3f0e616572 * s3_R6 + 0x514abd0cf6c7bc86 * s4_R6 + 0x47521b1361dcc546 * s5_R6 + 0x178093843f863d14 * s6_R6 + 0xad1003c5d28918e7 * s7_R6 + 0x738450e42495bc81 * s8_R6 + 0xaf947c59af5e4047 * s9_R6 + 0x4653fb0685084ef2 * s10_R6 + 0x57fde2062ae35bf * s11_R6; + pol s1_R7 = s1_R6 + a7_R * 0xf02a3ac068ee110b; + pol s2_R7 = s2_R6 + a7_R * 0xa3630dafb8ae2d7; + pol s3_R7 = s3_R6 + a7_R * 0xce0dc874eaf9b55c; + pol s4_R7 = s4_R6 + a7_R * 0x9a95f6cff5b55c7e; + pol s5_R7 = s5_R6 + a7_R * 0x626d76abfed00c7b; + pol s6_R7 = s6_R6 + a7_R * 0xa0c1cf1251c204ad; + pol s7_R7 = s7_R6 + a7_R * 0xdaebd3006321052c; + pol s8_R7 = s8_R6 + a7_R * 0x3d4bd48b625a8065; + pol s9_R7 = s9_R6 + a7_R * 0x7f1e584e071f6ed2; + pol s10_R7 = s10_R6 + a7_R * 0x720574f0501caed3; + pol s11_R7 = s11_R6 + a7_R * 0xe3260ba93d23540a; + + + + // Partial round 18 + pol s0_R18 = 0x19 * a7_R + 0x49026cc3a4afc5a6 * s1_R17 + 0xe06dff00ab25b91b * s2_R17 + 0xab38c561e8850ff * s3_R17 + 0x92c3c8275e105eeb * s4_R17 + 0xb65256e546889bd0 * s5_R17 + 0x3c0468236ea142f6 * s6_R17 + 0xee61766b889e18f2 * s7_R17 + 0xa206f41b12c30415 * s8_R17 + 0x2fe9d756c9f12d1 * s9_R17 + 0xe9633210630cbf12 * s10_R17 + 0x1ffea9fe85a0b0b1 * s11_R17; + pol s1_R18 = s1_R17 + a7_R * 0x11131738; + pol s2_R18 = s2_R17 + a7_R * 0xf56d588; + pol s3_R18 = s3_R17 + a7_R * 0x11050f86; + pol s4_R18 = s4_R17 + a7_R * 0xf848f4f; + pol s5_R18 = s5_R17 + a7_R * 0x111527d3; + pol s6_R18 = s6_R17 + a7_R * 0x114369a1; + pol s7_R18 = s7_R17 + a7_R * 0x106f2f38; + pol s8_R18 = s8_R17 + a7_R * 0x11e2ca94; + pol s9_R18 = s9_R17 + a7_R * 0x110a29f0; + pol s10_R18 = s10_R17 + a7_R * 0xfa9f5c1; + pol s11_R18 = s11_R17 + a7_R * 0x10f625d1; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp8 = POSEIDONCUSTFIRST * (-a[8]) + a[8] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xcdc4a239b0c44426; + // Calculate the 7th power of the 8th element + pol inpP8 = PARTIALROUND * s0_R7 + PARTIALROUND2 * s0_R18 + (POSEIDONM + POSEIDONP) * inp8; + pol a8_2 = inpP8 * inpP8; + pol a8_4 = a8_2 * a8_2; + pol a8_6 = a8_4 * a8_2; + pol a8_R = a8_6 * inpP8 + C[8]; + + + // Partial round 8 + pol s0_R8 = 0x19 * a8_R + 0xe376678d843ce55e * s1_R7 + 0x66f3860d7514e7fc * s2_R7 + 0x7817f3dfff8b4ffa * s3_R7 + 0x3929624a9def725b * s4_R7 + 0x126ca37f215a80a * s5_R7 + 0xfce2f5d02762a303 * s6_R7 + 0x1bc927375febbad7 * s7_R7 + 0x85b481e5243f60bf * s8_R7 + 0x2d3c5f42a39c91a0 * s9_R7 + 0x811719919351ae8 * s10_R7 + 0xf669de0add993131 * s11_R7; + pol s1_R8 = s1_R7 + a8_R * 0xab1cbd41d8c1e335; + pol s2_R8 = s2_R7 + a8_R * 0x9322ed4c0bc2df01; + pol s3_R8 = s3_R7 + a8_R * 0x51c3c0983d4284e5; + pol s4_R8 = s4_R7 + a8_R * 0x94178e291145c231; + pol s5_R8 = s5_R7 + a8_R * 0xfd0f1a973d6b2085; + pol s6_R8 = s6_R7 + a8_R * 0xd427ad96e2b39719; + pol s7_R8 = s7_R7 + a8_R * 0x8a52437fecaac06b; + pol s8_R8 = s8_R7 + a8_R * 0xdc20ee4b8c4c9a80; + pol s9_R8 = s9_R7 + a8_R * 0xa2c98e9549da2100; + pol s10_R8 = s10_R7 + a8_R * 0x1603fe12613db5b6; + pol s11_R8 = s11_R7 + a8_R * 0xe174929433c5505; + + + + // Partial round 19 + pol s0_R19 = 0x19 * a8_R + 0x81d1ae8cc50240f3 * s1_R18 + 0xf4c77a079a4607d7 * s2_R18 + 0xed446b2315e3efc1 * s3_R18 + 0xb0a6b70915178c3 * s4_R18 + 0xb11ff3e089f15d9a * s5_R18 + 0x1d4dba0b7ae9cc18 * s6_R18 + 0x65d74e2f43b48d05 * s7_R18 + 0xa2df8c6b8ae0804a * s8_R18 + 0xa4e6f0a8c33348a6 * s9_R18 + 0xc0a26efc7be5669b * s10_R18 + 0xa6b6582c547d0d60 * s11_R18; + pol s1_R19 = s1_R18 + a8_R * 0x11f718; + pol s2_R19 = s2_R18 + a8_R * 0x10b6c8; + pol s3_R19 = s3_R18 + a8_R * 0x134a96; + pol s4_R19 = s4_R18 + a8_R * 0x10cf7f; + pol s5_R19 = s5_R18 + a8_R * 0x124d03; + pol s6_R19 = s6_R18 + a8_R * 0x13f8a1; + pol s7_R19 = s7_R18 + a8_R * 0x117c58; + pol s8_R19 = s8_R18 + a8_R * 0x132c94; + pol s9_R19 = s9_R18 + a8_R * 0x134fc0; + pol s10_R19 = s10_R18 + a8_R * 0x10a091; + pol s11_R19 = s11_R18 + a8_R * 0x128961; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp9 = POSEIDONCUSTFIRST * (-a[9]) + a[9] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0x277fa208bf337bff; + // Calculate the 7th power of the 9th element + pol inpP9 = PARTIALROUND * s0_R8 + PARTIALROUND2 * s0_R19 + (POSEIDONM + POSEIDONP) * inp9; + pol a9_2 = inpP9 * inpP9; + pol a9_4 = a9_2 * a9_2; + pol a9_6 = a9_4 * a9_2; + pol a9_R = a9_6 * inpP9 + C[9]; + + + // Partial round 9 + pol s0_R9 = 0x19 * a9_R + 0x7de38bae084da92d * s1_R8 + 0x5b848442237e8a9b * s2_R8 + 0xf6c705da84d57310 * s3_R8 + 0x31e6a4bdb6a49017 * s4_R8 + 0x889489706e5c5c0f * s5_R8 + 0xe4a205459692a1b * s6_R8 + 0xbac3fa75ee26f299 * s7_R8 + 0x5f5894f4057d755e * s8_R8 + 0xb0dc3ecd724bb076 * s9_R8 + 0x5e34d8554a6452ba * s10_R8 + 0x4f78fd8c1fdcc5f * s11_R8; + pol s1_R9 = s1_R8 + a9_R * 0x3d4eab2b8ef5f796; + pol s2_R9 = s2_R8 + a9_R * 0xcfff421583896e22; + pol s3_R9 = s3_R8 + a9_R * 0x4143cb32d39ac3d9; + pol s4_R9 = s4_R8 + a9_R * 0x22365051b78a5b65; + pol s5_R9 = s5_R8 + a9_R * 0x6f7fd010d027c9b6; + pol s6_R9 = s6_R8 + a9_R * 0xd9dd36fba77522ab; + pol s7_R9 = s7_R8 + a9_R * 0xa44cf1cb33e37165; + pol s8_R9 = s8_R8 + a9_R * 0x3fc83d3038c86417; + pol s9_R9 = s9_R8 + a9_R * 0xc4588d418e88d270; + pol s10_R9 = s10_R8 + a9_R * 0xce1320f10ab80fe2; + pol s11_R9 = s11_R8 + a9_R * 0xdb5eadbbec18de5d; + + + + // Partial round 20 + pol s0_R20 = 0x19 * a9_R + 0x84afc741f1c13213 * s1_R19 + 0x2f8f43734fc906f3 * s2_R19 + 0xde682d72da0a02d9 * s3_R19 + 0xbb005236adb9ef2 * s4_R19 + 0x5bdf35c10a8b5624 * s5_R19 + 0x739a8a343950010 * s6_R19 + 0x52f515f44785cfbc * s7_R19 + 0xcbaf4e5d82856c60 * s8_R19 + 0xac9ea09074e3e150 * s9_R19 + 0x8f0fa011a2035fb0 * s10_R19 + 0x1a37905d8450904a * s11_R19; + pol s1_R20 = s1_R19 + a9_R * 0x1300; + pol s2_R20 = s2_R19 + a9_R * 0x1750; + pol s3_R20 = s3_R19 + a9_R * 0x114e; + pol s4_R20 = s4_R19 + a9_R * 0x131f; + pol s5_R20 = s5_R19 + a9_R * 0x167b; + pol s6_R20 = s6_R19 + a9_R * 0x1371; + pol s7_R20 = s7_R19 + a9_R * 0x1230; + pol s8_R20 = s8_R19 + a9_R * 0x182c; + pol s9_R20 = s9_R19 + a9_R * 0x1368; + pol s10_R20 = s10_R19 + a9_R * 0xf31; + pol s11_R20 = s11_R19 + a9_R * 0x15c9; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp10 = POSEIDONCUSTFIRST * (-a[10]) + a[10] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xe17653a29da578a1; + // Calculate the 7th power of the 10th element + pol inpP10 = PARTIALROUND * s0_R9 + PARTIALROUND2 * s0_R20 + (POSEIDONM + POSEIDONP) * inp10; + pol a10_2 = inpP10 * inpP10; + pol a10_4 = a10_2 * a10_2; + pol a10_6 = a10_4 * a10_2; + pol a10_R = a10_6 * inpP10 + C[10]; + + + // Partial round 10 + pol s0_R10 = 0x19 * a10_R + 0x4dd19c38779512ea * s1_R9 + 0xdb79ba02704620e9 * s2_R9 + 0x92a29a3675a5d2be * s3_R9 + 0xd5177029fe495166 * s4_R9 + 0xd32b3298a13330c1 * s5_R9 + 0x251c4a3eb2c5f8fd * s6_R9 + 0xe1c48b26e0d98825 * s7_R9 + 0x3301d3362a4ffccb * s8_R9 + 0x9bb6c88de8cd178 * s9_R9 + 0xdc05b676564f538a * s10_R9 + 0x60192d883e473fee * s11_R9; + pol s1_R10 = s1_R9 + a10_R * 0x1183dfce7c454afd; + pol s2_R10 = s2_R9 + a10_R * 0x21cea4aa3d3ed949; + pol s3_R10 = s3_R9 + a10_R * 0xfce6f70303f2304; + pol s4_R10 = s4_R9 + a10_R * 0x19557d34b55551be; + pol s5_R10 = s5_R9 + a10_R * 0x4c56f689afc5bbc9; + pol s6_R10 = s6_R9 + a10_R * 0xa1e920844334f944; + pol s7_R10 = s7_R9 + a10_R * 0xbad66d423d2ec861; + pol s8_R10 = s8_R9 + a10_R * 0xf318c785dc9e0479; + pol s9_R10 = s9_R9 + a10_R * 0x99e2032e765ddd81; + pol s10_R10 = s10_R9 + a10_R * 0x400ccc9906d66f45; + pol s11_R10 = s11_R9 + a10_R * 0xe1197454db2e0dd9; + + + + // Partial round 21 + pol s0_R21 = 0x19 * a10_R + 0x3abeb80def61cc85 * s1_R20 + 0x9d19c9dd4eac4133 * s2_R20 + 0x75a652d9641a985 * s3_R20 + 0x9daf69ae1b67e667 * s4_R20 + 0x364f71da77920a18 * s5_R20 + 0x50bd769f745c95b1 * s6_R20 + 0xf223d1180dbbf3fc * s7_R20 + 0x2f885e584e04aa99 * s8_R20 + 0xb69a0fa70aea684a * s9_R20 + 0x9584acaa6e062a0 * s10_R20 + 0xbc051640145b19b * s11_R20; + pol s1_R21 = s1_R20 + a10_R * 0x14; + pol s2_R21 = s2_R20 + a10_R * 0x22; + pol s3_R21 = s3_R20 + a10_R * 0x12; + pol s4_R21 = s4_R20 + a10_R * 0x27; + pol s5_R21 = s5_R20 + a10_R * 0xd; + pol s6_R21 = s6_R20 + a10_R * 0xd; + pol s7_R21 = s7_R20 + a10_R * 0x1c; + pol s8_R21 = s8_R20 + a10_R * 0x2; + pol s9_R21 = s9_R20 + a10_R * 0x10; + pol s10_R21 = s10_R20 + a10_R * 0x29; + pol s11_R21 = s11_R20 + a10_R * 0xf; + + // If it is the first round of CustPoseidon, we need to set as input the previously calculated one. + // If it is the first round, we will add the corresponding constant and directly verify round 1. + pol inp11 = POSEIDONCUSTFIRST * (-a[11]) + a[11] + (POSEIDONFIRST + POSEIDONCUSTFIRST) * 0xc54302f225db2c76; + // Calculate the 7th power of the 11th element + pol a11_2 = inp11 * inp11; + pol a11_4 = a11_2 * a11_2; + pol a11_6 = a11_4 * a11_2; + pol a11_R = a11_6 * inp11 + C[11]; + + + + POSEIDONP * (a[0]' - (0x19 * a0_R + 0xf * a1_R + 0x29 * a2_R + 0x10 * a3_R + 0x2 * a4_R + 0x1c * a5_R + 0xd * a6_R + 0xd * a7_R + 0x27 * a8_R + 0x12 * a9_R + 0x22 * a10_R + 0x14 * a11_R)) = 0; + POSEIDONP * (a[1]' - (0x78566230aa7cc5d0 * a0_R + 0x817bd8a7869ed1b5 * a1_R + 0xd267254bea1097f4 * a2_R + 0x60c33ebd1e023f0a * a3_R + 0xa89ef32ae1462322 * a4_R + 0x6250f5f176d483e7 * a5_R + 0xe16a6c1dee3ba347 * a6_R + 0xec9730136b7c2c05 * a7_R + 0x3cf7c3a39d94c236 * a8_R + 0xb4707207455f57e3 * a9_R + 0xaadb39e83e76a9e0 * a10_R + 0x32f8ae916e567d39 * a11_R)) = 0; + POSEIDONP * (a[2]' - (0xdbf23e50005e7f24 * a0_R + 0x819f2c14a8366b1f * a1_R + 0x2dc10fce3233f443 * a2_R + 0xdb6945a20d277091 * a3_R + 0x77c1a153e73659e8 * a4_R + 0xaad1255d46e78f07 * a5_R + 0x13d316e45539aef4 * a6_R + 0xe1ecc5c21eec0646 * a7_R + 0x9e62c7d7b000cb0b * a8_R + 0x8e1de42b665c6706 * a9_R + 0xcd9bf0bd292c5fda * a10_R + 0xaadb39e83e76a9e0 * a11_R)) = 0; + POSEIDONP * (a[3]' - (0xb4a02c5c826d523e * a0_R + 0x7a5cf5b7b922e946 * a1_R + 0xfa9db0de2d852e7a * a2_R + 0x383dd77e07998487 * a3_R + 0x2aec981be4b62ed5 * a4_R + 0x8a00c7c83c762584 * a5_R + 0x577e0472764f061d * a6_R + 0x956d3c8b5528e064 * a7_R + 0xe202be7ad7265af6 * a8_R + 0xee7b04568203481 * a9_R + 0x8e1de42b665c6706 * a10_R + 0xb4707207455f57e3 * a11_R)) = 0; + POSEIDONP * (a[4]' - (0x466d8f66a8f9fed5 * a0_R + 0x727eca45c8d7bb71 * a1_R + 0xde2a0516f8c9d943 * a2_R + 0xe04ea1957ad8305c * a3_R + 0xb70fb5f2b4f1f85f * a4_R + 0xc734f3829ed30b0c * a5_R + 0x226a4dcf5db3316d * a6_R + 0x6df1d31fa84398f4 * a7_R + 0x82178371fa5fff69 * a8_R + 0xe202be7ad7265af6 * a9_R + 0x9e62c7d7b000cb0b * a10_R + 0x3cf7c3a39d94c236 * a11_R)) = 0; + POSEIDONP * (a[5]' - (0x68da2264f65ec3e * a0_R + 0x605a82c52b5ad2f1 * a1_R + 0xe6fdf23648931b99 * a2_R + 0xd499fcbf63fbd266 * a3_R + 0x7c66d474cd2087cb * a4_R + 0xb1a0132288b1619b * a5_R + 0x3373035a3ca3dac6 * a6_R + 0xf4898a1a3554ee49 * a7_R + 0x6df1d31fa84398f4 * a8_R + 0x956d3c8b5528e064 * a9_R + 0xe1ecc5c21eec0646 * a10_R + 0xec9730136b7c2c05 * a11_R)) = 0; + POSEIDONP * (a[6]' - (0xb59f9ff0ac6d5d78 * a0_R + 0x59ccc4d5184bc93a * a1_R + 0x3743057c07a5dbfa * a2_R + 0x462269e4b04620a5 * a3_R + 0x39302966be7df654 * a4_R + 0x88685b4f0798dfd1 * a5_R + 0x441f3a3747b5adb7 * a6_R + 0x3373035a3ca3dac6 * a7_R + 0x226a4dcf5db3316d * a8_R + 0x577e0472764f061d * a9_R + 0x13d316e45539aef4 * a10_R + 0xe16a6c1dee3ba347 * a11_R)) = 0; + POSEIDONP * (a[7]' - (0xcfb03c902d447551 * a0_R + 0x66c8bab2096cfd38 * a1_R + 0xa6fdb8ebccc51667 * a2_R + 0x63c9679d8572a867 * a3_R + 0xb827c807875511c0 * a4_R + 0xfc02e869e21b72f8 * a5_R + 0x88685b4f0798dfd1 * a6_R + 0xb1a0132288b1619b * a7_R + 0xc734f3829ed30b0c * a8_R + 0x8a00c7c83c762584 * a9_R + 0xaad1255d46e78f07 * a10_R + 0x6250f5f176d483e7 * a11_R)) = 0; + POSEIDONP * (a[8]' - (0x2044ce14eaf8f5d9 * a0_R + 0xeb4c0ce280c3e935 * a1_R + 0x2c4916605e3dea58 * a2_R + 0x81c44e9699915693 * a3_R + 0xa4daffb3ffd0e78f * a4_R + 0xb827c807875511c0 * a5_R + 0x39302966be7df654 * a6_R + 0x7c66d474cd2087cb * a7_R + 0xb70fb5f2b4f1f85f * a8_R + 0x2aec981be4b62ed5 * a9_R + 0x77c1a153e73659e8 * a10_R + 0xa89ef32ae1462322 * a11_R)) = 0; + POSEIDONP * (a[9]' - (0xfb9373c8481e0f0d * a0_R + 0x17f9202c16676b2f * a1_R + 0xe95c10ae32e05085 * a2_R + 0x62ecbe05e02433fc * a3_R + 0x81c44e9699915693 * a4_R + 0x63c9679d8572a867 * a5_R + 0x462269e4b04620a5 * a6_R + 0xd499fcbf63fbd266 * a7_R + 0xe04ea1957ad8305c * a8_R + 0x383dd77e07998487 * a9_R + 0xdb6945a20d277091 * a10_R + 0x60c33ebd1e023f0a * a11_R)) = 0; + POSEIDONP * (a[10]' - (0x72af70cdcb99214f * a0_R + 0x9b6e5164ed35d878 * a1_R + 0x97f9b7d2cfc2ade5 * a2_R + 0xe95c10ae32e05085 * a3_R + 0x2c4916605e3dea58 * a4_R + 0xa6fdb8ebccc51667 * a5_R + 0x3743057c07a5dbfa * a6_R + 0xe6fdf23648931b99 * a7_R + 0xde2a0516f8c9d943 * a8_R + 0xfa9db0de2d852e7a * a9_R + 0x2dc10fce3233f443 * a10_R + 0xd267254bea1097f4 * a11_R)) = 0; + POSEIDONP * (a[11]' - (0xe3ef40eacc6ff78d * a0_R + 0x6fadc9347faeee81 * a1_R + 0x9b6e5164ed35d878 * a2_R + 0x17f9202c16676b2f * a3_R + 0xeb4c0ce280c3e935 * a4_R + 0x66c8bab2096cfd38 * a5_R + 0x59ccc4d5184bc93a * a6_R + 0x605a82c52b5ad2f1 * a7_R + 0x727eca45c8d7bb71 * a8_R + 0x7a5cf5b7b922e946 * a9_R + 0x819f2c14a8366b1f * a10_R + 0x817bd8a7869ed1b5 * a11_R)) = 0; + + POSEIDONM * (a[0]' - (0x19 * a0_R + 0xf * a1_R + 0x29 * a2_R + 0x10 * a3_R + 0x2 * a4_R + 0x1c * a5_R + 0xd * a6_R + 0xd * a7_R + 0x27 * a8_R + 0x12 * a9_R + 0x22 * a10_R + 0x14 * a11_R)) = 0; + POSEIDONM * (a[1]' - (0x14 * a0_R + 0x11 * a1_R + 0xf * a2_R + 0x29 * a3_R + 0x10 * a4_R + 0x2 * a5_R + 0x1c * a6_R + 0xd * a7_R + 0xd * a8_R + 0x27 * a9_R + 0x12 * a10_R + 0x22 * a11_R)) = 0; + POSEIDONM * (a[2]' - (0x22 * a0_R + 0x14 * a1_R + 0x11 * a2_R + 0xf * a3_R + 0x29 * a4_R + 0x10 * a5_R + 0x2 * a6_R + 0x1c * a7_R + 0xd * a8_R + 0xd * a9_R + 0x27 * a10_R + 0x12 * a11_R)) = 0; + POSEIDONM * (a[3]' - (0x12 * a0_R + 0x22 * a1_R + 0x14 * a2_R + 0x11 * a3_R + 0xf * a4_R + 0x29 * a5_R + 0x10 * a6_R + 0x2 * a7_R + 0x1c * a8_R + 0xd * a9_R + 0xd * a10_R + 0x27 * a11_R)) = 0; + POSEIDONM * (a[4]' - (0x27 * a0_R + 0x12 * a1_R + 0x22 * a2_R + 0x14 * a3_R + 0x11 * a4_R + 0xf * a5_R + 0x29 * a6_R + 0x10 * a7_R + 0x2 * a8_R + 0x1c * a9_R + 0xd * a10_R + 0xd * a11_R)) = 0; + POSEIDONM * (a[5]' - (0xd * a0_R + 0x27 * a1_R + 0x12 * a2_R + 0x22 * a3_R + 0x14 * a4_R + 0x11 * a5_R + 0xf * a6_R + 0x29 * a7_R + 0x10 * a8_R + 0x2 * a9_R + 0x1c * a10_R + 0xd * a11_R)) = 0; + POSEIDONM * (a[6]' - (0xd * a0_R + 0xd * a1_R + 0x27 * a2_R + 0x12 * a3_R + 0x22 * a4_R + 0x14 * a5_R + 0x11 * a6_R + 0xf * a7_R + 0x29 * a8_R + 0x10 * a9_R + 0x2 * a10_R + 0x1c * a11_R)) = 0; + POSEIDONM * (a[7]' - (0x1c * a0_R + 0xd * a1_R + 0xd * a2_R + 0x27 * a3_R + 0x12 * a4_R + 0x22 * a5_R + 0x14 * a6_R + 0x11 * a7_R + 0xf * a8_R + 0x29 * a9_R + 0x10 * a10_R + 0x2 * a11_R)) = 0; + POSEIDONM * (a[8]' - (0x2 * a0_R + 0x1c * a1_R + 0xd * a2_R + 0xd * a3_R + 0x27 * a4_R + 0x12 * a5_R + 0x22 * a6_R + 0x14 * a7_R + 0x11 * a8_R + 0xf * a9_R + 0x29 * a10_R + 0x10 * a11_R)) = 0; + POSEIDONM * (a[9]' - (0x10 * a0_R + 0x2 * a1_R + 0x1c * a2_R + 0xd * a3_R + 0xd * a4_R + 0x27 * a5_R + 0x12 * a6_R + 0x22 * a7_R + 0x14 * a8_R + 0x11 * a9_R + 0xf * a10_R + 0x29 * a11_R)) = 0; + POSEIDONM * (a[10]' - (0x29 * a0_R + 0x10 * a1_R + 0x2 * a2_R + 0x1c * a3_R + 0xd * a4_R + 0xd * a5_R + 0x27 * a6_R + 0x12 * a7_R + 0x22 * a8_R + 0x14 * a9_R + 0x11 * a10_R + 0xf * a11_R)) = 0; + POSEIDONM * (a[11]' - (0xf * a0_R + 0x29 * a1_R + 0x10 * a2_R + 0x2 * a3_R + 0x1c * a4_R + 0xd * a5_R + 0xd * a6_R + 0x27 * a7_R + 0x12 * a8_R + 0x22 * a9_R + 0x14 * a10_R + 0x11 * a11_R)) = 0; + + PARTIALROUND * (a[0]' - s0_R10) = 0; + PARTIALROUND * (a[1]' - s1_R10) = 0; + PARTIALROUND * (a[2]' - s2_R10) = 0; + PARTIALROUND * (a[3]' - s3_R10) = 0; + PARTIALROUND * (a[4]' - s4_R10) = 0; + PARTIALROUND * (a[5]' - s5_R10) = 0; + PARTIALROUND * (a[6]' - s6_R10) = 0; + PARTIALROUND * (a[7]' - s7_R10) = 0; + PARTIALROUND * (a[8]' - s8_R10) = 0; + PARTIALROUND * (a[9]' - s9_R10) = 0; + PARTIALROUND * (a[10]' - s10_R10) = 0; + PARTIALROUND * (a[11]' - s11_R10) = 0; + + + PARTIALROUND2 * (a[0]' - s0_R21) = 0; + PARTIALROUND2 * (a[1]' - s1_R21) = 0; + PARTIALROUND2 * (a[2]' - s2_R21) = 0; + PARTIALROUND2 * (a[3]' - s3_R21) = 0; + PARTIALROUND2 * (a[4]' - s4_R21) = 0; + PARTIALROUND2 * (a[5]' - s5_R21) = 0; + PARTIALROUND2 * (a[6]' - s6_R21) = 0; + PARTIALROUND2 * (a[7]' - s7_R21) = 0; + PARTIALROUND2 * (a[8]' - s8_R21) = 0; + PARTIALROUND2 * (a[9]' - s9_R21) = 0; + PARTIALROUND2 * (a[10]' - s10_R21) = 0; + PARTIALROUND2 * (a[11]' - s11_R21) = 0; + + // CMUL GATE - Check that a * b in Fp³ using (X³ - X - 1) as a generator is performed correctly + // In this particular case, + // a = [a[3], a[4], a[5]] + // b = [a[6], a[7], a[8]] + // and this must be equal to [ a[9], a[10], a[11] ] + + // Since the modulo is known (X³ - X - 1) we can calculate the coefficients in general form by calculating + // (a0 + a1*x + a2*x²)*(b0 + b1*x + b2*x²) and then using long division to get the residue when dividing by the modulo + // We get the following result: (a0*b0 + a1*b2 + a2*b1) + (a0*b1 + a1*b0 + a1*b2 + a2*b1 + a2*b2)x + (a0*b2 + a2*b2 + a2*b0 + a1*b1)x² + // This result can be expressed using this intermediate polyonials A,B,C,D,E,F that have less than degree 2 + pol cA1 = (a[3] + a[4]) * (a[6] + a[7]); + pol cB1 = (a[3] + a[5]) * (a[6] + a[8]); + pol cC1 = (a[4] + a[5]) * (a[7] + a[8]); + pol cD1 = a[3]*a[6]; + pol cE1 = a[4]*a[7]; + pol cF1 = a[5]*a[8]; + + // Whenever CMUL = 1, check that the CMul result matches with the values stored in a[9], a[10] and a[11] respectively + CMUL * (a[9] - (cC1 + cD1 - cE1 - cF1)) = 0; + CMUL * (a[10] - (cA1 + cC1 - 2*cE1 - cD1)) = 0; + CMUL * (a[11] - (cB1 - cD1 + cE1)) = 0; + + // Check that the plonk constraint stored in a[0], a[1], a[2] is correct + g012*CMUL = 0; + + // FFT4 + + pol g0 = C[0]*a[0] + C[1]*a[3] + C[2]*a[6] + C[3]*a[9] + C[6]*a[0] + C[7]*a[3]; + pol g3 = C[0]*a[0] - C[1]*a[3] + C[4]*a[6] - C[5]*a[9] + C[6]*a[0] - C[7]*a[3]; + pol g6 = C[0]*a[0] + C[1]*a[3] - C[2]*a[6] - C[3]*a[9] + C[6]*a[6] + C[8]*a[9]; + pol g9 = C[0]*a[0] - C[1]*a[3] - C[4]*a[6] + C[5]*a[9] + C[6]*a[6] - C[8]*a[9]; + + pol g1 = C[0]*a[1] + C[1]*a[4] + C[2]*a[7] + C[3]*a[10] + C[6]*a[1] + C[7]*a[4]; + pol g4 = C[0]*a[1] - C[1]*a[4] + C[4]*a[7] - C[5]*a[10] + C[6]*a[1] - C[7]*a[4]; + pol g7 = C[0]*a[1] + C[1]*a[4] - C[2]*a[7] - C[3]*a[10] + C[6]*a[7] + C[8]*a[10]; + pol g10 = C[0]*a[1] - C[1]*a[4] - C[4]*a[7] + C[5]*a[10] + C[6]*a[7] - C[8]*a[10]; + + pol g2 = C[0]*a[2] + C[1]*a[5] + C[2]*a[8] + C[3]*a[11] + C[6]*a[2] + C[7]*a[5]; + pol g5 = C[0]*a[2] - C[1]*a[5] + C[4]*a[8] - C[5]*a[11] + C[6]*a[2] - C[7]*a[5]; + pol g8 = C[0]*a[2] + C[1]*a[5] - C[2]*a[8] - C[3]*a[11] + C[6]*a[8] + C[8]*a[11]; + pol g11 = C[0]*a[2] - C[1]*a[5] - C[4]*a[8] + C[5]*a[11] + C[6]*a[8] - C[8]*a[11]; + + FFT4 * (a[0]' - g0) = 0; + FFT4 * (a[1]' - g1) = 0; + FFT4 * (a[2]' - g2) = 0; + FFT4 * (a[3]' - g3) = 0; + FFT4 * (a[4]' - g4) = 0; + FFT4 * (a[5]' - g5) = 0; + FFT4 * (a[6]' - g6) = 0; + FFT4 * (a[7]' - g7) = 0; + FFT4 * (a[8]' - g8) = 0; + FFT4 * (a[9]' - g9) = 0; + FFT4 * (a[10]' - g10) = 0; + FFT4 * (a[11]' - g11) = 0; + + // EVPOL4 - Check that the polynomial evaluation is valid + // Evaluate p(x) = d0*x⁴ + d1*x³ + d2*x²+ d3*x + d4 at point z = a[0]' + a[1]'x + a[2]'x² where + // d0 = a[3]' + a[4]' * x + a[5]' * x² + // d1 = a[0]' + a[1]' * x + a[2]' * x² + // d2 = a[9] + a[10] * x + a[11] * x² + // d3 = a[6] + a[7] * x + a[8] * x² + // d4 = a[3] + a[4] * x + a[5] * x² + // The result must be equal to a[6]' + a[7]' * x + a[8]' * x² + // The evaluation is performed using the Horner's rule, which means that p(x) is rewritten as + // p(x) = (d0 * x + d1)*x + d2)*x + d3)*x + d4 + // Note: All operations are performed in Fp³ and so multiplications are performed using CMulAdd + + + // Calculate acc = d0 * x + d1 + pol A1 = (a[3]' + a[4]') * (a[6]' + a[7]'); + pol B1 = (a[3]' + a[5]') * (a[6]' + a[8]'); + pol C1 = (a[4]' + a[5]') * (a[7]' + a[8]'); + pol D1 = a[3]' * a[6]'; + pol E1 = a[4]' * a[7]'; + pol F1 = a[5]' * a[8]'; + pol acc1_0 = C1+ D1 - E1 - F1 + a[0]'; + pol acc1_1 = A1+ C1- 2*E1 - D1 + a[1]'; + pol acc1_2 = B1- D1 + E1 + a[2]'; + + // Calculate acc2 = acc * x + d2 + pol A2 = (acc1_0 + acc1_1) * (a[6]' + a[7]'); + pol B2 = (acc1_0 + acc1_2) * (a[6]' + a[8]'); + pol C2 = (acc1_1 + acc1_2) * (a[7]' + a[8]'); + pol D2 = acc1_0 * a[6]'; + pol E2 = acc1_1 * a[7]'; + pol F2 = acc1_2 * a[8]'; + pol acc2_0 = C2+ D2 - E2 - F2 + a[9]; + pol acc2_1 = A2+ C2- 2*E2 - D2 + a[10]; + pol acc2_2 = B2- D2 + E2 + a[11]; + + // Calculate acc3 = acc2 * x + d3 + pol A3 = (acc2_0 + acc2_1) * (a[6]' + a[7]'); + pol B3 = (acc2_0 + acc2_2) * (a[6]' + a[8]'); + pol C3 = (acc2_1 + acc2_2) * (a[7]' + a[8]'); + pol D3 = acc2_0 * a[6]'; + pol E3 = acc2_1 * a[7]'; + pol F3 = acc2_2 * a[8]'; + pol acc3_0 = C3+ D3 - E3 - F3 + a[6]; + pol acc3_1 = A3+ C3- 2*E3 - D3 + a[7]; + pol acc3_2 = B3- D3 + E3 + a[8]; + + // Calculate p = acc4 * x + d4 + pol A4 = (acc3_0 + acc3_1) * (a[6]' + a[7]'); + pol B4 = (acc3_0 + acc3_2) * (a[6]' + a[8]'); + pol C4 = (acc3_1 + acc3_2) * (a[7]' + a[8]'); + pol D4 = acc3_0 * a[6]'; + pol E4 = acc3_1 * a[7]'; + pol F4 = acc3_2 * a[8]'; + pol acc4_0 = C4+ D4 - E4 - F4 + a[3]; + pol acc4_1 = A4+ C4- 2*E4 - D4 + a[4]; + pol acc4_2 = B4- D4 + E4 + a[5]; + + + // Whenever EVPOL4 = 1, check that the evaluation result matches with the values stored in a[9]', a[10]' and a[11]' respectively + EVPOL4 * (a[9]' - acc4_0) = 0; + EVPOL4 * (a[10]' - acc4_1) = 0; + EVPOL4 * (a[11]' - acc4_2) = 0; + + // Check that the plonk constraint stored in a[0], a[1], a[2] is correct + g012*EVPOL4 = 0; + + // TREESELECTOR4 GATE - Check that given 4 values and a key, checks that the output is correct + // The tree is created as follows: if key = 0, even values are pushed up the tree, if the key = 1 the odd ones are pushed. + // Therefore, we need to check that + // key == [0,0] -> [value1, value2, value3, value4] -> [value1, value3] -> [value1] + // key == [1,0] -> [value1, value2, value3, value4] -> [value2, value4] -> [value2] + // key == [0,1] -> [value1, value2, value3, value4] -> [value1, value3] -> [value3] + // key == [1,1] -> [value1, value2, value3, value4] -> [value2, value4] -> [value4] + + // The values are stored in a[6], a[7], a[8] // a[9], a[10], a[11] // a[0]', a[1]', a[2]' // a[3]', a[4]', a[5]' + // The key is stored in a[6]', a[7]' + // The output is stored in [a[9]', a[10]', a[11]'] + + // keys1 will only be 1 if both a[6]', a[7]' are zero + pol keys1 = (1 - a[6]')*(1 - a[7]'); + pol treeSelect1_1 = keys1 * (a[6] - a[8]'); + pol treeSelect1_2 = keys1 * (a[7] - a[9]'); + pol treeSelect1_3 = keys1 * (a[8] - a[10]'); + TREESELECTOR4 * treeSelect1_1 = 0; + TREESELECTOR4 * treeSelect1_2 = 0; + TREESELECTOR4 * treeSelect1_3 = 0; + + // keys2 will only be 1 if a[6]' equals 1 and a[7]' equals 0 + pol keys2 = (a[6]')*(1 - a[7]'); + pol treeSelect2_1 = keys2 * (a[9] - a[8]'); + pol treeSelect2_2 = keys2 * (a[10] - a[9]'); + pol treeSelect2_3 = keys2 * (a[11] - a[10]'); + TREESELECTOR4 * treeSelect2_1 = 0; + TREESELECTOR4 * treeSelect2_2 = 0; + TREESELECTOR4 * treeSelect2_3 = 0; + + // keys3 will only be 1 if a[6]' equals 0 and a[7]' equals 1 + pol keys3 = (1 - a[6]')*(a[7]'); + pol treeSelect3_1 = keys3 * (a[0]' - a[8]'); + pol treeSelect3_2 = keys3 * (a[1]' - a[9]'); + pol treeSelect3_3 = keys3 * (a[2]' - a[10]'); + TREESELECTOR4 * treeSelect3_1 = 0; + TREESELECTOR4 * treeSelect3_2 = 0; + TREESELECTOR4 * treeSelect3_3 = 0; + + // keys4 will only be 1 if a[6]' and a[7]' equals 1 + pol keys4 = (a[6]')*(a[7]'); + pol treeSelect4_1 = keys4 * (a[3]' - a[8]'); + pol treeSelect4_2 = keys4 * (a[4]' - a[9]'); + pol treeSelect4_3 = keys4 * (a[5]' - a[10]'); + TREESELECTOR4 * treeSelect4_1 = 0; + TREESELECTOR4 * treeSelect4_2 = 0; + TREESELECTOR4 * treeSelect4_3 = 0; + + // Check that the plonk constraint stored in a[0], a[1], a[2] and a[3], a[4], a[5] are correct + g012*TREESELECTOR4 = 0; + g345*TREESELECTOR4 = 0; + + pol checkBinaryKey1 = a[6]'*(1 - a[6]'); + pol checkBinaryKey2 = a[7]'*(1 - a[7]'); + TREESELECTOR4 * checkBinaryKey1 = 0; + TREESELECTOR4 * checkBinaryKey2 = 0; + + // Check connection equations of Plonk + { a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11] } connect { S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[8],S[9],S[10],S[11] } \ No newline at end of file