{-# LINE 1 "OpenSSL/BN.hsc" #-}{-# LANGUAGE ForeignFunctionInterface #-}{-# LINE 2 "OpenSSL/BN.hsc" #-}{-# LINE 4 "OpenSSL/BN.hsc" #-}{-# OPTIONS_HADDOCK prune #-}-- |BN - multiprecision integer arithmeticsmoduleOpenSSL.BN(-- * TypeBigNum,BIGNUM-- * Allocation,allocaBN,withBN,newBN,wrapBN-- private,unwrapBN-- private-- * Conversion from\/to Integer,peekBN{-# LINE 25 "OpenSSL/BN.hsc" #-},integerToBN,bnToInteger{-# LINE 28 "OpenSSL/BN.hsc" #-},integerToMPI,mpiToInteger-- * Computation,modexp-- * Random number generation,randIntegerUptoNMinusOneSuchThat,prandIntegerUptoNMinusOneSuchThat,randIntegerZeroToNMinusOne,prandIntegerZeroToNMinusOne,randIntegerOneToNMinusOne,prandIntegerOneToNMinusOne)whereimportControl.Exceptionhiding(try)importForeignimportqualifiedData.ByteStringasBSimportOpenSSL.Utils{-# LINE 53 "OpenSSL/BN.hsc" #-}importForeign.C.TypesimportGHC.Base{-# LINE 61 "OpenSSL/BN.hsc" #-}importGHC.Integer.GMP.Internals{-# LINE 63 "OpenSSL/BN.hsc" #-}{-# LINE 64 "OpenSSL/BN.hsc" #-}-- |'BigNum' is an opaque object representing a big number.newtypeBigNum=BigNum(PtrBIGNUM)dataBIGNUMforeignimportccallunsafe"BN_new"_new::IO(PtrBIGNUM)foreignimportccallunsafe"BN_free"_free::PtrBIGNUM->IO()-- |@'allocaBN' f@ allocates a 'BigNum' and computes @f@. Then it-- frees the 'BigNum'.allocaBN::(BigNum->IOa)->IOaallocaBNm=bracket_new_free(m.wrapBN)unwrapBN::BigNum->PtrBIGNUMunwrapBN(BigNump)=pwrapBN::PtrBIGNUM->BigNumwrapBN=BigNum{-# LINE 136 "OpenSSL/BN.hsc" #-}{- fast, dangerous functions ------------------------------------------------ -}-- Both BN (the OpenSSL library) and GMP (used by GHC) use the same internal-- representation for numbers: an array of words, least-significant first. Thus-- we can move from Integer's to BIGNUMs very quickly: by copying in the worst-- case and by just alloca'ing and pointing into the Integer in the fast case.-- Note that, in the fast case, it's very important that any foreign function-- calls be "unsafe", that is, they don't call back into Haskell. Otherwise the-- GC could do nasty things to the data which we thought that we had a pointer-- toforeignimportccallunsafe"memcpy"_copy_in::ByteArray#->Ptr()->CSize->IO()foreignimportccallunsafe"memcpy"_copy_out::Ptr()->ByteArray#->CSize->IO()-- These are taken from Data.Binary's disabled fast Integer supportdataByteArray=BA{-# UNPACK #-}!ByteArray#dataMBA=MBA{-# UNPACK #-}!(MutableByteArray#RealWorld)newByteArray::Int#->IOMBAnewByteArraysz=IO$\s->casenewByteArray#szsof{(#s',arr#)->(#s',MBAarr#)}freezeByteArray::MutableByteArray#RealWorld->IOByteArrayfreezeByteArrayarr=IO$\s->caseunsafeFreezeByteArray#arrsof{(#s',arr'#)->(#s',BAarr'#)}-- | Convert a BIGNUM to an IntegerbnToInteger::BigNum->IOIntegerbnToIntegerbn=donlimbs<-((\hsc_ptr->peekByteOffhsc_ptr4))(unwrapBNbn)::IOCInt{-# LINE 172 "OpenSSL/BN.hsc" #-}casenlimbsof0->return01->do(I#i)<-((\hsc_ptr->peekByteOffhsc_ptr0))(unwrapBNbn)>>=peek{-# LINE 175 "OpenSSL/BN.hsc" #-}negative<-((\hsc_ptr->peekByteOffhsc_ptr12))(unwrapBNbn)::IOCInt{-# LINE 176 "OpenSSL/BN.hsc" #-}ifnegative==0thenreturn$S#ielsereturn$0-(S#i)_->dolet!(I#nlimbsi)=fromIntegralnlimbs!(I#limbsize)=((4)){-# LINE 182 "OpenSSL/BN.hsc" #-}(MBAarr)<-newByteArray(nlimbsi*#limbsize)(BAba)<-freezeByteArrayarrlimbs<-((\hsc_ptr->peekByteOffhsc_ptr0))(unwrapBNbn){-# LINE 185 "OpenSSL/BN.hsc" #-}_copy_inbalimbs$fromIntegral$nlimbs*((4)){-# LINE 186 "OpenSSL/BN.hsc" #-}negative<-((\hsc_ptr->peekByteOffhsc_ptr12))(unwrapBNbn)::IOCInt{-# LINE 187 "OpenSSL/BN.hsc" #-}ifnegative==0thenreturn$J#nlimbsibaelsereturn$0-(J#nlimbsiba)-- | This is a GHC specific, fast conversion between Integers and OpenSSL-- bignums. It returns a malloced BigNum.integerToBN::Integer->IOBigNumintegerToBN(S#0#)=dobnptr<-mallocBytes((20)){-# LINE 196 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr0))bnptrnullPtr{-# LINE 197 "OpenSSL/BN.hsc" #-}-- This is needed to give GHC enough type informationletone::CIntone=1zero::CIntzero=0((\hsc_ptr->pokeByteOffhsc_ptr16))bnptrone{-# LINE 203 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr4))bnptrzero{-# LINE 204 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr8))bnptrzero{-# LINE 205 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr12))bnptrzero{-# LINE 206 "OpenSSL/BN.hsc" #-}return(wrapBNbnptr)integerToBN(S#v)=dobnptr<-mallocBytes((20)){-# LINE 210 "OpenSSL/BN.hsc" #-}limbs<-malloc::IO(PtrCULong)pokelimbs$fromIntegral$abs$I#v((\hsc_ptr->pokeByteOffhsc_ptr0))bnptrlimbs{-# LINE 213 "OpenSSL/BN.hsc" #-}-- This is needed to give GHC enough type information since #poke just-- uses an offsetletone::CIntone=1((\hsc_ptr->pokeByteOffhsc_ptr16))bnptrone{-# LINE 218 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr4))bnptrone{-# LINE 219 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr8))bnptrone{-# LINE 220 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr12))bnptr(if(I#v)<0thenoneelse0){-# LINE 221 "OpenSSL/BN.hsc" #-}return(wrapBNbnptr)integerToBNv@(J#nlimbs_bytearray)|v>=0=doletnlimbs=(I#nlimbs_)bnptr<-mallocBytes((20)){-# LINE 227 "OpenSSL/BN.hsc" #-}limbs<-mallocBytes(((4))*nlimbs){-# LINE 228 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr0))bnptrlimbs{-# LINE 229 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr16))bnptr(1::CInt){-# LINE 230 "OpenSSL/BN.hsc" #-}_copy_outlimbsbytearray(fromIntegral$((4))*nlimbs){-# LINE 231 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr4))bnptr((fromIntegralnlimbs)::CInt){-# LINE 232 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr8))bnptr((fromIntegralnlimbs)::CInt){-# LINE 233 "OpenSSL/BN.hsc" #-}((\hsc_ptr->pokeByteOffhsc_ptr12))bnptr(0::CInt){-# LINE 234 "OpenSSL/BN.hsc" #-}return(wrapBNbnptr)|otherwise=dobnptr<-integerToBN(0-v)((\hsc_ptr->pokeByteOffhsc_ptr12))(unwrapBNbnptr)(1::CInt){-# LINE 237 "OpenSSL/BN.hsc" #-}returnbnptr-- TODO: we could make a function which doesn't even allocate BN data if we-- wanted to be very fast and dangerout. The BIGNUM could point right into the-- Integer's data. However, I'm not sure about the semantics of the GC; which-- might move the Integer data around.-- |@'withBN' n f@ converts n to a 'BigNum' and computes @f@. Then it-- frees the 'BigNum'.withBN::Integer->(BigNum->IOa)->IOawithBNdecm=bracket(integerToBNdec)(_free.unwrapBN)m-- |This is an alias to 'bnToInteger'.peekBN::BigNum->IOIntegerpeekBN=bnToInteger-- |This is an alias to 'integerToBN'.newBN::Integer->IOBigNumnewBN=integerToBNforeignimportccallunsafe"BN_bn2mpi"_bn2mpi::PtrBIGNUM->PtrCChar->IOCIntforeignimportccallunsafe"BN_mpi2bn"_mpi2bn::PtrCChar->CInt->PtrBIGNUM->IO(PtrBIGNUM){-# LINE 264 "OpenSSL/BN.hsc" #-}-- | Convert a BigNum to an MPI: a serialisation of large ints which has a-- 4-byte, big endian length followed by the bytes of the number in-- most-significant-first order.bnToMPI::BigNum->IOBS.ByteStringbnToMPIbn=dobytes<-_bn2mpi(unwrapBNbn)nullPtrallocaBytes(fromIntegralbytes)(\buffer->do_<-_bn2mpi(unwrapBNbn)bufferBS.packCStringLen(buffer,fromIntegralbytes))-- | Convert an MPI into a BigNum. See bnToMPI for details of the formatmpiToBN::BS.ByteString->IOBigNummpiToBNmpi=doBS.useAsCStringLenmpi(\(ptr,len)->do_mpi2bnptr(fromIntegrallen)nullPtr)>>=return.wrapBN-- | Convert an Integer to an MPI. SEe bnToMPI for the formatintegerToMPI::Integer->IOBS.ByteStringintegerToMPIv=bracket(integerToBNv)(_free.unwrapBN)bnToMPI-- | Convert an MPI to an Integer. SEe bnToMPI for the formatmpiToInteger::BS.ByteString->IOIntegermpiToIntegermpi=dobn<-mpiToBNmpiv<-bnToIntegerbn_free(unwrapBNbn)returnvforeignimportccallunsafe"BN_mod_exp"_mod_exp::PtrBIGNUM->PtrBIGNUM->PtrBIGNUM->PtrBIGNUM->BNCtx->IO(PtrBIGNUM)typeBNCtx=PtrBNCTXdataBNCTXforeignimportccallunsafe"BN_CTX_new"_BN_ctx_new::IOBNCtxforeignimportccallunsafe"BN_CTX_free"_BN_ctx_free::BNCtx->IO()withBNCtx::(BNCtx->IOa)->IOawithBNCtxf=bracket_BN_ctx_new_BN_ctx_freef-- |@'modexp' a p m@ computes @a@ to the @p@-th power modulo @m@.modexp::Integer->Integer->Integer->Integermodexpapm=unsafePerformIO(dowithBNa(\bnA->(dowithBNp(\bnP->(dowithBNm(\bnM->(dowithBNCtx(\ctx->(dor<-newBN0_<-_mod_exp(unwrapBNr)(unwrapBNbnA)(unwrapBNbnP)(unwrapBNbnM)ctxbnToIntegerr>>=return))))))))){- Random Integer generation ------------------------------------------------ -}foreignimportccallunsafe"BN_rand_range"_BN_rand_range::PtrBIGNUM->PtrBIGNUM->IOCIntforeignimportccallunsafe"BN_pseudo_rand_range"_BN_pseudo_rand_range::PtrBIGNUM->PtrBIGNUM->IOCInt-- | Return a strongly random number in the range 0 <= x < n where the given-- filter function returns true.randIntegerUptoNMinusOneSuchThat::(Integer->Bool)-- ^ a filter function->Integer-- ^ one plus the upper limit->IOIntegerrandIntegerUptoNMinusOneSuchThatfrange=withBNrange(\bnRange->(dor<-newBN0lettry=do_BN_rand_range(unwrapBNr)(unwrapBNbnRange)>>=failIf_(/=1)i<-bnToIntegerriffithenreturnielsetrytry))-- | Return a random number in the range 0 <= x < n where the given-- filter function returns true.prandIntegerUptoNMinusOneSuchThat::(Integer->Bool)-- ^ a filter function->Integer-- ^ one plus the upper limit->IOIntegerprandIntegerUptoNMinusOneSuchThatfrange=withBNrange(\bnRange->(dor<-newBN0lettry=do_BN_rand_range(unwrapBNr)(unwrapBNbnRange)>>=failIf_(/=1)i<-bnToIntegerriffithenreturnielsetrytry))-- | Return a strongly random number in the range 0 <= x < nrandIntegerZeroToNMinusOne::Integer->IOIntegerrandIntegerZeroToNMinusOne=randIntegerUptoNMinusOneSuchThat(constTrue)-- | Return a strongly random number in the range 0 < x < nrandIntegerOneToNMinusOne::Integer->IOIntegerrandIntegerOneToNMinusOne=randIntegerUptoNMinusOneSuchThat(/=0)-- | Return a random number in the range 0 <= x < nprandIntegerZeroToNMinusOne::Integer->IOIntegerprandIntegerZeroToNMinusOne=prandIntegerUptoNMinusOneSuchThat(constTrue)-- | Return a random number in the range 0 < x < nprandIntegerOneToNMinusOne::Integer->IOIntegerprandIntegerOneToNMinusOne=prandIntegerUptoNMinusOneSuchThat(/=0)