123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117(***********************************************************************)(* *)(* The Cryptokit library *)(* *)(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)(* *)(* Copyright 2002 Institut National de Recherche en Informatique et *)(* en Automatique. All rights reserved. This file is distributed *)(* under the terms of the GNU Library General Public License, with *)(* the special exception on linking described in file LICENSE. *)(* *)(***********************************************************************)(* Arithmetic on big integers, based on the ZArith library. *)typet=Z.texternalwipe:t->unit="caml_wipe_z"letzero=Z.zeroletone=Z.oneletof_int=Z.of_intletcompare=Z.compareletadd=Z.addletsub=Z.subletmult=Z.mulletmod_=Z.remletrelative_primeab=Z.equal(Z.gcdab)Z.oneletmod_power=Z.powm_secletsub_modabp=letd=Z.subabinifZ.signd<0thenZ.adddpelsed(* Modular exponentiation via the Chinese Remainder Theorem.
Compute a ^ d mod pq, where d is defined by
dp = d mod (p-1) and dq = d mod (q-1).
qinv is q^-1 mod p.
Formula:
mp = (a mod p)^dp mod p
mq = (a mod q)^dq mod q
m = ((((mp - mq) mod p) * qInv) mod p) * q + mq
*)letmod_power_CRTapqdpdqqinv=letamodp=Z.remapandamodq=Z.remaqinletmp=mod_poweramodpdppandmq=mod_poweramodqdqqinletdiff=sub_modmpmqpinletdiff_qinv=Z.muldiffqinvinletdiff_qinv_mod_p=Z.remdiff_qinvpinletres=Z.(add(mulqdiff_qinv_mod_p)mq)inwipeamodp;wipeamodq;(* It is possible that res == mq, so we cannot wipe mq.
For consistency we don't wipe any of the intermediate results
besides amodp and amodq. *)resletmod_inv=Z.invertletwipe_bytess=Bytes.fills0(Bytes.lengths)'\000'letof_bytess=letl=String.lengthsinlett=Bytes.createlinfori=0tol-1doBytes.settis.[l-1-i]done;letn=Z.of_bits(Bytes.unsafe_to_stringt)inwipe_bytest;nletto_bytes?numbitsn=lets=Z.to_bitsninletl=matchnumbitswith|None->String.lengths|Somenb->assert(Z.numbitsn<=nb);(nb+7)/8inlett=Bytes.makel'\000'infori=0toString.lengths-1doBytes.sett(l-1-i)s.[i]done;wipe_bytes(Bytes.unsafe_of_strings);Bytes.unsafe_to_stringtletchange_bytesif=Bytes.setsi(Char.chr(f(Char.code(Bytes.getsi))))letrandom~rng?(odd=false)numbits=letnumbytes=(numbits+7)/8inletbuf=Bytes.createnumbytesinrngbuf0numbytes;(* adjust low byte if requested *)ifoddthenchange_bytebuf0(funb->blor1);(* adjust high byte so that the number is exactly numbits long *)letmask=1lsl((numbits-1)land7)inchange_bytebuf(numbytes-1)(funb->(bland(mask-1))lormask);(* convert to a number *)letn=Z.of_bits(Bytes.unsafe_to_stringbuf)inwipe_bytesbuf;assert(Z.numbitsn=numbits);ifoddthenassert(Z.is_oddn);nletrecrandom_prime~rngnumbits=(* Generate random odd number *)letn=random~rng~odd:truenumbitsin(* Find next prime above n *)letp=Z.nextprimenin(* Make sure it has the right number of bits *)ifZ.numbitsp=numbitsthenpelserandom_prime~rngnumbits