module Crypto.PVSS.Polynomial
( Polynomial(..)
, Degree(..)
, generate
, evaluate
, atZero
, lambda
) where
import Crypto.PVSS.ECC
import Crypto.Random
import Control.Monad
import Control.DeepSeq
import Foundation.Array
import Foundation.Collection ((!), length, foldl')
import Foundation (Offset(..), CountOf(..))
import qualified Foundation as F ((+))
import Prelude hiding (length)
newtype Polynomial = Polynomial [Scalar]
deriving (Show,Eq,NFData)
newtype Degree = Degree Int
deriving (Show,Eq,NFData)
generate :: MonadRandom randomly => Degree -> randomly Polynomial
generate (Degree i)
| i < 0 = error ("invalid polynomial degree: " ++ show i)
| otherwise = Polynomial <$> replicateM (i+1) keyGenerate
evaluate :: Polynomial -> Scalar -> Scalar
evaluate (Polynomial a) v =
foldl' (#+) (keyFromNum 0) $ zipWith (#*) a es
where
es = [ (v #^ degree) | degree <- [0..] ]
atZero :: Polynomial -> Scalar
atZero (Polynomial coeffs) = coeffs !! 0
lambda :: Array Scalar -> Offset Scalar -> Scalar
lambda xs i = factor (Offset 0) (keyFromNum 1)
where
!xi = xs !!! i
!(CountOf len) = length xs
factor !j !acc
| j == Offset len = acc
| j == i = factor (j F.+ Offset 1) acc
| otherwise =
let xj = xs !!! j
e = xj #* keyInverse (xj #- xi)
in factor (j F.+ Offset 1) (acc #* e)
(!!!) arr idx = maybe (error $ "out of bound: " ++ show idx ++ " " ++ show i) id (arr ! idx)