{-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeOperators #-} module Crypto.XEd25519.FieldElement where import Crypto.Error import qualified Crypto.PubKey.Curve25519 as X25519 import qualified Crypto.PubKey.Ed25519 as Ed25519 import Data.ByteArray as BA (pack,unpack,Bytes) import Data.Modular import Data.Word -- 2^255 - 19 type P25519 = 57896044618658097711785492504343953926634992332820282019728792003956564819949 newtype FieldElement = FE (ℤ / P25519) fe_frombytes :: X25519.PublicKey -> FieldElement fe_frombytes pub = FE $ toMod $ decodeLittleEndian $ BA.unpack pub fe_tobytes :: FieldElement -> Ed25519.PublicKey fe_tobytes (FE x) = throwCryptoError $ Ed25519.publicKey (b :: Bytes) where b = BA.pack $ take 32 $ (encodeLittleEndian $ unMod x) ++ repeat 0 fe_1 :: FieldElement fe_1 = FE $ toMod 1 fe_sub :: FieldElement -> FieldElement -> FieldElement fe_sub (FE x) (FE y) = FE $ x - y fe_add :: FieldElement -> FieldElement -> FieldElement fe_add (FE x) (FE y) = FE $ x + y fe_invert :: FieldElement -> FieldElement fe_invert (FE x) = FE $ inv x fe_mul :: FieldElement -> FieldElement -> FieldElement fe_mul (FE x) (FE y) = FE (x * y) decodeLittleEndian :: [Word8] -> Integer decodeLittleEndian [] = 0 decodeLittleEndian (x:xs) = fromIntegral x + 256 * decodeLittleEndian xs encodeLittleEndian :: Integer -> [Word8] encodeLittleEndian 0 = [] encodeLittleEndian x = let (bs,b) = divMod x 256 in fromIntegral b : encodeLittleEndian bs