types/preimage-sha256.js

'use strict'

/**
 * @module types
 */

const BaseSha256 = require('./base-sha256')
const MissingDataError = require('../errors/missing-data-error')

/**
 * PREIMAGE-SHA-256: Hashlock condition using SHA-256.
 *
 * This type of condition is also called a hashlock. By creating a hash
 * of a difficult-to-guess 256-bit random or pseudo-random integer it
 * is possible to create a condition which the creator can trivially
 * fulfill by publishing the random value. However, for anyone else,
 * the condition is cryptgraphically hard to fulfill, because they
 * would have to find a preimage for the given condition hash.
 *
 * PREIMAGE-SHA-256 is assigned the type ID 0. It relies on the SHA-256
 * and PREIMAGE feature suites which corresponds to a feature bitmask
 * of 0x03.
 */
class PreimageSha256 extends BaseSha256 {
  /**
   * Generate the contents of the condition hash.
   *
   * @return {Buffer} Hash payload.
   *
   * @private
   */
  getFingerprintContents () {
    if (!this.preimage) {
      throw new MissingDataError('Could not calculate hash, no preimage provided')
    }

    return this.preimage
  }

  /**
   * Provide a preimage.
   *
   * The preimage is the only input to a SHA256 hashlock condition.
   *
   * Note that the preimage should contain enough (pseudo-random) data in order
   * to be difficult to guess. A sufficiently large secret seed and a
   * cryptographically secure pseudo-random number generator (CSPRNG) can be
   * used to avoid having to store each individual preimage.
   *
   * @param {Buffer} preimage Secret data that will be hashed to form the condition.
   */
  setPreimage (preimage) {
    if (!Buffer.isBuffer(preimage)) {
      throw new TypeError('Preimage must be a buffer, was: ' + preimage)
    }

    this.preimage = preimage
  }

  parseJson (json) {
    this.preimage = Buffer.from(json.preimage, 'base64')
  }

  getAsn1JsonPayload () {
    return {
      preimage: this.preimage
    }
  }

  /**
   * Calculate the cost of fulfilling this condition.
   *
   * The cost of the preimage condition equals the size of the preimage in
   * bytes.
   *
   * @return {Number} Expected maximum cost to fulfill this condition
   * @private
   */
  calculateCost () {
    if (!this.preimage) {
      throw new MissingDataError('Preimage must be specified')
    }

    return this.preimage.length
  }

  /**
   * Validate this fulfillment.
   *
   * For a SHA256 hashlock fulfillment, successful parsing implies that the
   * fulfillment is valid, so this method is a no-op.
   *
   * @param {Buffer} Message (ignored in this condition type)
   * @return {Boolean} Validation result
   */
  validate (message) {
    return true
  }
}

PreimageSha256.TYPE_ID = 0
PreimageSha256.TYPE_NAME = 'preimage-sha-256'
PreimageSha256.TYPE_ASN1_CONDITION = 'preimageSha256Condition'
PreimageSha256.TYPE_ASN1_FULFILLMENT = 'preimageSha256Fulfillment'
PreimageSha256.TYPE_CATEGORY = 'simple'

module.exports = PreimageSha256