An asset’s hash ensures that its legal meaning cannot be changed after it is created.

The hash encodes some key information provided by a CoinSpark asset’s web page and stores it in the genesis metadata of the transaction which created the asset, which is embedded in the blockchain.

While many aspects of assets (such as their icon) can be freely changed after the asset genesis, the following cannot:

  • Asset name
  • Issuer legal name
  • Asset description
  • Value per unit
  • Issue and expiry dates
  • Interest rate (if any)
  • Multiple for display (e.g. 0.01 display units per 1 integer raw unit)
  • Asset contract content

Asset hashes are calculated from a 0x00-delimited concatenation of these values using the same SHA-256 hashing algorithm as the bitcoin protocol. The name, issuer, description and dates are taken directly as text from the asset web page JSON and must use UTF-8 encoding. The interest rate and multiple are floating point numbers, and are converted to text in a deterministic way. The contract content is included in the hash input in its raw form.

Due to the 40 byte limit of OP_RETURNs in Bitcoin Core 0.9, there will usually not be space to include the full 32 byte SHA-256 hash digest within the genesis metadata. In that case, as much of the hash prefix as possible will be used.

To ensure consistency and ease of use, all of this logic is handled by the CoinSpark library – please see the example below.

Calculating an asset hash

C/C++

char name[]="Credit at John Doe's";
char issuer[]="John Doe's Restaurant Chain";
char description[]="Can be used for any purchase at John Doe's, excluding breakfasts.";
char issueDate[]="2014-03-01";
char expiryDate[]="2024-02-29";
double interestRate=0.0;
double multiple=0.01;
char contractURL[]="http://www.john-doe-dining.com/bitcoin-credits-contract.pdf";
char* contractContent;
size_t contractContentLen;
unsigned char assetHash[32];

contractContent=RetrieveURLContent(contractURL, &contractContentLen);
    // assume we have some function like this that we can use

if (contractContent)
    CoinSparkCalcAssetHash(name, strlen(name), issuer, strlen(issuer), description, strlen(description),
        issueDate, strlen(issueDate), expiryDate, strlen(expiryDate), &interestRate, &multiple,
        contractContent, contractContentLen, assetHash);
else
    ; // handle error

// The assetHash variable now contains the CoinSpark asset hash

Java

String name="Credit at John Doe's";
String issuer="John Doe's Restaurant Chain";
String description="Can be used for any purchase at John Doe's, excluding breakfasts.";
String issueDate="2014-03-01";
String expiryDate="2024-02-29";
double interestRate=0.0;
double multiple=0.01;
String contractURL="http://www.john-doe-dining.com/bitcoin-credits-contract.pdf";

byte[] contractContent="Contract Content retrieved by contractURL".getBytes();
    // assume we have some function like this that we can use

byte[] assetHash=null;

if (contractContent!=null)
    assetHash=CoinSparkGenesis.calcAssetHash(name, issuer, description, issueDate,
        expiryDate, interestRate, multiple, contractContent);
else
    ; // handle error

Javascript

var name="Credit at John Doe's";
var issuer="John Doe's Restaurant Chain";
var description="Can be used for any purchase at John Doe's, excluding breakfasts.";
var issueDate="2014-03-01";
var expiryDate="2024-02-29";
var interestRate=0.0;
var multiple=0.01;
var contractURL="http://www.john-doe-dining.com/bitcoin-credits-contract.pdf";

var contractContent=RetrieveURLContent(contractURL);
    // assume we have some function like this that we can use, which returns a UInt8Array

if (contractContent)
    var assetHash=CoinSparkCalcAssetHash(name, issuer, description, issueDate, expiryDate,
        interestRate, multiple, contractContent);
else
    ; // handle error

// The assetHash variable now contains the CoinSpark asset hash as a UInt8Array

PHP

$name="Credit at John Doe's";
$issuer="John Doe's Restaurant Chain";
$description="Can be used for any purchase at John Doe's, excluding breakfasts.";
$issueDate="2014-03-01";
$expiryDate="2024-02-29";
$interestRate=0.0;
$multiple=0.01;
$contractURL="http://www.john-doe-dining.com/bitcoin-credits-contract.pdf";

$contractContent=file_get_contents($contractURL); // requires allow_url_fopen=1 in php.ini

if (strlen($contractContent))
    $assetHash=CoinSparkCalcAssetHash($name, $issuer, $description, $issueDate, $expiryDate,
        $interestRate, $multiple, $contractContent);
else
    ; // handle error

// The $assetHash variable now contains the CoinSpark asset hash as a raw binary string

Python

name="Credit at John Doe's"
issuer="John Doe's Restaurant Chain"
description="Can be used for any purchase at John Doe's, excluding breakfasts."
units="1 US Dollar"
issueDate="2014-03-01"
expiryDate="2024-02-29"
interestRate=0.0
multiple=0.01
contractURL="http://www.john-doe-dining.com/bitcoin-credits-contract.pdf"

contractContent=urllib2.urlopen(contractURL).read() # for Python 2.x
contractContent=urllib.request.urlopen(contractURL).read() # for Python 3.x

if not contractContent is None: # need proper exception handling for urllib calls
    assetHash=CoinSparkCalcAssetHash(name, issuer, description, units, issueDate,
        expiryDate, interestRate, multiple, contractContent)
else:
     # handle error

Ruby

name="Credit at John Doe's"
issuer="John Doe's Restaurant Chain"
description="Can be used for any purchase at John Doe's, excluding breakfasts."
units="1 US Dollar"
issueDate="2014-03-01"
expiryDate="2024-02-29"
interestRate=0.0
multiple=0.01
contractURL="http://www.john-doe-dining.com/bitcoin-credits-contract.pdf"

require 'open-uri'
contractContent=open(contractURL) { |io| io.read }

if contractContent!=nil # need proper exception handling for open-uri
    assetHash=CoinSparkCalcAssetHash(name, issuer, description, units, issueDate,
        expiryDate, interestRate, multiple, contractContent)
else
     # handle error
end