Skip to main content



This specification defines a user-facing asset fingerprint as a bech32-encoded blake2b-160 digest of the concatenation of the policy id and the asset name.

Motivation: why is this CIP necessary?

The Mary era of Cardano introduces the support for native assets. On the blockchain, native assets are uniquely identified by both their so-called policy id and asset name. Neither the policy id nor the asset name are intended to be human-readable data.

On the one hand, the policy id is a hash digest of either a monetary script or a Plutus script. On the other hand, the asset name is an arbitrary bytestring of up to 32 bytes (which does not necessarily decode to a valid UTF-8 sequence). In addition, it is possible for an asset to have an empty asset name, or, for assets to have identical asset names under different policies.

Because assets are manipulated in several user-facing features on desktop and via hardware applications, it is useful to come up with a short(er) and human-readable identifier for assets that user can recognize and refer to when talking about assets. We call such an identifier an asset fingerprint.


We define the asset fingerprint in pseudo-code as:

assetFingerprint := encodeBech32
( datapart = hash
( algorithm = 'blake2b'
, digest-length = 20
, message = policyId | assetName
, humanReadablePart = 'asset'

where | designates the concatenation of two byte strings. The digest-length is given in bytes (so, 160 bits).

Reference Implementation



Haskell (GHC >= 8.6.5)

Language Extensions

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TypeApplications #-}


-- package: base >= 4.0.0
import Prelude
import Data.Function
( (&) )

-- package: bech32 >= 1.0.2
import qualified Codec.Binary.Bech32 as Bech32

-- package: bech32-th >= 1.0.2
import Codec.Binary.Bech32.TH
( humanReadablePart )

-- package: bytestring >=
import Data.ByteString
( ByteString )

-- package: cryptonite >= 0.22
import Crypto.Hash
( hash )
import Crypto.Hash.Algorithms
( Blake2b_160 )

-- package: memory >= 0.14
import Data.ByteArray
( convert )

-- package: text >=
import Data.Text
( Text )
newtype PolicyId = PolicyId ByteString
newtype AssetName = AssetName ByteString
newtype AssetFingerprint = AssetFingerprint Text

mkAssetFingerprint :: PolicyId -> AssetName -> AssetFingerprint
mkAssetFingerprint (PolicyId policyId) (AssetName assetName)
= (policyId <> assetName)
& convert . hash @_ @Blake2b_160
& Bech32.encodeLenient hrp . Bech32.dataPartFromBytes
& AssetFingerprint
hrp = [humanReadablePart|asset|]

Test Vectors

ℹ️ policy_id and asset_name are hereby base16-encoded; their raw, decoded, versions should be used when computing the fingerprint.

- policy_id: 7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373
asset_name: ""
asset_fingerprint: asset1rjklcrnsdzqp65wjgrg55sy9723kw09mlgvlc3

- policy_id: 7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc37e
asset_name: ""
asset_fingerprint: asset1nl0puwxmhas8fawxp8nx4e2q3wekg969n2auw3

- policy_id: 1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209
asset_name: ""
asset_fingerprint: asset1uyuxku60yqe57nusqzjx38aan3f2wq6s93f6ea

- policy_id: 7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373
asset_name: 504154415445
asset_fingerprint: asset13n25uv0yaf5kus35fm2k86cqy60z58d9xmde92

- policy_id: 1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209
asset_name: 504154415445
asset_fingerprint: asset1hv4p5tv2a837mzqrst04d0dcptdjmluqvdx9k3

- policy_id: 1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209
asset_name: 7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373
asset_fingerprint: asset1aqrdypg669jgazruv5ah07nuyqe0wxjhe2el6f

- policy_id: 7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373
asset_name: 1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209
asset_fingerprint: asset17jd78wukhtrnmjh3fngzasxm8rck0l2r4hhyyt

- policy_id: 7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373
asset_name: 0000000000000000000000000000000000000000000000000000000000000000
asset_fingerprint: asset1pkpwyknlvul7az0xx8czhl60pyel45rpje4z8w

Rationale: how does this CIP achieve its goals?

Design choices

  • The asset fingerprint needs to be somewhat unique (although collisions are plausible, see next section) and refer to a particular asset. It must therefore include both the policy id and the asset name.

  • Using a hash gives us asset id of a same deterministic length which is short enough to display reasonably well on small screens.

  • We use bech32 as a user-facing encoding since it is both user-friendly and quite common within the Cardano eco-system (e.g. addresses, pool ids, keys).

Security Considerations

  • With a 160-bit digest, an attacker needs at least 2^80 operations to find a collision. Although 2^80 operations is relatively low (it remains expansive but doable for an attacker), it is considered safe within the context of an asset fingerprint as a mean of user verification within a particular wallet. An attacker may obtain advantage if users can be persuaded that a certain asset is in reality another (which implies to find a collision, and make both assets at the reach of the user).

  • We recommend however that in addition to the asset fingerprint, applications also show whenever possible a visual checksum calculated from the policy id and the asset name as specified in [CIP-YET-TO-COME]. Such generated images, which are designed to be unique and easy to distinguish, in combination with a readable asset fingerprint gives strong verification means to end users.

Path to Active

Acceptance Criteria

  • Asset fingerprints as described have been universally adopted in: wallets, blockchain explorers, query layers, token minting utilities, NFT specifications, and CLI tools.

Implementation Plan

  • Reference implementations available in both Javascript and Haskell.
  • Public presentation with confirmed interest in adopting this standard in advance of Mary ledger era.

This CIP is licensed under CC-BY-4.0.

CIP Information

This null ./CIP-0014 created on 2020-02-01 has the status: Active.
This page was generated automatically from: cardano-foundation/CIPs.