diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,13 @@
 # Changelog for pairing
 
+## 0.3
+
+- Square root calculation on Fq2
+- Both square roots returned on Fq
+- Point serialisation for G1, G2 and GT
+
+## 0.2
+
 ## 0.1
 
 * Initial release.
diff --git a/bench/BenchPairing.hs b/bench/BenchPairing.hs
--- a/bench/BenchPairing.hs
+++ b/bench/BenchPairing.hs
@@ -8,7 +8,7 @@
 import qualified Pairing.Group as Group
 import qualified Pairing.Point as Point
 import qualified Pairing.Pairing as Pairing
-
+import Pairing.CyclicGroup (asInteger)
 import qualified Pairing.Fq as Fq
 import qualified Pairing.Fr as Fr
 import qualified Pairing.Fq2 as Fq2
@@ -159,8 +159,12 @@
               $ whnf (uncurry (+)) (testFq_1, testFq_2)
           , bench "division"
               $ whnf (uncurry (/)) (testFq_1, testFq_2)
+          , bench "pow"
+              $ whnf (Fq.fqPow testFq_1) (asInteger testFr_1)
           , bench "inversion"
               $ whnf Fq.fqInv testFq_1
+          , bench "fqFromX"
+              $ whnf (Fq.fqYforX testFq_1) True
           ]
 
       , bgroup "Fr"
@@ -172,6 +176,8 @@
               $ whnf (uncurry (/)) (testFr_1, testFr_2)
           , bench "inversion"
               $ whnf Fr.frInv testFr_1
+          , bench "pow"
+              $ whnf (Fr.frPow testFr_1) (asInteger testFr_2)
           ]
 
       , bgroup "Fq2"
@@ -183,12 +189,18 @@
               $ whnf (uncurry (/)) (testFq2_1, testFq2_2)
           , bench "squaring"
               $ whnf Fq2.fq2sqr testFq2_1
+          , bench "pow"
+              $ whnf (Fq2.fq2pow testFq2_1) (asInteger testFr_1)
           , bench "negation"
               $ whnf negate testFq2_1
           , bench "inversion"
               $ whnf Fq2.fq2inv testFq2_1
           , bench "conjugation"
               $ whnf Fq2.fq2conj testFq2_1
+          , bench "square root"
+              $ whnf Fq2.fq2sqrt testFq2_1
+          , bench "fq2FromX"
+              $ whnf (Fq2.fq2YforX testFq2_1) True 
           ]
 
       , bgroup "Fq6"
diff --git a/pairing.cabal b/pairing.cabal
--- a/pairing.cabal
+++ b/pairing.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: dabb8024b0664bed6aa89f042dbbc95b098bf5f62fb35bd2d70d4a79992e2314
+-- hash: d047536a7348fa341206f72c42c935d58cf595375dbccae1dbcf0789040cbeb0
 
 name:           pairing
-version:        0.2
+version:        0.3.0
 synopsis:       Optimal ate pairing over Barreto-Naehrig curves
 description:    Optimal ate pairing over Barreto-Naehrig curves
 category:       Cryptography
@@ -48,18 +48,23 @@
       Pairing.Jacobian
       Pairing.CyclicGroup
       Pairing.Hash
+      Pairing.Serialize
+      Pairing.ByteRepr
   other-modules:
       Pairing.Modular
   hs-source-dirs:
       src
-  default-extensions: LambdaCase RecordWildCards OverloadedStrings NoImplicitPrelude FlexibleInstances ExplicitForAll RankNTypes DataKinds KindSignatures GeneralizedNewtypeDeriving TypeApplications ExistentialQuantification ScopedTypeVariables DeriveGeneric
+  default-extensions: LambdaCase RecordWildCards OverloadedStrings NoImplicitPrelude FlexibleInstances ExplicitForAll RankNTypes DataKinds KindSignatures GeneralizedNewtypeDeriving TypeApplications ExistentialQuantification ScopedTypeVariables DeriveGeneric BangPatterns FlexibleContexts
   ghc-options: -fwarn-tabs -fwarn-incomplete-patterns -fwarn-incomplete-record-updates -fwarn-redundant-constraints -fwarn-implicit-prelude -fwarn-overflowed-literals -fwarn-orphans -fwarn-identities -fwarn-dodgy-exports -fwarn-dodgy-imports -fwarn-duplicate-exports -fwarn-overlapping-patterns -fwarn-missing-fields -fwarn-missing-methods -fwarn-missing-signatures -fwarn-noncanonical-monad-instances -fwarn-unused-pattern-binds -fwarn-unused-type-patterns -fwarn-unrecognised-pragmas -fwarn-wrong-do-bind -fno-warn-name-shadowing -fno-warn-unused-binds -fno-warn-unused-matches -fno-warn-unused-do-bind
   build-depends:
       QuickCheck
     , arithmoi
     , base >=4.7 && <5
+    , binary
     , bytestring
     , cryptonite
+    , errors
+    , integer-logarithms
     , memory
     , protolude >=0.2
     , random
@@ -77,12 +82,16 @@
       Paths_pairing
   hs-source-dirs:
       tests
+  default-extensions: FlexibleContexts
   build-depends:
       QuickCheck
     , arithmoi
     , base
+    , binary
     , bytestring
     , cryptonite
+    , errors
+    , integer-logarithms
     , memory
     , pairing
     , protolude >=0.2
@@ -106,9 +115,12 @@
       QuickCheck
     , arithmoi
     , base >=4.7 && <5
+    , binary
     , bytestring
     , criterion
     , cryptonite
+    , errors
+    , integer-logarithms
     , memory
     , pairing
     , protolude >=0.2
diff --git a/src/Pairing/ByteRepr.hs b/src/Pairing/ByteRepr.hs
new file mode 100644
--- /dev/null
+++ b/src/Pairing/ByteRepr.hs
@@ -0,0 +1,33 @@
+module Pairing.ByteRepr where
+
+import Protolude
+import Data.ByteString as B
+import Data.ByteString.Builder
+
+class ByteRepr a where
+  mkRepr :: a -> Maybe ByteString
+  fromRepr :: a -> ByteString -> Maybe a
+  reprLength :: a -> Int
+
+toBytes :: Integer -> ByteString
+toBytes x = B.reverse . B.unfoldr (fmap go) . Just $ changeSign x
+  where
+    changeSign :: Num a => a -> a
+    changeSign | x < 0     = subtract 1 . negate
+               | otherwise = identity
+    go :: Integer -> (Word8, Maybe Integer)
+    go x = ( b, i )
+      where
+        b = changeSign (fromInteger x)
+        i | x >= 128  = Just (x `shiftR` 8 )
+          | otherwise = Nothing
+
+toPaddedBytes :: Int -> Integer -> Maybe ByteString
+toPaddedBytes len a = if B.length bs > len then Nothing else Just (B.append (B.replicate (len - B.length bs) 0x0)  bs)
+  where
+    bs = toBytes a
+
+fromBytesToInteger :: ByteString -> Integer
+fromBytesToInteger = B.foldl' f 0
+  where
+    f a b = a `shiftL` 8 .|. fromIntegral b
diff --git a/src/Pairing/CyclicGroup.hs b/src/Pairing/CyclicGroup.hs
--- a/src/Pairing/CyclicGroup.hs
+++ b/src/Pairing/CyclicGroup.hs
@@ -2,18 +2,26 @@
   ( AsInteger(..)
   , CyclicGroup(..)
   , sumG
+  , FromX(..)
+  , Validate (..)
   ) where
 
 import Protolude
+import Crypto.Random (MonadRandom)
+import Data.ByteString.Builder
+import Data.ByteString as BS
 
 class AsInteger a where
   asInteger :: a -> Integer
 
+type LargestY = Bool
+
 class Monoid g => CyclicGroup g where
   generator :: g
   order :: Proxy g -> Integer
   expn :: AsInteger e => g -> e -> g
   inverse :: g -> g
+  random :: (MonadRandom m) => g -> m g
 
 -- | Sum all the elements of some container according to its group
 -- structure.
@@ -22,3 +30,14 @@
 
 instance AsInteger Int where
   asInteger = toInteger
+
+instance AsInteger Integer where
+  asInteger = identity
+
+class FromX a where
+  yFromX :: a -> LargestY -> Maybe a
+  isLargestY :: a -> Bool
+
+class Validate a where
+  isValidElement :: a -> Bool
+
diff --git a/src/Pairing/Fq.hs b/src/Pairing/Fq.hs
--- a/src/Pairing/Fq.hs
+++ b/src/Pairing/Fq.hs
@@ -14,18 +14,20 @@
   fqZero,
   fqOne,
   fqNqr,
-  euclidean,
+  fqPow,
+  fqSqrt,
   random,
-  Pairing.Fq.fromBytes
+  fqYforX,
+  fromBytesToInteger
 ) where
 
 import Protolude
 import Crypto.Random (MonadRandom)
 import Crypto.Number.Generate (generateMax)
 import Pairing.Params as Params
-import Pairing.CyclicGroup
+import Pairing.CyclicGroup (AsInteger(..), FromX(..))
+import Pairing.ByteRepr
 import Pairing.Modular as M
-import Data.Bits
 import qualified Data.ByteString as BS
 import Data.Bits
 import Math.NumberTheory.Moduli.Class
@@ -56,14 +58,19 @@
   (/) = fqDiv
   fromRational (a :% b) = Fq a / Fq b
 
+instance FromX Fq where
+  yFromX = fqYforX
+  isLargestY y = y > negate y
+
+instance ByteRepr Fq where
+  mkRepr f@(Fq a) = toPaddedBytes (reprLength f) a
+  fromRepr _ bs = Just (Fq $ fromBytesToInteger bs)
+  reprLength _ = 32
+
 -- | Turn an integer into an @Fq@ number, should be used instead of
 -- the @Fq@ constructor.
 new :: Integer -> Fq
-new a = Fq $ withQ $ (getVal . newMod a)
-
-{-# INLINE norm #-}
-norm :: Fq -> Fq
-norm (Fq a) = new a
+new a = Fq $ withQ (getVal . newMod a)
 
 {-# INLINE fqAdd #-}
 fqAdd :: Fq -> Fq -> Fq
@@ -89,6 +96,10 @@
 fqDiv :: Fq -> Fq -> Fq
 fqDiv (Fq a) (Fq b) = Fq $ withQ (modBinOp a b (/))
 
+{-# INLINE fqPow #-}
+fqPow :: Integral e => Fq -> e -> Fq
+fqPow (Fq a) b = Fq $ withQ (modUnOp a (flip powMod b))
+
 {-# INLINE fqNqr #-}
 -- | Quadratic non-residue
 fqNqr :: Fq
@@ -109,30 +120,17 @@
 fqOne :: Fq
 fqOne = Fq 1
 
-inv :: Fq -> Fq
-inv (Fq a) = Fq $ euclidean a _q `mod` _q
-
--- | Euclidean algorithm to compute inverse in an integral domain @a@
-euclidean :: (Integral a) => a -> a -> a
-euclidean a b = fst (inv' a b)
-
-{-# INLINEABLE inv' #-}
-{-# SPECIALISE inv' :: Integer -> Integer -> (Integer, Integer) #-}
-inv' :: (Integral a) => a -> a -> (a, a)
-inv' a b =
-  case b of
-   1 -> (0, 1)
-   _ -> let (e, f) = inv' b d
-        in (f, e - c*f)
-  where c = a `div` b
-        d = a `mod` b
+fqSqrt :: Bool -> Fq -> Maybe Fq
+fqSqrt largestY (Fq a) = do
+  (y1, y2) <- withQM (modUnOpMTup a bothSqrtOf)
+  Fq <$> if largestY then Just (max y1 y2) else Just (min y1 y2)
 
 random :: MonadRandom m => m Fq
 random = do
   seed <- generateMax _q
   pure (Fq seed)
 
-fromBytes :: ByteString -> Fq
-fromBytes bs = Fq $ withQ (M.toInteger . M.fromBytes bs)
 
-
+fqYforX :: Fq -> Bool -> Maybe Fq
+fqYforX x largestY = fqSqrt largestY (x `fqPow` 3 + new _b)
+  
diff --git a/src/Pairing/Fq12.hs b/src/Pairing/Fq12.hs
--- a/src/Pairing/Fq12.hs
+++ b/src/Pairing/Fq12.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE Strict #-}
+{-# LANGUAGE DeriveAnyClass, DeriveGeneric #-}
 
 -- | Final quadratic extension of the tower:
 --
@@ -29,12 +30,15 @@
 import Pairing.Fq6 (Fq6(..))
 import qualified Pairing.Fq2 as Fq2
 import qualified Pairing.Fq6 as Fq6
+import Pairing.CyclicGroup (AsInteger(..), FromX(..))
 import Pairing.Params
+import Pairing.ByteRepr
+import Data.ByteString as B (length, splitAt)
 
 -- | Field extension defined as Fq6[w]/w^2 - v
 data Fq12 = Fq12 { fq12x :: Fq6, fq12y :: Fq6 } -- ^ Use @new@ instead
                                                 -- of this constructor
-  deriving (Eq, Show)
+  deriving (Eq, Show, Generic, NFData)
 
 instance Num Fq12 where
   (+)         = fq12add
@@ -47,6 +51,15 @@
 instance Fractional Fq12 where
   (/) = fq12div
   fromRational (a :% b) = fq12int a / fq12int b
+
+instance ByteRepr Fq12 where
+  mkRepr (Fq12 x y) = mkRepr x <> mkRepr y
+  fromRepr (Fq12 x _) bs = do
+    let (xbs, ybs) = B.splitAt (reprLength x) bs
+    x <- fromRepr Fq6.fq6one xbs
+    y <- fromRepr Fq6.fq6one ybs
+    Just (Fq12 x y)
+  reprLength (Fq12 x y)  = reprLength x + reprLength y
 
 -- | Create a new value in @Fq12@ by providing a list of twelve
 -- coefficients in @Fq@, should be used instead of the @Fq12@
diff --git a/src/Pairing/Fq2.hs b/src/Pairing/Fq2.hs
--- a/src/Pairing/Fq2.hs
+++ b/src/Pairing/Fq2.hs
@@ -20,17 +20,24 @@
   fq2zero,
   fq2conj,
   fq2sqr,
+  fq2sqrt,
+  fq2pow,
+  fq2YforX,
   mulXi,
   divXi,
   xi,
-  Pairing.Fq2.random
+  Pairing.Fq2.random,
 ) where
 
 import Protolude
 import Crypto.Random (MonadRandom)
-
+import Pairing.Modular
 import Pairing.Fq as Fq
 import qualified Pairing.Params as Params
+import Data.Bits
+import Data.ByteString as B (length, splitAt)
+import Pairing.CyclicGroup (AsInteger(..), FromX(..))
+import Pairing.ByteRepr
 
 -- | Quadratic extension of @Fq@ defined as @Fq[u]/x^2 + 1@
 data Fq2 = Fq2 { fq2x :: Fq, fq2y :: Fq } -- ^ Use @new@ instead of
@@ -53,6 +60,22 @@
   (/) = fq2div
   fromRational (a :% b) = fq2int a / fq2int b
 
+instance Ord Fq2 where
+  compare (Fq2 x y) (Fq2 a b)
+    | compare x a == EQ = compare y b
+    | otherwise = compare x a
+
+instance FromX Fq2 where
+  yFromX = fq2YforX
+  isLargestY y = y > negate y
+
+instance ByteRepr Fq2 where
+  mkRepr (Fq2 x y) = mkRepr x <> mkRepr y
+  fromRepr (Fq2 x _) bs = do
+    let (xbs, ybs) = B.splitAt (reprLength x) bs
+    Just (Fq2 (Fq $ fromBytesToInteger xbs) (Fq $ fromBytesToInteger ybs))
+  reprLength (Fq2 x y) = reprLength x + reprLength y
+
 -- | Cubic non-residue in @Fq2@
 xi :: Fq2
 xi = Fq2 xiA xiB
@@ -110,6 +133,13 @@
     c0 = bb * fqNqr + aa
     c1 = (a0 + a1) * (a0 + a1) - aa - bb
 
+{-# INLINE fq2pow #-}
+fq2pow :: Fq2 -> Integer -> Fq2
+fq2pow b 0 = fq2one
+fq2pow b e = t * fq2pow (b * b) (shiftR e 1)
+  where 
+    t = if testBit e 0 then b else fq2one
+
 -- | Multiplicative inverse
 fq2inv :: Fq2 -> Fq2
 fq2inv (Fq2 a0 a1) = Fq2 c0 c1
@@ -122,9 +152,41 @@
 fq2conj :: Fq2 -> Fq2
 fq2conj (Fq2 x y) = Fq2 x (negate y)
 
+-- | Square root of Fq2 are specified by https://eprint.iacr.org/2012/685.pdf, Algorithm 9
+-- with lots of help from https://docs.rs/pairing/0.14.1/src/pairing/bls12_381/fq2.rs.html#162-222
+-- This implementation appears to return the larger square root so check the return value and
+-- negate as necessary
+fq2sqrt :: Fq2 -> Maybe Fq2
+fq2sqrt a = do
+  let a1 = a `fq2pow` qm3by4
+  let alpha = (fq2sqr a1) * a
+  let a0 = (alpha `fq2pow` Params._q) * alpha
+  if  a0 == neg1 then Nothing else do
+    let x0 = a1 * a
+    if alpha == neg1 then Just (a1 `fq2mul` Pairing.Fq2.new fqZero fqOne) else do
+      let b = (alpha + fq2one) `fq2pow` qm1by2
+      Just (b * x0)
+  where
+    neg1 = Pairing.Fq2.new (negate fqOne) fqZero
+    qm3by4 = withQ (modBinOp (Params._q -3) 4 (/))
+    qm1by2 = withQ (modBinOp (Params._q -1) 2 (/))
 
 random :: MonadRandom m => m Fq2
 random = do
   x <- Fq.random
   y <- Fq.random
   pure (Fq2 x y)
+
+-- https://docs.rs/pairing/0.14.1/src/pairing/bls12_381/ec.rs.html#102-124
+fq2YforX :: Fq2 -> Bool -> Maybe Fq2
+fq2YforX x ly 
+  | ly = newy
+  | otherwise = negate <$> newy
+  where
+    newy = fq2sqrt (x `fq2pow` 3 + Fq2 (b * inv_xi_a) (b * inv_xi_b))
+    (Fq2 inv_xi_a inv_xi_b) = fq2inv xi
+    b = Fq Params._b
+
+
+
+
diff --git a/src/Pairing/Fq6.hs b/src/Pairing/Fq6.hs
--- a/src/Pairing/Fq6.hs
+++ b/src/Pairing/Fq6.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE Strict #-}
+{-# LANGUAGE DeriveAnyClass, DeriveGeneric #-}
 
 -- | Cubic extension of the tower:
 --
@@ -26,6 +27,9 @@
 
 import Pairing.Fq2 (Fq2)
 import qualified Pairing.Fq2 as Fq2
+import Pairing.CyclicGroup (AsInteger(..), FromX(..))
+import Data.ByteString as B (length, splitAt)
+import Pairing.ByteRepr
 
 -- | Field extension defined as Fq2[v]/v^3 - (9 + u)
 data Fq6
@@ -34,7 +38,7 @@
     , fq6y :: Fq2
     , fq6z :: Fq2
     }
-  deriving (Eq, Show)
+  deriving (Eq, Show, Generic, NFData)
 
 instance Num Fq6 where
   (+)         = fq6add
@@ -47,6 +51,17 @@
 instance Fractional Fq6 where
   (/) = fq6div
   fromRational (a :% b) = fq6int a / fq6int b
+
+instance ByteRepr Fq6 where
+  mkRepr (Fq6 x y z) = mkRepr x <> mkRepr y <> mkRepr z
+  fromRepr (Fq6 x _ _) bs = do
+    let (xbs, yzbs) = B.splitAt (reprLength x) bs
+    let (ybs, zbs) = B.splitAt (reprLength x) yzbs
+    x <- fromRepr Fq2.fq2one xbs
+    y <- fromRepr Fq2.fq2one ybs
+    z <- fromRepr Fq2.fq2one zbs
+    Just (Fq6 x y z)
+  reprLength (Fq6 x y z) = reprLength x + reprLength y + reprLength z
 
 -- | Create a new value in @Fq6@, should be used instead of the @Fq6@
 -- constructor.
diff --git a/src/Pairing/Fr.hs b/src/Pairing/Fr.hs
--- a/src/Pairing/Fr.hs
+++ b/src/Pairing/Fr.hs
@@ -6,6 +6,9 @@
   Fr(..),
   new,
   frInv,
+  frPow,
+  frAdd,
+  frNeg,
   random,
   isRootOfUnity,
   isPrimitiveRootOfUnity,
@@ -20,8 +23,9 @@
 import Text.PrettyPrint.Leijen.Text
 
 import Pairing.Params
-import Pairing.CyclicGroup
-import Pairing.Fq (euclidean)
+import Pairing.CyclicGroup (AsInteger(..))
+import Pairing.Modular
+import Math.NumberTheory.Moduli.Class
 
 instance AsInteger Fr where
   asInteger (Fr n) = n
@@ -48,19 +52,15 @@
 -- | Turn an integer into an @Fr@ number, should be used instead of
 -- the @Fr@ constructor.
 new :: Integer -> Fr
-new a = Fr (a `mod` _r)
-
-{-# INLINE norm #-}
-norm :: Fr -> Fr
-norm (Fr a) = Fr (a `mod` _r)
+new a = Fr $ withR (getVal . newMod a)
 
 {-# INLINE frAdd #-}
 frAdd :: Fr -> Fr -> Fr
-frAdd (Fr a) (Fr b) = norm (Fr (a+b))
+frAdd (Fr a) (Fr b) = Fr $ withR (modBinOp a b (+))
 
 {-# INLINE frMul #-}
 frMul :: Fr -> Fr -> Fr
-frMul (Fr a) (Fr b) = norm (Fr (a*b))
+frMul (Fr a) (Fr b) = Fr $ withR (modBinOp a b (*))
 
 {-# INLINE frAbs #-}
 frAbs :: Fr -> Fr
@@ -68,21 +68,21 @@
 
 {-# INLINE frSig #-}
 frSig :: Fr -> Fr
-frSig (Fr a) = Fr (signum a  `mod` _r)
+frSig (Fr a) = Fr $ withR (modUnOp a signum)
 
 {-# INLINE frNeg #-}
 frNeg :: Fr -> Fr
-frNeg (Fr a) = Fr ((-a) `mod` _r)
+frNeg (Fr a) = Fr $ withR (modUnOp a negate)
 
 {-# INLINE frDiv #-}
 frDiv :: Fr -> Fr -> Fr
-frDiv a b = frMul a (inv b)
-
-inv :: Fr -> Fr
-inv (Fr a) = Fr $ euclidean a _r `mod` _r
+frDiv (Fr a) (Fr b) = Fr $ withR (modBinOp a b (/))
 
 frInv :: Fr -> Fr
-frInv = inv
+frInv a = 1 / a
+
+frPow :: Integral e => Fr -> e -> Fr
+frPow (Fr a) b = Fr $ withQ (modUnOp a (`powMod` b))
 
 random :: MonadRandom m => m Fr
 random = do
diff --git a/src/Pairing/Group.hs b/src/Pairing/Group.hs
--- a/src/Pairing/Group.hs
+++ b/src/Pairing/Group.hs
@@ -15,8 +15,10 @@
   b1,
   b2,
   hashToG1,
-  randomG1,
-  randomG2
+  groupFromX,
+  fromByteStringG1,
+  fromByteStringG2,
+  fromByteStringGT
 ) where
 
 import Protolude
@@ -25,12 +27,17 @@
 import Pairing.Fq as Fq
 import Pairing.Fq2 as Fq2
 import Pairing.Fq12 as Fq12
+import Pairing.Fr as Fr
 import Pairing.Point
 import Pairing.Params
 import Pairing.CyclicGroup
 import Test.QuickCheck
 import Pairing.Hash
 import Crypto.Random (MonadRandom)
+import Pairing.Modular
+import System.Random
+import Pairing.Serialize
+import Pairing.ByteRepr
 
 -- | G1 is E(Fq) defined by y^2 = x^3 + b
 type G1 = Point Fq
@@ -60,7 +67,17 @@
   order _ = _r
   expn a b = gMul a (asInteger b)
   inverse = gNeg
+  random _ = randomG1
 
+instance Validate G1 where
+  isValidElement = isOnCurveG1
+
+instance ToCompressedForm G1 where
+  serializeCompressed = fmap toS . toCompressedForm
+
+instance ToUncompressedForm G1 where
+  serializeUncompressed = fmap toS . toUncompressedForm
+
 instance Monoid G2 where
   mappend = gAdd
   mempty = Infinity
@@ -70,7 +87,17 @@
   order _ = _r
   expn a b = gMul a (asInteger b)
   inverse = gNeg
+  random _ = randomG2
 
+instance Validate G2 where
+  isValidElement = isOnCurveG2
+
+instance ToCompressedForm G2 where
+  serializeCompressed = fmap toS . toCompressedForm
+
+instance ToUncompressedForm G2 where
+  serializeUncompressed = fmap toS . toUncompressedForm
+
 instance Monoid GT where
   mappend = (*)
   mempty = 1
@@ -80,7 +107,14 @@
   order = notImplemented -- should be a factor of _r
   expn a b = a ^ asInteger b
   inverse = recip
+  random _ = Fq12.random
 
+instance ToUncompressedForm GT where
+  serializeUncompressed = fmap toS . elementToUncompressedForm
+
+instance Validate GT where
+  isValidElement = isInGT
+
 -- | Generator for G1
 g1 :: G1
 g1 = Point 1 2
@@ -103,7 +137,7 @@
 isOnCurveG1 Infinity
   = True
 isOnCurveG1 (Point x y)
-  = (y ^ 2 == x ^ 3 + Fq _b)
+  = (y `fqPow` 2 == x `fqPow` 3 + Fq _b)
 
 -- | Test whether a value in G2 satisfies the corresponding curve
 -- equation
@@ -111,7 +145,7 @@
 isOnCurveG2 Infinity
   = True
 isOnCurveG2 (Point x y)
-  = (y ^ 2 == x ^ 3 + (Fq2 (b * inv_xi_a) (b * inv_xi_b)))
+  = y `fq2pow` 2 == x `fq2pow` 3 + Fq2 (b * inv_xi_a) (b * inv_xi_b)
   where
     (Fq2 inv_xi_a inv_xi_b) = Fq2.fq2inv Fq2.xi
     b = Fq _b
@@ -138,15 +172,30 @@
 instance Arbitrary (Point Fq2) where -- G2
   arbitrary = gMul g2 . abs <$> (arbitrary :: Gen Integer)
 
-hashToG1 :: (MonadIO m, MonadRandom m) => ByteString -> m G1
+hashToG1 :: MonadIO m => ByteString -> m (Maybe G1)
 hashToG1 = swEncBN
 
-randomG1 :: (MonadIO m, MonadRandom m) => m G1
+randomG1 :: (MonadRandom m) => m G1
 randomG1 = do
   Fq r <- Fq.random
   pure (gMul g1 r)
 
-randomG2 :: (MonadIO m, MonadRandom m) => m G2
+randomG2 :: (MonadRandom m) => m G2
 randomG2 = do
   Fq r <- Fq.random
   pure (gMul g2 r)
+
+groupFromX :: (Validate (Point a), FromX a) => Bool -> a -> Maybe (Point a)
+groupFromX largestY x = do
+  y <- yFromX x largestY
+  if isValidElement (Point x y) then Just (Point x y) else Nothing
+
+fromByteStringG1 :: ByteString -> Either Text G1
+fromByteStringG1 = pointFromByteString fqOne . toSL
+
+fromByteStringG2 :: ByteString -> Either Text G2
+fromByteStringG2 = pointFromByteString fq2one . toSL
+
+fromByteStringGT :: ByteString -> Either Text GT
+fromByteStringGT = elementReadUncompressed fq12one . toSL
+
diff --git a/src/Pairing/Hash.hs b/src/Pairing/Hash.hs
--- a/src/Pairing/Hash.hs
+++ b/src/Pairing/Hash.hs
@@ -11,18 +11,10 @@
 import Math.NumberTheory.Moduli.Sqrt
 import Crypto.Random (MonadRandom)
 import Data.List
-
-sqrtOfMinusThree :: forall m . KnownNat m => Proxy m -> Mod m
-sqrtOfMinusThree mName = sqrtOf mName (-3)
-
--- |
--- Picks the postive square root only
--- |
+import Control.Error (runMaybeT, hoistMaybe)
 
-sqrtOf :: forall m . KnownNat m => Proxy m -> Mod m -> Mod m
-sqrtOf mName i = case sqrtsMod i of
-  [] -> panic ("Could not calculate sqrt " <> show i)
-  (x:_) -> x
+sqrtOfMinusThree :: forall m . KnownNat m => Proxy m -> Maybe (Mod m)
+sqrtOfMinusThree _ = sqrtOf (-3)
 
 w ::  forall m . KnownNat m => Proxy m -> Mod m -> Mod m -> Mod m
 w mname sq3 t = (sq3 * t) / (1 + (b mname) + (t `powMod` 2))
@@ -30,8 +22,10 @@
 b ::  forall m . KnownNat m => Proxy m -> Mod m
 b mName = fromInteger @(Mod m) _b
 
-x1 :: forall m . KnownNat m => Proxy m -> Mod m -> Mod m -> Mod m
-x1 mName t w = ((sqrtOfMinusThree mName) - 1) / 2 - (t * w)
+x1 :: forall m . KnownNat m => Proxy m -> Mod m -> Mod m -> Maybe (Mod m)
+x1 mName t w = do
+  m3 <- sqrtOfMinusThree mName
+  pure $ (m3  - 1) / 2 - (t * w)
 
 x2 :: forall m . KnownNat m => Proxy m -> Mod m -> Mod m
 x2 mName x1' = (-1) - x1'
@@ -51,11 +45,11 @@
 i :: Integer -> Integer -> Integer
 i pa pb = (((pa - 1) * pb) `mod` 3) + 1
 
-swy :: forall m . KnownNat m => Proxy m -> Mod m -> Mod m -> Mod m -> Mod m -> Integer
-swy mn pr3 pt pxi pb = ch * y
+swy :: forall m . KnownNat m => Proxy m -> Mod m -> Mod m -> Mod m -> Mod m -> Maybe Integer
+swy mn pr3 pt pxi pb = (ch *) <$>  y
   where
     ch = chi mn ((pr3 `powMod` 2) * pt)
-    y = getVal $ sqrtOf mn ((pxi `powMod` 3) + pb)
+    y = getVal <$> sqrtOf ((pxi `powMod` 3) + pb)
 
 -- | Encodes a given byte string to a point on the BN curve.
 -- The implemenation uses the Shallue van de Woestijne encoding to BN curves as specifed
@@ -64,23 +58,24 @@
 -- This function evaluates an empty bytestring or one that contains \NUL to zero
 -- which according to Definiton 2 of the paper is sent to an arbitrary point on the curve
 --
-swEncBN :: (MonadIO m, MonadRandom m) => ByteString -> m (Point Fq)
-swEncBN bs = withQM $ \mn -> do
+swEncBN :: MonadIO m => ByteString -> m (Maybe (Point Fq))
+swEncBN bs = runMaybeT $ withQM $ \mn -> do
   let t = M.fromBytes bs mn
-  let sq3 = sqrtOfMinusThree mn
+  sq3 <- hoistMaybe (sqrtOfMinusThree mn)
   let w' = w mn sq3 t
-  let x1' = x1 mn t w'
-  if (t == 0) then
-    pure $ (Point (Fq.new (getVal x1')) (Fq.new (getVal $ sqrtOf mn (1 + (b mn)))))
+  x1' <- hoistMaybe (x1 mn t w')
+  if (t == 0) then do
+    onebmn <- hoistMaybe (sqrtOf (1 + (b mn)))
+    pure $ (Point (Fq.new (getVal x1')) (Fq.new (getVal $ onebmn)))
   else do
     let x2' = x2 mn x1'
     let x3' = x3 mn w'
     let lst = [x1', x2', x3']
-    r1 <- randomMod mn
-    r2 <- randomMod mn
-    r3 <- randomMod mn
+    r1 <- liftIO (randomMod mn)
+    r2 <- liftIO (randomMod mn)
+    r3 <- liftIO (randomMod mn)
     let al = alphaBeta mn r1 x1'
     let bet = alphaBeta mn r2 x2'
     let i' = i al bet
-    let swy' = swy mn r3 t (genericIndex lst (i' -  1)) (b mn)
-    pure (Point (Fq.new (getVal $ genericIndex lst (i' - 1))) (Fq.new swy'))
+    swy' <- hoistMaybe (swy mn r3 t (genericIndex lst (i' -  1)) (b mn))
+    pure $ (Point (Fq.new (getVal $ genericIndex lst (i' - 1))) (Fq.new swy'))
diff --git a/src/Pairing/Modular.hs b/src/Pairing/Modular.hs
--- a/src/Pairing/Modular.hs
+++ b/src/Pairing/Modular.hs
@@ -5,22 +5,37 @@
 import Math.NumberTheory.Moduli.Sqrt
 import Math.NumberTheory.UniqueFactorisation
 import Pairing.Params
+import Pairing.ByteRepr
 import Crypto.Random (MonadRandom)
 import Crypto.Number.Generate (generateMax)
 import qualified Data.ByteString as BS
+import Math.NumberTheory.Logarithms
 
+withMod :: Integer -> (forall m . KnownNat m => Proxy m -> r) -> r
+withMod n cont = case someNatVal n of 
+  Nothing -> panic ("Somehow " <> show n <> " was not a Nat")
+  Just (SomeNat mName) -> cont mName 
+
+withModM :: Integer -> (forall n. KnownNat n => Proxy n -> m r) -> m r
+withModM n cont = case someNatVal n of 
+  Nothing -> panic ("Somehow " <> show n <> " was not a Nat")
+  Just (SomeNat mName) -> cont mName
+
 -- Mod conversion and management
 withQ :: (forall m . KnownNat m => Proxy m -> r) -> r
-withQ cont = case someNatVal _q of 
-  Nothing -> panic ("Somehow " <> show _q <> " was not a Nat")
-  Just (SomeNat mName) -> cont mName
+withQ = withMod _q
 
 -- Mod conversion and management
 withQM :: (forall n. KnownNat n => Proxy n -> m r) -> m r
-withQM cont = case someNatVal _q of 
-  Nothing -> panic ("Somehow " <> show _q <> " was not a Nat")
-  Just (SomeNat mName) -> cont mName
+withQM = withModM _q
 
+withR :: (forall m . KnownNat m => Proxy m -> r) -> r
+withR = withMod _r
+
+-- Mod conversion and management
+withRM :: (forall n. KnownNat n => Proxy n -> m r) -> m r
+withRM = withModM _r
+
 newMod :: forall m . KnownNat m => Integer -> Proxy m -> Mod m
 newMod n mName = fromInteger @(Mod m) n
 
@@ -44,27 +59,32 @@
   a <- f (fromInteger @(Mod m) n)
   pure (getVal a)
 
-modPow :: Integral p => Integer -> p -> Integer
-modPow a b = withQ (modUnOp a (flip powMod b))
-
-modSqrt :: Integer -> [Integer]
-modSqrt a = withQ (modUnOpM a sqrtsMod)
+modUnOpMTup :: forall m a . (KnownNat m, Monad a) => Integer -> (Mod m -> a (Mod m, Mod m)) -> Proxy m -> a (Integer, Integer)
+modUnOpMTup n f mName = do
+  (a, b) <- f (fromInteger @(Mod m) n)
+  pure (getVal a, getVal b)
 
 threeModFourCongruence :: Integer -> Bool
 threeModFourCongruence q = q `mod` 4 == 3 `mod` 4
 
 isSquare :: forall m . KnownNat m => Proxy m -> Mod m -> Bool
-isSquare _ a = if (threeModFourCongruence _q) then (length kp > 0) else False
+isSquare _ a = if (threeModFourCongruence (getMod a)) then (length kp > 0) else False
   where
     kp = sqrtsMod a
 
-isSquareIn3Mod4 :: Integer -> Integer
-isSquareIn3Mod4 a = if (threeModFourCongruence _q) then sq else 0
-  where
-    sq = withQ (modUnOp a f)
-    f m = m `powMod` p2
-    p2 = (_q + 1) `quot` 4
+-- |
+-- Picks the postive square root only
+-- |
 
+sqrtOf :: forall m . KnownNat m => Mod m -> Maybe (Mod m)
+sqrtOf i = fst <$> bothSqrtOf i
+
+bothSqrtOf :: forall m . KnownNat m => Mod m -> Maybe (Mod m, Mod m)
+bothSqrtOf i = case sqrtsMod i of
+  [] -> Nothing
+  (x : x1 : xs) -> Just (x, x1)
+  [_] -> Nothing
+
 legendre :: Integer -> Integer
 legendre a = if  conv > 1 then (-1) else conv 
   where
@@ -78,8 +98,4 @@
   pure (fromInteger @(Mod n) seed)
 
 fromBytes :: forall n. (KnownNat n) => ByteString -> Proxy n -> Mod n
-fromBytes bs mn = newMod (fromBytes' bs) mn
-  where
-    fromBytes' :: ByteString -> Integer
-    fromBytes' = BS.foldl' f 0
-    f a b = a `shiftL` 8 .|. fromIntegral b
+fromBytes bs mn = newMod (fromBytesToInteger bs) mn
diff --git a/src/Pairing/Serialize.hs b/src/Pairing/Serialize.hs
new file mode 100644
--- /dev/null
+++ b/src/Pairing/Serialize.hs
@@ -0,0 +1,105 @@
+module Pairing.Serialize where
+
+import Protolude hiding (putByteString)
+import Pairing.Point
+import Data.ByteString.Builder
+import Data.ByteString as B
+import Data.Binary.Get
+import Data.Binary.Put (Put, putWord8, runPut, putByteString)
+import Control.Error
+import Pairing.ByteRepr
+import Pairing.CyclicGroup
+
+class ToCompressedForm a where
+  -- | The serialisation may fail if y cannot be obtained from x
+  serializeCompressed :: a -> Maybe ByteString
+
+class ToUncompressedForm a where
+  serializeUncompressed :: a -> Maybe ByteString
+
+-- | Point serialisation using https://tools.ietf.org/id/draft-jivsov-ecc-compact-05.html
+-- It is unclear if 02 is smallest y or not so the following is used in the first 2 bytes
+-- 01 - Point at infinity
+-- 02 - Compressed repr i.e. x only but use smallest y on decode
+-- 03 - Compressed repr i.e. x only but use largest y on decode
+-- 04 -- Uncompressed repr i.e. x & y
+
+header :: Word8 -> Put
+header n = putWord8 0 >> putWord8 n
+
+elementToUncompressedForm :: (ByteRepr a) => a -> Maybe LByteString
+elementToUncompressedForm a = do
+  repr <- mkRepr a
+  pure $ runPut $ do 
+    header 4 
+    putByteString repr
+
+toUncompressedForm :: (ByteRepr a) => Point a -> Maybe LByteString
+toUncompressedForm (Point x y) = do
+  rx <- mkRepr x
+  ry <- mkRepr y
+  pure $ runPut $ do
+    header 4 
+    putByteString rx
+    putByteString ry
+toUncompressedForm Infinity = pure $ runPut (header 1)
+
+toCompressedForm :: (ByteRepr a, FromX a, Eq a) => Point a -> Maybe LByteString
+toCompressedForm (Point x y) = do
+  ny <- yFromX x True
+  let yform = if ny == y then 3 else 2
+  rx <- mkRepr x
+  pure (runPut $ header yform >> putByteString rx)
+toCompressedForm Infinity = Just (toLazyByteString (word8 0 <> word8 1))
+
+pointFromByteString :: (Show a, Validate (Point a), ByteRepr a, FromX a) => a -> LByteString -> Either Text (Point a)
+pointFromByteString a = parseBS fromByteStringGet
+  where
+    fromByteStringGet = do
+      ctype <- getCompressionType
+      processCompressed a ctype
+
+processCompressed :: forall a . (ByteRepr a, FromX a) => a -> Word8 -> Get (Maybe (Point a))
+processCompressed one ct
+  | ct == 4 = do
+      xbs <- getByteString rlen
+      ybs <- getByteString rlen
+      pure (buildPoint one xbs ybs)
+  | ct == 2 = fromCompressed False
+  | ct == 3 = fromCompressed True
+  | ct == 1 = pure (Just Infinity)
+  | otherwise = pure Nothing
+  where
+    rlen = reprLength one
+    fromCompressed largestY = runMaybeT $ do
+      xbs <- lift $ getByteString rlen
+      x <- hoistMaybe $ fromRepr one xbs
+      y <- hoistMaybe $ yFromX x largestY
+      pure (Point x y)
+      
+buildPoint :: ByteRepr a => a -> ByteString -> ByteString -> Maybe (Point a)
+buildPoint one xbs ybs = do
+  x <- fromRepr one xbs
+  y <- fromRepr one ybs
+  pure (Point x y)
+
+getCompressionType :: Get Word8
+getCompressionType = getWord8 >> getWord8
+
+elementReadUncompressed :: (Validate a, Show a, ByteRepr a) =>  a -> LByteString -> Either Text a
+elementReadUncompressed ele = parseBS runc
+  where
+    runc = do 
+      ctype <- getCompressionType
+      if ctype == 4 then do
+        bs <- getByteString (reprLength ele)
+        pure (fromRepr ele bs)
+      else 
+        pure Nothing
+
+parseBS :: (Validate a, Show a) => Get (Maybe a) -> LByteString -> Either Text a
+parseBS f bs = do
+  (_, _, mpt) <- first (\(_,_,err) -> toS err) (runGetOrFail f bs)
+  case mpt of 
+    Just pt -> if isValidElement pt then (Right pt) else Left ("Element was not valid after deserialisation: " <> show pt)
+    Nothing -> Left "Point could not be parsed"
diff --git a/tests/TestFields.hs b/tests/TestFields.hs
--- a/tests/TestFields.hs
+++ b/tests/TestFields.hs
@@ -97,6 +97,24 @@
     u = Fq2.new 0 1
     minusOne = Fq2.new (-1) 0
 
+unit_fq2pow :: Assertion
+unit_fq2pow = do
+  fq2 <- Fq2.random
+  let pow5 = fq2sqr (fq2sqr fq2) * fq2
+  pow5 @=?  fq2pow fq2 5
+  let pow10 = ((fq2sqr (fq2sqr (fq2sqr fq2))) * fq2) * fq2
+  pow10 @=?  fq2pow fq2 10
+  where
+    u = Fq2.new 0 1
+    minusOne = Fq2.new (-1) 0
+
+unit_fq2sqrt :: Assertion
+unit_fq2sqrt = do
+  fq2 <- Fq2.random
+  let sq = fq2sqr fq2
+  let (Just rt) = fq2sqrt sq
+  sq @=? fq2sqr rt
+
 -------------------------------------------------------------------------------
 -- Fq6
 -------------------------------------------------------------------------------
diff --git a/tests/TestGroups.hs b/tests/TestGroups.hs
--- a/tests/TestGroups.hs
+++ b/tests/TestGroups.hs
@@ -5,15 +5,18 @@
 import Protolude
 
 import Pairing.Fq as Fq
+import Pairing.Fr as Fr
 import Pairing.Fq2
+import Pairing.Fq12
 import Pairing.Point
-import Pairing.Group 
+import Pairing.Group as G
 import Pairing.Params
-
+import Pairing.Serialize
+import Pairing.Pairing
 import Test.Tasty
 import Test.Tasty.QuickCheck
 import Test.Tasty.HUnit
-import qualified Test.QuickCheck.Monadic as TQM (monadicIO, assert)
+import qualified Test.QuickCheck.Monadic as TQM (monadicIO, assert, run)
 import Test.QuickCheck.Instances ()
 import Data.ByteString as BS (null, dropWhile)
 import TestCommon
@@ -41,6 +44,28 @@
       $ isInverse binOp neg ident
     ]
 
+serializeTest pt compFunc testFunc = do
+  let (Just cbs) = compFunc pt
+  let npt2e = testFunc cbs
+  isRight npt2e @? (Protolude.show npt2e)
+  let (Right npt2) = npt2e
+  pt @=? npt2
+
+g1FromXTest :: G1 -> Assertion
+g1FromXTest Infinity = pure ()
+g1FromXTest pt@(Point x y) = do
+  let ysq = fqPow y 2
+  let (Just lysqrt) = fqSqrt True ysq
+  let (Just sysqrt) = fqSqrt False ysq
+  let egly = groupFromX True x
+  let egsy = groupFromX False x
+  isJust egly @=? True
+  isJust egsy @=? True
+  let Just lyg = egly
+  let Just syg = egsy
+  (Point x lysqrt) @=? lyg
+  (Point x sysqrt) @=? syg
+
 -------------------------------------------------------------------------------
 -- G1
 -------------------------------------------------------------------------------
@@ -63,9 +88,21 @@
 
 prop_hashToG1 :: ByteString -> Property
 prop_hashToG1 bs = TQM.monadicIO $ do
-  toCurve <- liftIO (hashToG1 bs) 
+  toCurveMay <- liftIO (hashToG1 bs)
+  TQM.assert (isJust toCurveMay)
+  let Just toCurve = toCurveMay
   TQM.assert (isOnCurveG1 toCurve)
 
+prop_g1FromX :: G1 -> Property
+prop_g1FromX g = TQM.monadicIO $ do
+  TQM.run $ g1FromXTest g
+
+prop_g1SerializeUncomp :: G1 -> Property
+prop_g1SerializeUncomp g = TQM.monadicIO $ TQM.run $ serializeTest g serializeUncompressed G.fromByteStringG1
+
+prop_g1SerializeComp :: G1 -> Property
+prop_g1SerializeComp g = TQM.monadicIO $ TQM.run $ serializeTest g serializeCompressed G.fromByteStringG1
+
 -------------------------------------------------------------------------------
 -- G2
 -------------------------------------------------------------------------------
@@ -85,8 +122,33 @@
 unit_order_g2_valid
   = gMul g2 _r @=? Infinity
 
+g2FromXTest :: G2 -> Assertion
+g2FromXTest Infinity = pure ()
+g2FromXTest pt@(Point x y) = do
+  let ysq = fq2pow y 2
+  let (Just ny) = fq2YforX x True
+  if (ny /= y) then (Point x y) @=? (Point x (negate ny)) else (Point x y) @=? (Point x ny)
+
+prop_g2FromX :: G2 -> Property
+prop_g2FromX g = TQM.monadicIO $ do
+  TQM.run $ g2FromXTest g
+
+prop_g2SerializeUncomp :: G2 -> Property
+prop_g2SerializeUncomp g = TQM.monadicIO $ TQM.run $ serializeTest g serializeUncompressed G.fromByteStringG2
+
+prop_g2SerializeComp :: G2 -> Property
+prop_g2SerializeComp g = TQM.monadicIO $ TQM.run $ serializeTest g serializeUncompressed G.fromByteStringG2
+
 -------------------------------------------------------------------------------
 -- GT
 -------------------------------------------------------------------------------
 
 -- The group laws for GT are implied by the field tests for Fq12.
+
+gtSerializeTest :: G1 -> G2 -> Assertion
+gtSerializeTest g1 g2 = do
+  let gt = reducedPairing g1 g2
+  serializeTest gt serializeUncompressed fromByteStringGT
+
+prop_gtSerializeUncomp :: G1 -> G2 -> Property
+prop_gtSerializeUncomp g1 g2 = TQM.monadicIO $ TQM.run $ gtSerializeTest g1 g2
