123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130(*****************************************************************************)(* *)(* Copyright (c) 2021 Danny Willems <be.danny.willems@gmail.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. *)(* *)(*****************************************************************************)moduletypeSIGNATURE_SCHEME=sigtypesecret_keytypepublic_keytypesignaturevalsignature_to_bytes:signature->Bytes.tvalsign:secret_key->Bytes.t->signaturevalsign_deterministic:Bytes.t->secret_key->Bytes.t->signaturevalverify:public_key->Bytes.t->signature->boolendmoduleMakeRedDSA(Ec:Ec_sig.AffineEdwardsT)(Param:sigvallength:intvalhash:Bytes.t->Bytes.tvalgenerator:Ec.tvalto_compressed:Ec.t->Bytes.tvalof_compressed_opt:Bytes.t->Ec.toptionend)=structlet()=ifParam.lengthmod8<>0thenfailwith"Length must be a multiple of 8"lethash_starbytes=letlimbs=Param.hashbytesinEc.Scalar.of_bytes_exnlimbstypesecret_key=Ec.Scalar.ttypepublic_key=Ec.ttypesignature={r:Bytes.t;s:Bytes.t}letsignature_to_bytessignature=Bytes.concatBytes.empty[signature.r;signature.s]letsign_deterministicrandomnessskmessage=(* length is given in bits *)letlength=(Param.length+128)/8inassert(Bytes.lengthrandomness=length);(* IMPORTANT!!!
r = H*(T || vk || M) --> This is the spec in the Sapling PDF. However,
the reference implementation do not use the vk:
- https://github.com/zcash/librustzcash/blob/da431a0eb207f69c9b0631d7d02136d819e1bfd9/zcash_primitives/src/sapling/redjubjub.rs#L80
- https://github.com/zcash/librustzcash/blob/da431a0eb207f69c9b0631d7d02136d819e1bfd9/zcash_primitives/src/sapling/util.rs#L9
- https://github.com/zcash/librustzcash/issues/179
*)letr=hash_star(Bytes.concatBytes.empty[randomness;message])in(* R = r . P *)letp_r=Ec.mulParam.generatorrin(* Get the little endian encoding of the point R *)letp_r_le=Param.to_compressedp_rin(* s = r + sk . H*(LE(P) || M) *)lets=hash_star(Bytes.concatBytes.empty[p_r_le;message])inlets=Ec.Scalar.(sk*s)inlets=Ec.Scalar.(r+s)in(* R || S *){r=p_r_le;s=Ec.Scalar.to_bytess}letsignskmessage=(* Generate T, length + 128 bits *)lett=Bytes.init((Param.length+128)/8)(fun_->char_of_int(Random.int256))insign_deterministictskmessageletverifyvkmessagesignature=(* we do not have to check the first condition as it is an invariant of the
type signature
*)letr=Param.of_compressed_optsignature.rinlets=Z.of_bits(Bytes.to_stringsignature.s)in(* The Sapling PDF does use vk in the hash, but not the reference
implementation of zcash. Therefore, ignoring it
- https://github.com/zcash/librustzcash/blob/da431a0eb207f69c9b0631d7d02136d819e1bfd9/zcash_primitives/src/sapling/redjubjub.rs#L80
- https://github.com/zcash/librustzcash/blob/da431a0eb207f69c9b0631d7d02136d819e1bfd9/zcash_primitives/src/sapling/util.rs#L9
- https://github.com/zcash/librustzcash/issues/179
*)letc=hash_star(Bytes.concatBytes.empty[signature.r;message])in(* FIXME: not constant time!! Like everything... *)matchrwith|None->false|Somer->lets_leq_r=Z.(leqsEc.Scalar.order)in(* [c] * vk *)letc_vk=Ec.(mulvkc)in(* [S] * P_G *)lets_p_g=Ec.(mulParam.generator(Scalar.of_zs))in(* -[S] * P_G + R + [c] vk *)letres=Ec.(add(add(negates_p_g)r)c_vk)in(* multiply by the cofactor -> [h_G] res *)letres=Ec.(mulres(Scalar.of_zcofactor))inletres_is_null=Ec.is_zeroresins_leq_r&&res_is_nullend