{- |
Module      : Singular.Registry.AssetName
Description : Deterministic asset-name derivation
License     : Apache-2.0

Derives a unique asset name from an output reference,
matching Aiken's @lib.assetName@:

@SHA2-256(txId ++ bigEndian16(outputIndex))@
-}
module Singular.Registry.AssetName
    ( -- * Asset-name derivation
      deriveAssetName
    ) where

import Crypto.Hash (Digest, SHA256, hash)
import Data.Bits (shiftR)
import Data.ByteArray (convert)
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.Word (Word16)
import PlutusTx.Builtins.Internal
    ( BuiltinByteString (..)
    )
import Singular.Registry.Types (OnChainTxOutRef (..))

{- | Derive the asset name from an output reference,
matching Aiken's @lib.assetName@:

@SHA2-256(txId ++ bigEndian16(outputIndex))@
-}
deriveAssetName :: OnChainTxOutRef -> ByteString
deriveAssetName :: OnChainTxOutRef -> ByteString
deriveAssetName OnChainTxOutRef{BuiltinByteString
txOutRefId :: BuiltinByteString
txOutRefId :: OnChainTxOutRef -> BuiltinByteString
txOutRefId, Integer
txOutRefIdx :: Integer
txOutRefIdx :: OnChainTxOutRef -> Integer
txOutRefIdx} =
    Digest SHA256 -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert Digest SHA256
digest
  where
    digest :: Digest SHA256
    digest :: Digest SHA256
digest = ByteString -> Digest SHA256
forall ba a.
(ByteArrayAccess ba, HashAlgorithm a) =>
ba -> Digest a
hash (ByteString
txIdBytes ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
indexBytes)

    txIdBytes :: ByteString
    txIdBytes :: ByteString
txIdBytes =
        let BuiltinByteString ByteString
bs = BuiltinByteString
txOutRefId
        in  ByteString
bs

    indexBytes :: ByteString
    indexBytes :: ByteString
indexBytes =
        let w16 :: Word16
w16 =
                Integer -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
txOutRefIdx :: Word16
        in  [Word8] -> ByteString
BS.pack
                [ Word16 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16
w16 Word16 -> Int -> Word16
forall a. Bits a => a -> Int -> a
`shiftR` Int
8)
                , Word16 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
w16
                ]