{-# LANGUAGE Safe #-}--------------------------------------------------------------------------------moduleData.ThresholdScheme.Shamir(share,join)where--------------------------------------------------------------------------------importData.List(reverse)importData.Maybe(fromMaybe)--------------------------------------------------------------------------------share::Int->Int->Integer->[Integer]->Integer->EitherString[(Int,Integer)]join::Integer->[(Int,Integer)]->Integer--------------------------------------------------------------------------------sharetotalrequiredprimerandomssecret=if(required>1)&&(total>=required)thenRight$pointstotalprime(secret:randoms)elseLeft$"'required' must be greater than 1 and less-equal than 'total'."joinprimeshares=lagrange0primeshares--------------------------------------------------------------------------------points::Int->Integer->[Integer]->[(Int,Integer)]horner::Integer->Integer->[Integer]->Integerlagrange0::Integer->[(Int,Integer)]->Integerprecompute::Integer->Int->Int->[Int]->(Integer,Integer)gcdExt::Integer->Integer->(Integer,Integer,Integer)modInv::Integer->Integer->MaybeInteger--------------------------------------------------------------------------------points0_______=[]pointsnprimexs=points(n-1)primexs++[(n,hornerprime(toIntegern)xs)]hornerprimeindexxs=foldl(\accx->(((index*acc)`mod`prime)+x)`mod`prime)0$reversexs{-
Protecting AES with Shamir's Secret Sharing Scheme:
-- https://eprint.iacr.org/2011/516.pdf
-}lagrange0primexs=letindexes=fst<$>xsprecomputed=(\(i,(x,n))->(n,precomputeprimeixindexes))<$>zip[0..]xsinfoldl(\acc(n,(num,den))->{- As m is prime, we can default to 1 as all the non-zero elements
of Z / p Z have multiplicative inverses -}letden'=fromMaybe1$den`modInv`primen'=n*num*den'in(prime+acc+n')`mod`prime)0$precomputedprecomputeprimeindexxiindexes=letfractions=(\(j,xj)->ifindex==jthenNothingelseJust(toInteger$negatexj,toInteger$xi-xj))<$>zip[0..]indexesinfoldl(\accfrac->casefracofNothing->accJust(num,den)->letnum'=((fst$acc)*num)`mod`primeden'=((snd$acc)*den)`mod`primein(num',den'))(1,1)$fractions{- Extended Euclidean algorithm -}gcdExta0=(1,0,a)gcdExtab=let(q,r)=a`quotRem`b(s,t,g)=gcdExtbrin(t,s-q*t,g){- Modular inverse (in modular arithmetic, the modular multiplicative inverse):
-- https://rosettacode.org/wiki/Modular_inverse#Haskell
-}modInvam=let(i,_,g)=gcdExtaminifg==1thenJust(mkPosi)elseNothingwheremkPosx=ifx<0thenx+melsex