module OT ( setup , choose , deriveSenderKeys , deriveReceiverKey , mDeriveSenderKeys , mDeriveReceiverKeys --, unzip3 , mChoose ) where import Protolude hiding (hash) import Crypto.Hash import Crypto.Random.Types (MonadRandom) import qualified Crypto.PubKey.ECC.Prim as ECC import qualified Crypto.PubKey.ECC.Types as ECC import qualified Crypto.PubKey.ECC.Generate as ECC import Crypto.Number.Generate (generateMax) import qualified Crypto.PubKey.ECC.ECDSA as ECDSA import Crypto.Number.Serialize (os2ip) import qualified Data.ByteArray as BA import qualified Data.ByteString as BS import Control.Monad.Fail import Data.List ((!!)) -- | Setup: Only once, independently of the number of OT messages *m*. setup :: (MonadRandom m, MonadFail m) => ECC.Curve -> m (Integer, ECC.Point, ECC.Point) setup curve = do -- 1. Sender samples y <- Zp and computes S = yB and T = yS (sPubKey, sPrivKey) <- bimap ECDSA.public_q ECDSA.private_d <$> ECC.generate curve let t = ECC.pointMul curve sPrivKey sPubKey -- 2. S sends S to R, who aborts if S doesn't belong to G unless (ECC.isPointValid curve sPubKey) $ fail "Invalid sPubKey from sender" pure (sPrivKey, sPubKey, t) -- | Choose: In parallel for all OT messages. choose :: (MonadRandom m, MonadFail m) => ECC.Curve -> Integer -> ECC.Point -> m (Integer, ECC.Point, Integer) choose curve n sPubKey = do -- 1. Receiver samples x <- Zp and computes Response c <- generateMax (n - 1) rPrivKey <- ECDSA.private_d . snd <$> ECC.generate curve let cS = ECC.pointMul curve c sPubKey let xB = ECC.pointBaseMul curve rPrivKey let response = ECC.pointAdd curve cS xB -- 2. Fail if the response is not a valid point in the curve unless (ECC.isPointValid curve response) $ fail "Invalid response from verifier" pure (rPrivKey, response, c) mChoose :: (Eq t, Num t, MonadRandom m, MonadFail m) => ECC.Curve -> Integer -> ECC.Point -> t -> [(Integer, ECC.Point, Integer)] -> m [(Integer, ECC.Point, Integer)] -- | Call 'choose' 'm' times to create a list of three lists -- | Return lists of private keys, responses and choice bit mChoose curve n sPubKey 0 accum = return accum mChoose curve n sPubKey m accum = do a <- choose curve n sPubKey b <- mChoose curve (n) sPubKey (m-1) accum let accum = a : b return (accum) -- | Sender's key derivation from his private key and receiver's response -- In parallel for all OT messages deriveSenderKeys :: ECC.Curve -> Integer -> Integer -> ECC.Point -> ECC.Point -> [Integer] deriveSenderKeys curve n sPrivKey response t = deriveSenderKey <$> [0..n-1] where deriveSenderKey j = hashPoint curve (ECC.pointAdd curve yR (ECC.pointNegate curve (jT j))) yR = ECC.pointMul curve sPrivKey response jT j = ECC.pointMul curve j t mDeriveSenderKeys :: ECC.Curve -> Integer -> Integer -> [ECC.Point] -> ECC.Point -> [[Integer]] -- | Fold together 'm' calls of 'deriveSenderKeys' mDeriveSenderKeys curve n sPrivKey responses t = mDeriveSenderKeys' <$> responses where mDeriveSenderKeys' response = deriveSenderKeys curve n sPrivKey response t -- | Receiver's key derivation from his private key and sender's public key -- In parallel for all OT messages deriveReceiverKey :: ECC.Curve -> Integer -> ECC.Point -> Integer deriveReceiverKey curve rPrivKey sPubKey = hashPoint curve (ECC.pointMul curve rPrivKey sPubKey) mDeriveReceiverKeys :: ECC.Curve -> [Integer] -> ECC.Point -> [Integer] -- | Fold together 'm' calls of 'deriveReceiverKeys' mDeriveReceiverKeys curve rPrivKeys sPubKey = deriveReceiverKey' <$> rPrivKeys where deriveReceiverKey' rPrivKey = deriveReceiverKey curve rPrivKey sPubKey hashPoint :: ECC.Curve -> ECC.Point -> Integer hashPoint curve ECC.PointO = oracle curve "" hashPoint curve (ECC.Point x y) = oracle curve (show x <> show y) -- | Outputs unpredictable but deterministic random values oracle :: ECC.Curve -> BS.ByteString -> Integer oracle curve x = os2ip (sha256 x) `mod` ecc_n where ecc_n = ECC.ecc_n (ECC.common_curve curve) -- | Secure cryptographic hash function sha256 :: BS.ByteString -> BS.ByteString sha256 bs = BA.convert (hash bs :: Digest SHA3_256)