packages feed

morley-1.9: src/Michelson/Interpret/Utils.hs

-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ

-- | General utilities used by interpreter.
--
-- This is not supposed to import any Michelson modules.
module Michelson.Interpret.Utils
  ( encodeZarithNumber
  ) where

import Control.Exception (assert)
import qualified Data.Bits as Bits

-- | Encode a number as tezos does this.
--
-- In the Tezos reference implementation this encoding is called @zarith@.
encodeZarithNumber :: Integer -> NonEmpty Word8
encodeZarithNumber = doEncode True
  where
    {- Numbers, when packed by tezos, are represented as follows:

    byte 0:         1              _         ______   ||  lowest digits
            has continuation  is negative   payload   ||
                                                      ||
    byte 1:         1                       _______   ||
    ...             1                       _______   ||
    byte n:         0                       _______   ||
            has continuation                payload   \/  highest digits
    -}
    doEncode :: Bool -> Integer -> NonEmpty Word8
    doEncode isFirst a
      | a >= byteWeight =
          let (hi, lo) = a `divMod` byteWeight
              byte = Bits.setBit (fromIntegral @_ @Word8 lo) 7
          in byte :| toList (doEncode False hi)
      | a >= 0 =
          one (fromIntegral @_ @Word8 a)
      | otherwise = assert isFirst $
          let h :| t = doEncode True (-a)
          in Bits.setBit h 6 :| t
      where
        byteWeight = if isFirst then 64 else 128