123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359(*****************************************************************************)(* *)(* MIT License *)(* Copyright (c) 2022 Nomadic Labs <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)(** A polynomial protocol allows a prover to convince a verifier of the fact
that certain algebraic identites between polynomials (polynomials that have
been previously committed) hold when evaluated over a set of points.
(In our implementation such set of points must be a subgroup of roots of
unity.)
For example, let K be a field and let H be a subset of K.
Let f1(X), f2(X) and f3(X) be univariate polynomials over K and let
C1, C2 and C3 be polynomial commitments to f1, f2 and f3, respectively.
A polynomial protocol allows a prover to argue knowledge of:
{[
PoK{ (f1, f2, f3) : Ci = Com(fi) ∀ i /\ f1(x) * f2(x) = f3(x) ∀ x ∈ H }
]}
This can be accomplished by evaluating polynomial commitments at a single
point ξ (uniformly sampled from K). For that, note that the above
polynomial identity holds for every x ∈ H iff polynomial (f1 * f2 - f3) is
divisible by Zh, the minimal (monic) polynomial that vanishes over set H.
Thus, the prover can commit to polynomial T := (f1 * f2 - f3) / Zh and
evaluate polynomial commitments C1, C2, C3, T at ξ (chosen after T). Let
c1, c2, c3, t be such evaluations.
The verifier can then check that t * Zh(ξ) = c1 * c2 - c3.
A general polynomial protocol should allow for multiple identities involving
addition, multiplication and composition of polynomials.
See {{: https://eprint.iacr.org/2019/953.pdf }2019/953 Section 4.1} for
more details. *)(** Functor building an implementation of a polynomial protocol given a
polynomial commitment scheme [PC]. *)moduleMake_impl(PC:Polynomial_commitment.S)=structmodulePC=PCmoduleDomain=PC.Polynomial.DomainmodulePoly=PC.Polynomial.PolynomialmoduleEvaluations=Evaluations_map.Make(PC.Polynomial.Evaluations)moduleFr_generation=PC.Fr_generationtypeprover_public_parameters=PC.Public_parameters.prover[@@derivingrepr]typeverifier_public_parameters=PC.Public_parameters.verifier[@@derivingrepr]typeprover_identities=Evaluations.tSMap.t->Evaluations.tSMap.ttypeverifier_identities=PC.Scalar.t->PC.Scalar.tSMap.tSMap.t->PC.Scalar.tSMap.ttypenon_committed=PC.Scalar.t->PC.Scalar.tSMap.tSMap.t->PC.Scalar.tSMap.ttypetranscript=Bytes.t[@@derivingrepr]typeproof={cm_t:PC.Commitment.t;pc_proof:PC.proof;pc_answers:PC.answerlist;}[@@derivingrepr]typeeval_point=X|GX|Customofstring*(PC.Scalar.t->PC.Scalar.t)letstring_of_eval_point=function|X->"x"|GX->"gx"|Custom(s,_)->sletconvert_eval_points~generator~xl=leteval=function|X->x|GX->PC.Scalar.mulgeneratorx|Custom(_,f)->fxinSMap.of_list@@List.map(funp->(string_of_eval_pointp,evalp))lletget_answeranswersxn=SMap.find(string_of_eval_pointx)answers|>SMap.findnletmerge_prover_identitiesidentities_list:prover_identities=funevaluations->List.fold_left(funacc_mapids->SMap.union_disjointacc_map(idsevaluations))SMap.emptyidentities_listletmerge_verifier_identitiesidentities_list:verifier_identities=funxanswers->List.fold_left(funacc_mapids->SMap.union_disjointacc_map(idsxanswers))SMap.emptyidentities_listletsplit_tntnb_of_t_chunks=List.mapi(funit_i->("T_"^string_of_inti,t_i))(Poly.split~nb_chunks:nb_of_t_chunksnt)|>SMap.of_listletcompute_t~n~alpha~nb_of_t_chunksevaluated_identities=letnb_ids=SMap.cardinalevaluated_identitiesinletevaluations=List.mapsnd@@SMap.bindingsevaluated_identitiesinletalphas=Fr_generation.powersnb_idsalpha|>Array.to_listinlets_eval=Evaluations.linear_c~evaluations~linear_coeffs:alphas()inlets_deg=Evaluations.degrees_evalinletdomain=Domain.build_power_of_two(Z.log2up(Z.of_int(s_deg+1)))inlets=Evaluations.interpolation_fftdomains_evalinlett,rem=Poly.division_xnsnPC.Scalar.(negateone)inifPoly.is_zeroremthen(letsplits=split_tntnb_of_t_chunksinassert(SMap.for_all(fun_kv->Poly.degreev<n)splits);splits)elseraise@@Poly.Rest_not_null"T is not divisible by Zh"letverify_tnxalphaevaluated_identitiescm_tanswers=letvalues=List.mapsnd@@SMap.bindingsevaluated_identitiesinlets=Fr_generation.batchalphavaluesinlett_val=letx_evals=SMap.find(string_of_eval_pointX)answersinletnb_t=PC.Commitment.cardinalcm_tinList.initnb_t(funi->SMap.find("T_"^string_of_inti)x_evals)|>Fr_generation.batch(PC.Scalar.powx(Z.of_intn))inletzh=PC.Scalar.(sub(powx(Z.of_intn))one)inPC.Scalar.(eqs(t_val*zh))letsetup~setup_params~srs=PC.Public_parameters.setupsetup_paramssrsletprove_aux~pc_functionpc_public_parameterstranscriptngeneratorsecretseval_pointsevaluationsidentitiesnb_of_t_chunks=letalpha,transcript=Fr_generation.random_frtranscriptinletevaluated_ids=identitiesevaluationsinlett=compute_t~n~alpha~nb_of_t_chunksevaluated_idsinletcm_t,t_prover_aux=PC.Commitment.commitpc_public_parameterstinlettranscript=Utils.expand_transcriptPC.Commitment.tcm_ttranscriptinletx,transcript=Fr_generation.random_frtranscriptinletprover_aux_list=t_prover_aux::List.mapsndsecretsinletpolys_list=t::List.mapfstsecretsinleteval_points=[X]::eval_pointsinletquery_list=List.map(convert_eval_points~generator~x)eval_pointsinletanswer_list=List.map2PC.evaluatepolys_listquery_listinletpc_ret=pc_functionpc_public_parameterstranscriptpolys_listprover_aux_listquery_listanswer_listin(pc_ret,(alpha,x,answer_list,cm_t))letprovepc_public_parameterstranscript~n~generator~secrets~eval_points~evaluations~identities~nb_of_t_chunks=let(pc_proof,transcript),(_,_,answer_list,cm_t)=prove_aux~pc_function:PC.provepc_public_parameterstranscriptngeneratorsecretseval_pointsevaluationsidentitiesnb_of_t_chunksin({cm_t;pc_proof;pc_answers=answer_list},transcript)typepp_commit_to_t_r=Evaluations.tSMap.t[@@derivingrepr]letverify_auxtranscriptgeneratorcommitmentseval_pointsproof=letalpha,transcript=Fr_generation.random_frtranscriptinlettranscript=Utils.expand_transcriptPC.Commitment.tproof.cm_ttranscriptinletx,transcript=Fr_generation.random_frtranscriptinletcm_list=proof.cm_t::commitmentsinleteval_points=[X]::eval_pointsinletquery_list=List.map(convert_eval_points~generator~x)eval_pointsin(alpha,x,transcript,cm_list,query_list)letverifypc_public_parameterstranscript~n~generator~commitments~eval_points?(non_committed=fun__->SMap.empty)~identitiesproof=letalpha,x,transcript,cmts,query_list=verify_auxtranscriptgeneratorcommitmentseval_pointsproofinletpc_verif,transcript=PC.verifypc_public_parameterstranscriptcmtsquery_listproof.pc_answersproof.pc_proofinletanswers=letf_keym1m2=Some(SMap.union_disjointm1m2)inletanswers=List.fold_left(SMap.unionf)SMap.emptyproof.pc_answersinletnc_answers=non_committedxanswers|>SMap.singleton(string_of_eval_pointX)inSMap.unionfanswersnc_answersinletevaluated_ids=identitiesxanswersinlett_verif=verify_tnxalphaevaluated_idsproof.cm_tanswersin(pc_verif&&t_verif,transcript)end(** Output signature of the functor [Polynomial_protocol.Make]. *)moduletypeS=sigmodulePC:Polynomial_commitment.S(** Underlying polynomial commitment scheme on which the polynomial protocol
is based. Input of the functor [Polynomial_protocol.Make]. *)(** Module to operate with polynomials in FFT evaluations form. *)moduleEvaluations:Evaluations_map.Evaluations_sigwithtypescalar:=PC.Scalar.tandtypedomain=PC.Polynomial.Domain.tandtypepolynomial=PC.Polynomial.Polynomial.tandtypet=PC.Polynomial.Evaluations.ttypeprover_public_parameters=PC.Public_parameters.prover[@@derivingrepr](** The type of prover public parameters. *)typeverifier_public_parameters=PC.Public_parameters.verifier[@@derivingrepr](** The type of verifier public parameters. *)typeprover_identities=Evaluations.tSMap.t->Evaluations.tSMap.t(** The type for prover identities: functions from a (string) map of
polynomials in FFT evaluations form to a (string) map of evaluated
identities (also polynomials in FFT evaluations form). *)typeverifier_identities=PC.Scalar.t->PC.Scalar.tSMap.tSMap.t->PC.Scalar.tSMap.t(** The type for verifier identities: functions which map an evaluation point
ξ an a [PC.answer] into a (string) map of evaluated identities. *)typenon_committed=PC.Scalar.t->PC.Scalar.tSMap.tSMap.t->PC.Scalar.tSMap.t(** A type to involve in the identities computations corresponding to
(public) polynomials that have not been committed by the prover.
It maps an evaluation point ξ and a [PC.answer] into a (string) map
of evaluated (non-committed) polynomials. *)typetranscript=PC.transcript[@@derivingrepr](** The type for transcripts, used for applying the Fiat-Shamir heuristic *)typeproof={cm_t:PC.Commitment.t;pc_proof:PC.proof;pc_answers:PC.answerlist;}[@@derivingrepr](** The type for proofs, containing a commitment to the polynomial T that
asserts the satisfiability of the identities over the subset of interest,
as well as a [PC] proof and a list of [PC] answers. *)(** The type for evaluation points. Either [X], [GX], or a custom point,
which must be specified by an evaluation point name paired with a
function that computes it from ξ. For example:
- [X] could be implemented as [Custom ("x", Fun.id)]
- [GX] could be implemented as
[Custom ("gx", fun x -> Scalar.mul generator x)]. *)typeeval_point=X|GX|Customofstring*(PC.Scalar.t->PC.Scalar.t)valconvert_eval_points:generator:PC.Scalar.t->x:PC.Scalar.t->eval_pointlist->PC.Scalar.tSMap.t(** [convert_eval_points gen x points] maps the polynomial protocol
[points : eval_point list] into scalars, by evaluating the underlying
"composition" polynomial at [x].
The generator [gen] is used in case the [eval_point] equals [GX], in
which case the resulting scalar is [x * gen]. *)valget_answer:PC.answer->eval_point->string->PC.Scalar.t(** [get_answer answers p name] extracts the evaluation of polynomial [name]
at point [p] from the given [answers]. *)valmerge_prover_identities:prover_identitieslist->prover_identities(** A function to merge a list of prover identities into one. *)valmerge_verifier_identities:verifier_identitieslist->verifier_identities(** A function to merge a list of verifier identities into one. *)valcompute_t:n:int->alpha:PC.Scalar.t->nb_of_t_chunks:int->Evaluations.tSMap.t->Evaluations.polynomialSMap.t(** [compute_t ~n ~alpha evaluations] returns a polynomial T splitted in chunks,
where [T(X) = (sum_i alpha^i evaluations[i]) / (X^n - 1)] and the returned
chunks [{ 'T_0' -> T0; 'T_1' -> T1; 'T_2' -> T2 }] are such that
[T = T0 + X^n T1 + X^{2n} T2]. *)valsetup:setup_params:PC.Public_parameters.setup_params->srs:Bls12_381_polynomial.Srs.t*Bls12_381_polynomial.Srs.t->prover_public_parameters*verifier_public_parameters(** The polynomial commitment setup function, requires a labeled
argument of setup parameters for the underlying [PC] and a labeled
argument containing the path location of a set of SRS files. *)valprove:prover_public_parameters->transcript->n:int->generator:PC.Scalar.t->secrets:(PC.Polynomial.Polynomial.tSMap.t*PC.Commitment.prover_aux)list->eval_points:eval_pointlistlist->evaluations:Evaluations.tSMap.t->identities:prover_identities->nb_of_t_chunks:int->proof*transcript(** The prover function. Takes as input the [prover_public_parameters],
an initial [transcript] (possibly including a context if this [prove] is
used as a building block of a bigger protocol), the size [n] of subgroup H,
the canonical [generator] of subgroup H, a list of [secrets] including
polynomials that have supposedly been committed (and a verifier received
such commitments) as well as prover auxiliary information generated
during the committing process, a list of evaluation point lists specifying
the evaluation points where each secret needs to be evaluated at,
a map of the above-mentioned polynomials this time in FFT [evaluations] form,
for efficient polynomial multiplication, and some [prover_identities] that
are supposedly satisfied by the secret polynomials.
Outputs a proof and an updated transcript. *)valverify:verifier_public_parameters->transcript->n:int->generator:PC.Scalar.t->commitments:PC.Commitment.tlist->eval_points:eval_pointlistlist->?non_committed:non_committed->identities:verifier_identities->proof->bool*transcript(** The verifier function. Takes as input the [verifier_public_parameters],
an initial [transcript] (that should coincide with the initial transcript
used by [prove]), the size [n] of subgroup H, the canonical [generator] of
subgroup H, a list of [commitments] to the secret polynomials by the prover,
a list of evaluation points as in [prove], some [verifier_identities], and
a [proof].
Outputs a [bool] value representing acceptance or rejection. *)endmoduleMake:functor(PC:Polynomial_commitment.S)->SwithmodulePC=PC=Make_implincludeMake(Polynomial_commitment)