content: module Pos.Core.Common.SharedSeed
         ( SharedSeed (..)
         ) where
  
  import           Universum
  
  import qualified Data.Aeson as Aeson (FromJSON (..), ToJSON (..))
  import qualified Data.ByteString as BS (pack, zipWith)
  import qualified Data.ByteString.Char8 as BSC (pack)
  import           Data.SafeCopy (base, deriveSafeCopySimple)
  import qualified Data.Semigroup (Semigroup (..))
  import           Formatting (formatToString)
  import qualified Formatting.Buildable as Buildable
  import           Serokell.Util.Base16 (base16F, formatBase16)
  import qualified Serokell.Util.Base16 as B16
  import           Serokell.Util.Base64 (JsonByteString (..))
  import           Text.JSON.Canonical (FromJSON (..), JSValue (..),
                       ReportSchemaErrors, ToJSON (..))
  
  import           Pos.Binary.Class (Cons (..), Field (..), deriveSimpleBi)
  import           Pos.Core.Constants (sharedSeedLength)
  import           Pos.Util.Json.Canonical ()
  import           Pos.Util.Json.Parse (tryParseString)
  
  -- | This is a shared seed used for follow-the-satoshi. This seed is
  -- randomly generated by each party and eventually they agree on the
  -- same value.
  newtype SharedSeed = SharedSeed
      { getSharedSeed :: ByteString
      } deriving (Show, Eq, Ord, Generic, NFData, Typeable)
  
  instance Buildable SharedSeed where
      build = formatBase16 . getSharedSeed
  
  instance Semigroup SharedSeed where
      (<>) (SharedSeed a) (SharedSeed b) =
          SharedSeed $ BS.pack (BS.zipWith xor a b) -- fast due to rewrite rules
  
  instance Monoid SharedSeed where
      mempty = SharedSeed $ BSC.pack $ replicate sharedSeedLength '\NUL'
      mappend = (Data.Semigroup.<>)
      mconcat = foldl' mappend mempty
  
  instance Monad m => ToJSON m SharedSeed where
      toJSON (SharedSeed seed) = pure . JSString . formatToString base16F $ seed
  
  instance ReportSchemaErrors m => FromJSON m SharedSeed where
      fromJSON = fmap SharedSeed . tryParseString B16.decode
  
  instance Aeson.ToJSON SharedSeed where
      toJSON = Aeson.toJSON . JsonByteString . getSharedSeed
  
  instance Aeson.FromJSON SharedSeed where
      parseJSON v = SharedSeed . getJsonByteString <$> Aeson.parseJSON v
  
  deriveSimpleBi ''SharedSeed [
      Cons 'SharedSeed [
          Field [| getSharedSeed :: ByteString |]
      ]]
  
  deriveSafeCopySimple 0 'base ''SharedSeed
  