-- | -- MCL WASM (https://github.com/herumi/mcl-wasm) serialisation support -- MCL WASM uses the following algorithm to serialise -- P = (x, y) in G1 -- if P.isZero() then 64-bytes zero. -- otherwise, -- d = x.serialize() -- if (y.isOdd()) d[MSB] |= 0x80 -- On analysis of the GT format, each element of GT is simply LSB serialised -- and appended as a continuous bytestring, using the element length to split -- each point module Pairing.Serialize.MCLWasm ( MCLWASM(..) ) where import Protolude hiding (putByteString) import Pairing.Serialize.Types import Pairing.Point import Pairing.ByteRepr import Pairing.CyclicGroup import Data.Binary.Put (Put, putWord8, putWord16le, runPut, putByteString) import Data.ByteString.Builder import Data.ByteString as B hiding (length) import qualified Data.ByteString as B data MCLWASM = MCLWASM deriving (Eq, Show) instance MkCompressedForm MCLWASM where serializeCompressed _ = toCompressedForm instance FromSerialisedForm MCLWASM where unserializePoint _ = fromCompressedForm toCompressedForm :: (ByteRepr a, FromX a) => Point a -> Maybe LByteString toCompressedForm (Point x y) = do ny <- yFromX x (\y1 y2 -> if isOdd y1 then y1 else y2) rx <- mkRepr (ByteOrderLength LeastSignificantFirst minReprLength) x bs <- if isOdd y then do k <- toPaddedBytes (ByteOrderLength MostSignificantFirst (calcReprLength x minReprLength)) 0x80 pure (B.pack $ B.zipWith (.|.) rx k) else pure rx pure (runPut $ putByteString bs) toCompressedForm Infinity = Just (toLazyByteString (word8 0)) fromCompressedForm :: (ByteRepr a, FromX a) => Point a -> LByteString -> Either Text (Point a) fromCompressedForm (Point onex _) bs = if isInfinity then pure Infinity else do k <- note "Padding failed" (toPaddedBytes (ByteOrderLength MostSignificantFirst (calcReprLength onex minReprLength)) 0x80) let nbs = B.pack $ B.zipWith (.&.) (toS bs) k (xbs, yodd) = if fromBytesToInteger MostSignificantFirst nbs == 0x80 then (B.pack (B.zipWith xor (toS bs) k), True) else (toS bs, False) x <- note "Failed to deserialise x" (fromRepr (ByteOrderLength LeastSignificantFirst minReprLength) onex xbs) y <- note "Failed to get y from x" (yFromX x (selOdd yodd)) pure (Point x y) where selOdd yesOdd y1 y2 = if yesOdd then whichOdd y1 y2 else whichEven y1 y2 whichOdd y1 y2 = if isOdd y1 then y1 else y2 whichEven y1 y2 = if isOdd y1 then y2 else y1 isInfinity = fromBytesToInteger MostSignificantFirst (toS bs) == 0 fromCompressedForm Infinity _ = Left "Cannot use infinity to extract from bytestring"