1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003openPlonkmoduleScalar=Bls.Scalarlet(!)=List.mapScalar.of_intlet(!!)l=List.mapScalar.of_intl|>Array.of_listtypeoutcome=Valid|Proof_error|Lookup_errortypecase={name:string;circuit:Circuit.t;witness:Scalar.tarray;outcome:outcome;}(* This function aggregates cases ; if several cases concern the same circuit,
it becomes a circuit with several statements *)letaggregate_cases?(prefix="")cases=letoutcome=(List.hdcases).outcomeinletname,circuits_map,inputs_map,outcome=List.fold_left(fun(name,circuits_map,inputs_map,outcome)case->assert(outcome=case.outcome);letcircuit=case.circuitinletother_inputs=Option.value~default:[]@@SMap.find_optcase.nameinputs_mapinletinputs=case.witness::other_inputsinSMap.((ifname=""thencase.nameelsename^"+"^case.name),addcase.name(circuit,List.lengthinputs)circuits_map,addcase.nameinputsinputs_map,outcome))SMap.(prefix,empty,empty,outcome)casesinletinputs_map=SMap.mapList.revinputs_mapin(name,circuits_map,inputs_map,outcome)moduleUnit_tests_for_each_selector=struct(* ---- Unit tests for each selector. ----
We make circuits with 2 constraints,
as circuits with 1 constraint are not supported. *)letqc=letname="qc"inletwitness=!![0;1]inletcircuit=letwires=leta=[0;0]inletb=[0;0]inletc=[0;1]in[|a;b;c|]inletqo=![0;-1]inletgates=Circuit.make_gates~linear:[(2,qo)]~qc:![0;1]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letlinear_selector_testi=(* We don't have a test for "qo" *)assert(i<>2);letname=Plompiler.Csir.linear_selector_nameiinletwitness=!![0;1]inletcircuit=letwires=Array.initPlompiler.Csir.nb_wires_arch(funj->ifj=i||j=2then[0;1]else[0;0])inletq_linear=![1;1]inletqo=![0;-1]inletlinear=[(i,q_linear);(2,qo)]inletgates=Circuit.make_gates~linear()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letnext_linear_selector_testi=letname=Plompiler.Csir.(linear_selector_namei|>add_next_wire_suffix)inletwitness=!![0;1]inletcircuit=letwires=Array.initPlompiler.Csir.nb_wires_arch(funj->ifj=2thenifi=2then[1;1]else[1;0]elseifj=ithen[0;1]else[0;0])inletgates=Circuit.make_gates~linear:[(2,![-1;0])]~linear_g:[(i,![1;0])]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letqm=letname="qm"inletwitness=!![0;1]inletcircuit=letwires=leta=[0;1]inletb=[1;1]inletc=[0;1]in[|a;b;c|]inletgates=Circuit.make_gates~qm:![1;1]~linear:[(2,![0;-1])]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letqx2b=letname="qx2b"inletwitness=!![0;-3;3;9]inletcircuit=letwires=leta=[0;0;0]inletb=[0;1;2]inletc=[0;3;3]in[|a;b;c|]inletgates=Circuit.make_gates~qx2b:![1;1;1]~linear:[(2,![0;-1;-1])]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letqx5a=letname="qx5a"inletwitness=!![0;2;32]inletcircuit=letwires=leta=[0;1]inletb=[0;0]inletc=[0;2]in[|a;b;c|]inletgates=Circuit.make_gates~qx5a:![1;1]~linear:[(2,![0;-1])]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letqx5c=letname="qx5c"inletwitness=!![0;243;3]inletcircuit=letwires=leta=[0;1]inletb=[0;0]inletc=[0;2]in[|a;b;c|]inletgates=Circuit.make_gates~qx5c:![1;1]~linear:[(0,![0;-1])]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letqecc_ws_add=letname="qecc_ws_add"in(* We check that: (3,1) + (4,4) = (2,2).
These are dummy points, they do not belong to a specific curve. *)letwitness=!![1;2;3;4]inletcircuit=letwires=leta=[2;0]inletb=[3;3]inletc=[1;1]in[|a;b;c|]inletgates=Circuit.make_gates~qecc_ws_add:![1;0]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letqecc_ed_add=letname="qecc_ed_add"inletwitness=!![0;1]inletcircuit=letwires=leta=[0;1]inletb=[0;1]inletc=[0;1]in[|a;b;c|]inletgates=Circuit.make_gates~qecc_ed_add:![1;0]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letqecc_ed_cond_add=letname="qecc_cond_ed_add"in(* In the first 2 constraints we are doing A(0;1) + 0B(2;3) = C(1;2);
in the other 2, A(0;1) + 1B(0;1) = C(0;1) *)letwitness=!![0;1;2;3]inletcircuit=letwires=leta=[0;0;1;0]inletb=[2;0;0;0]inletc=[3;0;1;0]inletd=[1;1;0;0]inlete=[2;2;1;1]in[|a;b;c;d;e|]inletgates=Circuit.make_gates~qecc_ed_cond_add:![1;0;1;0]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letqbool=letname="qbool"inletwitness=!![0;1]inletcircuit=letwires=leta=[0;1]inletb=[0;0]inletc=[0;0]in[|a;b;c|]inletgates=Circuit.make_gates~qbool:![1;1]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letqcond_swap=letname="qcond_swap"inletwitness=!![0;1;2]inletcircuit=letwires=leta=[0;1]inletb=[1;1]inletc=[2;2]inletd=[1;2]inlete=[2;1]in[|a;b;c;d;e|]inletgates=Circuit.make_gates~qcond_swap:![1;1]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letq_anemoi=letname="q_anemoi"inletx0="1"inlety0="1"inletx1="39027417478195954763090966714903261667484379123570980405377627458504913299628"inlety1="12807118572207854608879870979725669075358379219019309928321803168748017551407"inletx2="16347289160862248212893857406118677211322091184422502665988411845410114556281"inlety2="7279269625797671375403766084307099687590046281141194129086784189878517048332"inletkx1=Scalar.of_string"39"inletky1=Scalar.of_string"14981678621464625851270783002338847382197300714436467949315331057125308909900"inletkx2=Scalar.of_string"41362478282768062297187132445775312675360473883834860695283235286481594490621"inletky2=Scalar.of_string"28253420209785428420233456008091632509255652343634529984400816700490470131093"inletwitness=Array.mapScalar.of_string[|"0";x0;y0;x1;y1;x2;y2|]inletcircuit=letwires=leta=[0;0;0;0]inletb=[0;0;3;0]inletc=[0;0;4;0]inletd=[0;0;1;5]inlete=[0;0;2;6]in[|a;b;c;d;e|]inletprecomputed_advice=SMap.of_list[("qadv0",Scalar.[zero;zero;kx1;zero]);("qadv1",Scalar.[zero;zero;ky1;zero]);("qadv2",Scalar.[zero;zero;kx2;zero]);("qadv3",Scalar.[zero;zero;ky2;zero]);]inletgates=Circuit.make_gates~q_anemoi:Scalar.[zero;zero;one;zero]~linear:[(0,![1;1;0;0]);(1,![1;0;0;0])]~precomputed_advice()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letlist=letwires=List.initPlompiler.Csir.nb_wires_archFun.idin(qc::List.maplinear_selector_test(List.filter(funi->i<>2)wires))@List.mapnext_linear_selector_testwires@[qm;qx2b;qx5a;qx5c;qecc_ws_add;qecc_ed_add;qecc_ed_cond_add;qbool;qcond_swap;q_anemoi;]endmoduleGeneral_circuits=structletbnot=letname="bnot"inletwitness=!![0;1]inletcircuit=letwires=leta=[0;0]inletb=[0;0]inletc=[1;0]in[|a;b;c|]inletgates=Circuit.make_gates~linear:[(2,![-1;-1])]~qc:![1;0]()inCircuit.make~wires~gates~public_input_size:1()in{name;circuit;witness;outcome=Valid}letlist=[bnot]endmoduleGeneral=struct(* General tests *)(* Proving the relations
x10 = x0 + x1 * (x2 + x3 * (x4 + x5))
& P(x2, x0) + Q(x3, x3) = R(x1, x1)
Using intermediary variables:
x10 = x0 + x1 * (x2 + x3 * x6)
x10 = x0 + x1 * (x2 + x7)
x10 = x0 + x1 * x8
x10 = x0 + x9
<=>
Constraints:
1*x0 + 1*x9 - 1*x10 + 0*x0*x9 + 0 = 0
0*x1 + 0*x8 - 1*x9 + 1*x1*x8 + 0 = 0
1*x2 + 1*x7 - 1*x8 + 0*x2*x7 + 0 = 0
0*x3 + 0*x6 - 1*x7 + 1*x3*x6 + 0 = 0
1*x4 + 1*x5 - 1*x6 + 0*x4*x5 + 0 = 0
F_add_weirestrass(x2, x3, x1, x0, x3, x1) = 0
*)(* Base circuit proves that:
95 = 1 + 2 * (3 + 4 * (5 + 6))
with 1 public input
*)letwires=leta=[0;1;2;3;4;2;0]inletb=[9;8;7;6;5;3;3]inletc=[10;9;8;7;6;1;1]in[|a;b;c|]letgates=Circuit.make_gates~linear:[(0,![1;0;1;0;1;0;0]);(1,![1;0;1;0;1;0;0]);(2,![-1;-1;-1;-1;-1;0;0]);]~qm:![0;1;0;1;0;0;0]~qecc_ws_add:![0;0;0;0;0;1;0]()letcircuit=Circuit.make~wires~gates~public_input_size:1()letwitness=!![1;2;3;4;5;6;11;44;47;94;95]letzero_values=letname="zero_values"inletwitness=Array.make11(Scalar.of_int0)in{name;circuit;witness;outcome=Valid}letnon_zero_values=letname="non_zero_values"in{name;circuit;witness;outcome=Valid}(* Same test with no public inputs *)letno_public_inputs=letname="no_public_inputs"inletcircuit=Circuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letwrong_values=letname="wrong_values"inletwitness=!in{name;circuit;witness;outcome=Proof_error}letinput_com=letname="input_commitment"inletcircuit=Circuit.make~wires~gates~public_input_size:0~input_com_sizes:[3;1]()in{name;circuit;witness;outcome=Valid}letlist=[zero_values;non_zero_values;no_public_inputs;wrong_values;input_com]letlist_one_public_input=[zero_values;non_zero_values;wrong_values]endmoduleRange_Checks=structopenGeneralletpublic_input_size=0letvalid=letname="RC_single_valid"inletcircuit=Plonk.Circuit.make~wires~gates~public_input_size~range_checks:(SMap.of_list[("w0",[(4,4);(6,4)])])()in{name;circuit;witness;outcome=Valid}letwrong=letname="RC_single_wrong"inletcircuit=Plonk.Circuit.make~wires~gates~public_input_size~range_checks:(SMap.of_list[("w0",[(1,2);(3,4);(4,2)])])()in{name;circuit;witness;outcome=Proof_error}letbasic=letcircuit=(* This circuit takes x₁ & x₂ (given as first elements of d & e) as inputs and
rangechecks the outputs x₁ + x₂ & 3×x₁ + x₂ given in a
We also bound x₂ as the first value of e (in order to check bounds on other wires)
*)letgates=Circuit.make_gates~linear:[(0,![-1;-1]);(3,![1;3]);(4,![1;1])]()inletwires=[|[2;3];[0;0];[0;0];[0;0];[1;1]|]inCircuit.make~wires~gates~public_input_size:0~range_checks:(SMap.of_list[("w0",[(0,3);(1,4)]);("w4",[(0,2)])])()inletget_witnessx1x2=letx1=Scalar.of_intx1inletx2=Scalar.of_intx2inletx3=Scalar.(x1+x2)inletx4=Scalar.((of_int3*x1)+x2)in[|x1;x2;x3;x4|]inletwitness=get_witness43in{name="basic";circuit;witness;outcome=Valid}letlist=[valid;wrong;basic]endmoduleMod_Arith=structletadd_mod_25519?(valid=true)?(sub=false)case_name~x~y~z~qm~tj=letprefix=ifsubthen"sub"else"add"inletname=prefix^"_mod_2^255-19."^case_namein(* addition mod 2^255-19, we have;
|moduli| = [base] = [2^85]
qm_shift := -1
tj_shift := -32767
*)(* if there is no wrap-around, we will have qm = 1 and tj = 32767 *)(* if there is wrap-around 2^255 - 19, qm = 2 (so that qm + qm_shift = 1)
and tj = 32767 . *)letbase=Z.(shift_leftone85)inletxs=Plompiler.Utils.z_to_limbs~len:3~basexinletys=Plompiler.Utils.z_to_limbs~len:3~baseyinletzs=Plompiler.Utils.z_to_limbs~len:3~basezinletxs,zs=ifsubthen(zs,xs)else(xs,zs)inletwitness=(Z.zero::xs)@ys@[qm;tj]@zs|>List.mapScalar.of_z|>Array.of_listinletcircuit=letwires=leta=[1;9]inletb=[2;10]inletc=[3;11]inletd=[4;7]inlete=[5;8]inletf=[6;0]in[|a;b;c;d;e;f|]inletgates=Circuit.make_gates~q_mod_add:[("25519",![1;0])]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=(ifvalidthenValidelseProof_error)}letmod_add_tests_25519=let(!)=Z.of_intinletm=Z.(shift_leftone255-of_int19)inlettj=!32767inletsub=truein[add_mod_25519"no_wrap_around"~x:!5~y:!6~z:!11~qm:!1~tj;add_mod_25519"wrap_around"~x:Z.(m-!1)~y:!2~z:!1~qm:!2~tj;add_mod_25519"non-std out"~x:Z.(m-!1)~y:!4~z:Z.(m+!3)~qm:!1~tj;add_mod_25519~valid:false"invalid"~x:!0~y:!1~z:!2~qm:!1~tj;add_mod_25519~valid:false"invalid qm"~x:!1~y:!2~z:!3~qm:!0~tj;add_mod_25519~valid:false"invalid tj"~x:!1~y:!2~z:!3~qm:!1~tj:!0;add_mod_25519"no_wrap_around"~sub~x:!8~y:!2~z:!6~qm:!1~tj;add_mod_25519"wrap_around"~sub~x:!8~y:Z.(m-!2)~z:!10~qm:!2~tj;add_mod_25519~valid:false~sub"invalid"~x:!0~y:!1~z:!1~qm:!1~tj;]letadd_mod_64?(valid=true)?(sub=false)case_name~x~y~z~qm=letprefix=ifsubthen"sub"else"add"inletname=prefix^"_mod_2^64."^case_nameinletm=Z.(shift_leftone64)inletxs=Plompiler.Utils.z_to_limbs~len:1~base:mxinletys=Plompiler.Utils.z_to_limbs~len:1~base:myinletzs=Plompiler.Utils.z_to_limbs~len:1~base:mzinletxs,zs=ifsubthen(zs,xs)else(xs,zs)in(*
PlonK wires distribution:
row i : x0 y0 0 0 0 0
row i+1 : z0 qm 0 0 0 0
*)letwitness=(Z.zero::xs)@ys@[qm]@zs|>List.mapScalar.of_z|>Array.of_listinletcircuit=letwires=leta=[1;4]inletb=[2;3]inletc=[0;0]inletd=[0;0]inlete=[0;0]inletf=[0;0]in[|a;b;c;d;e;f|]inletgates=Circuit.make_gates~q_mod_add:[("64",![1;0])]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=(ifvalidthenValidelseProof_error)}letmod_add_tests_64=let(!)=Z.of_intinletm=Z.(shift_leftone64)inletsub=truein[add_mod_64"no_wrap_around"~x:!5~y:!6~z:!11~qm:!0;add_mod_64"wrap_around"~x:Z.(m-!1)~y:!2~z:!1~qm:!1;add_mod_64~valid:false"invalid"~x:!0~y:!1~z:!2~qm:!0;add_mod_64"no_wrap_around"~sub~x:!8~y:!2~z:!6~qm:!0;add_mod_64"wrap_around"~sub~x:!8~y:Z.(m-!2)~z:!10~qm:!1;add_mod_64~valid:false~sub"invalid"~x:!0~y:!1~z:!1~qm:!0;]letmul_mod_25519?(valid=true)?(div=false)case_name~x~y~z~qm~t1~t2=letprefix=ifdivthen"div"else"mul"inletname=prefix^"_mod_2^255-19."^case_namein(* multiplication mod 2^255-19, we have;
|moduli| = [base; base-1] = [2^85; 2^85-1]
qm_shift := -1
t1_shift := -1237940039285380274899123616
t2_shift := -1237940039285380274899123649
*)letbase=Z.(shift_leftone85)inletxs=Plompiler.Utils.z_to_limbs~len:3~basexinletys=Plompiler.Utils.z_to_limbs~len:3~baseyinletzs=Plompiler.Utils.z_to_limbs~len:3~basezinletxs,zs=ifdivthen(zs,xs)else(xs,zs)inletwitness=xs@ys@[qm;t1;t2]@zs|>List.mapScalar.of_z|>Array.of_listinletcircuit=letwires=leta=[0;9]inletb=[1;10]inletc=[2;11]inletd=[3;6]inlete=[4;7]inletf=[5;8]in[|a;b;c;d;e;f|]inletgates=Circuit.make_gates~q_mod_mul:[("25519",![1;0])]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=(ifvalidthenValidelseProof_error)}letmod_mul_tests_25519=let(!)=Z.of_intinletm=Z.(shift_leftone255-of_int19)in(* The correct t1, t2 when there is no wrap-around: *)lett1=Z.of_string"1237940039285380274899123616"inlett2=Z.of_string"1237940039285380274899123649"inletdiv=truein[mul_mod_25519"no_wrap_around"~x:!7~y:!13~z:!91~qm:!1~t1~t2;mul_mod_25519"wrap_around"~x:Z.(m-!1)~y:!2~z:Z.(m-!2)~qm:!2~t1~t2:(Z.of_string"1237940039285380274899123651");mul_mod_25519"non-std out"~x:Z.(m-!1)~y:Z.(m-!3)~z:Z.(m+!3)~qm:(Z.of_string"116056878683004400771792871")~t1:(Z.of_string"2630622583481433084160638332")~t2:(Z.of_string"3559077612945468290334981463");mul_mod_25519~valid:false"invalid"~x:!0~y:!1~z:!1~qm:!1~t1~t2;mul_mod_25519~valid:false"invalid qm"~x:!1~y:!2~z:!2~qm:!2~t1~t2;mul_mod_25519~valid:false"invalid t1"~x:!1~y:!2~z:!2~qm:!1~t1:!0~t2;mul_mod_25519~valid:false"invalid t2"~x:!1~y:!2~z:!2~qm:!1~t1~t2:!0;mul_mod_25519"no_wrap_around"~div~x:!9009~y:!9~z:!1001~qm:!1~t1~t2;mul_mod_25519"wrap_around"~div~x:!8~y:Z.(m-!2)~z:Z.(m-!4)~qm:(Z.of_string"116056878683004400771792870")~t1:(Z.of_string"2630622583481433084160638332")~t2:(Z.of_string"3559077612945468290334981461");mul_mod_25519"invalid"~valid:false~div~x:!10~y:!2~z:!3~qm:!1~t1~t2;]letmul_mod_64?(valid=true)case_name~x~y~z~qm=letname="mul_mod_2^64."^case_nameinletm=Z.(shift_leftone64)inletxs=Plompiler.Utils.z_to_limbs~len:1~base:mxinletys=Plompiler.Utils.z_to_limbs~len:1~base:myinletzs=Plompiler.Utils.z_to_limbs~len:1~base:mzinletwitness=(Z.zero::xs)@ys@[qm]@zs|>List.mapScalar.of_z|>Array.of_listinletcircuit=letwires=leta=[1;4]inletb=[2;3]inletc=[0;0]inletd=[0;0]inlete=[0;0]inletf=[0;0]in[|a;b;c;d;e;f|]inletgates=Circuit.make_gates~q_mod_mul:[("64",![1;0])]()inCircuit.make~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=(ifvalidthenValidelseProof_error)}letmod_mul_tests_64=let(!)=Z.of_intinletm=Z.(shift_leftone64)in[mul_mod_64"no_wrap_around"~x:!7~y:!13~z:!91~qm:!0;mul_mod_64"wrap_around"~x:Z.(m-!1)~y:!2~z:Z.(m-!2)~qm:!1;mul_mod_64~valid:false"invalid"~x:!0~y:!1~z:!1~qm:!1;mul_mod_64~valid:false"invalid qm"~x:!1~y:!2~z:!2~qm:!2;]letlist=mod_add_tests_25519@mod_add_tests_64@mod_mul_tests_25519@mod_mul_tests_64endmoduleBig_circuit=struct(* generates circuit with 2^k - 1 constraints that adds 2^(k + 1) inputs 4 by 4,
then adds 2^(k-1) inputs 2 by 2, then multiplies 2^(k-2) inputs 2 by 2, and
repeat the two last steps until there is 1 output left.
At each gate of the circuit, a random scalar is also added. There
is a total of k-1 layers of gates, i-th layer contains 2^i gates (starting
from the "output layer", numbering from 0 to i-1)
IMPORTANT : with aPlonK, this case is intended to fit PI_rollup_example
module, which means 2 public inputs and the first element of each witness
equal to the second element of the previous witness.
*)letmake~nb_proofs~public_input_size~k=letname=Format.sprintf"big_circuit.%i.%i"public_input_sizekinletlen_fst_layer=1lsl(k-1)in(* for wires d & e : [[d₁ ; e₁] ; [d₂ ; e₂] ; …]. They are handled
separately because they are only in the first gate & we don’t want to
involve them in the loop *)lete_d=Array.initlen_fst_layer(fun_->Scalar.[|random();random()|])inletwitnessnb_proofskqc=letrecbuild_w(acc_w_left,acc_w_right)=letl=List.hdacc_w_leftinletr=List.hdacc_w_rightinletlen_l=Array.lengthlinassert(Array.(len_l=lengthr));letop=ifList.lengthacc_w_leftmod2=0thenScalar.mulelseScalar.addinletadd_qci=leti_constraint=letlens=List.(fold_left(funil->i+Array.lengthl))0(acc_w_left@acc_w_right)inlens-(1lslk)+iinScalar.(addqc.(i_constraint))iniflen_l=1then(* We are at the last layer, there is only 1 gate left *)letlast=add_qc0(opl.(0)r.(0))inArray.(concatList.(revacc_w_left@revacc_w_right@[[|last|]]@to_liste_d))elseiflen_l=len_fst_layerthenletwl=Array.init(len_l/2)(funi->letj=2*iinadd_qcjScalar.(l.(j)+r.(j)+e_d.(j).(0)+e_d.(j).(1)))inletwr=Array.init(len_l/2)(funi->letj=(2*i)+1inadd_qcjScalar.(l.(j)+r.(j)+e_d.(j).(0)+e_d.(j).(1)))inbuild_w(wl::acc_w_left,wr::acc_w_right)elseletwl=Array.init(len_l/2)(funi->add_qc(2*i)(opl.(2*i)r.(2*i)))inletwr=Array.init(len_l/2)(funi->add_qc((2*i)+1)(opl.((2*i)+1)r.((2*i)+1)))inbuild_w(wl::acc_w_left,wr::acc_w_right)inletopenStdlib(* to recover the ! deref operator *)inletw0=ref(Scalar.random())inList.initnb_proofs(fun_->letw=letw_left=Array.initlen_fst_layer(funi->ifi=0then!w0elseScalar.random())inletw_right=Array.initlen_fst_layer(fun_->Scalar.random())inbuild_w([w_left],[w_right])inw0:=w.(1);w)inletn=(1lslk)-1inletqc=List.initn(fun_->Scalar.random())inletcircuit=letwires=letlast_c=2*ninleta=List.initnFun.idinletb=List.initn(funi->n+i)inletc=List.init(n/2)(funi->leti=(1lsl(k-1))+iin[i;n+i])@[[last_c]]|>List.concatinletd=List.initn(funi->ifi<len_fst_layerthenlast_c+((2*i)+1)else0)inlete=List.mapi(funix->ifi<len_fst_layerthenx+1else0)din[|a;b;c;d;e|]inletgates=letis_addkni=letdist=k-Z.(log2(of_int(Int.subni)))inifdistmod2=0thenfalseelsetrueinletqm=List.initn(funi->ifis_addknithen0else1)inletql=List.initn(funi->ifis_addknithen1else0)inletqr=qlinletqo=List.initn(fun_->-1)inletqd=List.initn(funi->ifi<1lsl(k-1)then1else0)inletqe=qdinCircuit.Circuit.make_gates~qm:!qm~linear:[(0,!ql);(1,!qr);(2,!qo);(3,!qd);(4,!qe)]~qc()inCircuit.make~wires~gates~public_input_size()inletwitnesses=witnessnb_proofsk(Array.of_listqc)inList.map(funwitness->{name;circuit;witness;outcome=Valid})witnessesletlist=make~nb_proofs:2~public_input_size:2~k:5letlist_slow=make~nb_proofs:2~public_input_size:2~k:16endletlist=Unit_tests_for_each_selector.list@General_circuits.list@General.list@Mod_Arith.list@Big_circuit.listletlist_slow=Big_circuit.list_slowmoduleLookup=struct(* Tables corresponding to addition of digits mod m to perform tests on. *)lettable_add_mod_mm=letm2=m*minlett_1=List.initm2(funi->i/m)inlett_2=List.initm2(funi->imodm)inlett_3=List.initm2(funi->((i/m)+i)modm)in[!!t_1;!!t_2;!!t_3]lettable_add_mod_5=table_add_mod_m5lettable_add_mod_10=table_add_mod_m10(* ---- Unit tests for each selector. ---- *)letqplookup=letname="qplookup"inletwitness=!![0;1;2]inletcircuit=leta=[1]inletb=[1]inletc=[2]inletwires=[|a;b;c|]inletgates=Circuit.make_gates~q_plookup:![1]~q_table:![0]()inlettables=[table_add_mod_5]inCircuit.make~tables~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}(* ---- Test with 2 tables. ---- *)letqplookup_two_tables=letname="qplookup_two_tables"inletwitness=!![0;1;3;9]inletcircuit=letwires=leta=[2;3]inletb=[2;1]inletc=[1;0]in[|a;b;c|]inletgates=Circuit.make_gates~q_plookup:![1;1]~q_table:![0;1]()inlettables=[table_add_mod_5;table_add_mod_10]inCircuit.make~tables~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}(* ---- General test with correct and incorrect witness. ---- *)letwires=leta=[1;1;4;2;4;3;1]inletb=[2;1;2;2;3;4;4]inletc=[3;1;1;4;2;2;2]in[|a;b;c|]letgates=Circuit.make_gates~linear:[(2,![0;-1;0;-1;0;0;0])]~qm:![0;1;0;1;0;0;0]~qecc_ws_add:![0;0;0;0;0;1;0]~q_plookup:![1;0;1;0;1;0;0]~q_table:![0;0;0;0;0;0;0]()lettables=[table_add_mod_5]letcircuit=(* Proving the relations with addition mod 5 using lookups
x8 = x7 + x1 * (x3 + x4 * (x5 + x6))
R(x2, x2) = P(x3, x1) + Q(x4, x4) <- these are dummy points
with 1 public input
<=>
Constraints:
lookup: x1 (+) x7 = x8
1*x1*x7 - 1*x7 = 0
lookup: x3 (+) x4 = x7
1*x4*x1 - x4 = 0
lookup: x5 (+) x6 = x1
F_add_weirestrass(x3, x4, x2, x1, x4, x2) = 0
*)Circuit.make~tables~wires~gates~public_input_size:1()(* Base witness proves that:
3 = 2 + 1 * (2 + 2 * (3 + 4)) addition modulo 5
R(2,2) = P(3,1) + Q(4,4) weierstrass point addition
*)letwitness=!![0;1;2;3;4]letlookup_zero_values=letname="lookup_zero_values"inletwitness=!!(List.init5(fun_i->0))in{name;circuit;witness;outcome=Valid}letlookup_non_zero_values=letname="lookup_non_zero_values"in{name;circuit;witness;outcome=Valid}letlookup_no_public_inputs=letname="lookup_no_public_inputs"inletcircuit=Circuit.make~tables~wires~gates~public_input_size:0()in{name;circuit;witness;outcome=Valid}letlookup_wrong_arith_values=letname="lookup_wrong_arith_values"inletwires=leta=[1;1;4;2;4;3;1]inletb=[2;1;2;2;3;4;4]inletc=[3;1;1;3;2;2;2]in[|a;b;c|](* """mistake""" here in arith. constraint *)inletcircuit=Circuit.make~tables~wires~gates~public_input_size:1()in{name;circuit;witness;outcome=Proof_error}letwrong_plookup_values=letname="wrong_plookup_values"inletwires=leta=[0;1;4;2;4;3;1]inletb=[2;1;2;2;3;4;4]inletc=[3;1;1;4;2;2;2]in[|a;b;c|](* """mistake""" here in lookup constraint *)inletcircuit=Circuit.make~tables~wires~gates~public_input_size:1()in{name;circuit;witness;outcome=Lookup_error}letlist=[qplookup;qplookup_two_tables;lookup_zero_values;lookup_non_zero_values;lookup_no_public_inputs;lookup_wrong_arith_values;wrong_plookup_values;]end