signature.js

const createKeccakHash  = require('keccak')
const RLP               = require('rlp')
const secp256k1         = require('secp256k1')

/** @namespace*/
var signature = {


  /**
   * @method
   * @param {string} prikey Privatekey used to sign message
   * @param {string} msg Message to be signed
   * @return {string} String signature
   * @example
   * signature.signMsg()
   * // returns
   */
  signMsg: function signMessageString(prikey, msg){
    var hash      = createKeccakHash('keccak256').update(RLP.encode(msg)).digest().toString('hex')
    var signature = secp256k1.sign(Buffer.from(hash, 'hex'), Buffer.from(prikey.slice(2), 'hex'))
    var sign      = Buffer.concat([signature.signature, Buffer.from([signature.recovery])]).toString('base64')
    return sign
  },


  /**
   * @method
   * @param {string} prikey Privatekey used to sign transaction
   * @param {object} tx Transaction object to be signed
   * @return {object} Signed transaction object
   * @example
   * signature.signTxn()
   * // returns
   */
  signTxn: function signTransaction(prikey, tx){
    var infolist = [
      tx.Type,
      tx.From,
      tx.To,
      tx.Amount,
      tx.AccountNonce,
      tx.GasPrice,
      tx.GasLimit,
      tx.Timestamp,
      tx.Payload
    ]
    // console.log(RLP.encode(infolist));
    var hash = "0x"+createKeccakHash('keccak256').update(RLP.encode(infolist)).digest().toString('hex')
    var signature = secp256k1.sign(Buffer.from(hash.slice(2), 'hex'), Buffer.from(prikey.slice(2), 'hex'))
    var sign = Buffer.concat([signature.signature, Buffer.from([signature.recovery])]).toString('base64')
    var Data = tx
    var txDone = {
      "Hash": hash,
      "Data": Data,
      "Signature": {
        "Sig": sign,
      }
    }
    return txDone
  },


  /**
   * @method
   * @param {string} sign Signature of signed message
   * @param {string} msg Signed message
   * @return {string} Address string
   * @example
   * signature.tellMsg()
   * // returns
   */
  tellMsg: function recoverMessageString(sign, msg){
    var totalB= Buffer.from(sign, 'base64')
    var signB = totalB.slice(0,64)
    var rcvrB = totalB.slice(64)
    var hashB = Buffer.from(createKeccakHash('keccak256').update(RLP.encode(msg)).digest().toString('hex'), 'hex')
    var rcvr  = [...rcvrB]
    var pubk  = secp256k1.recover(hashB, signB, rcvr[0], false).slice(1)
    var addr  = publicToAddress('0x'+pubk.toString('hex'))
    return addr
  },


  /**
   * @method
   * @param {string} sign Signature of signed transaction
   * @param {string} hash Hash of transaction
   * @return {string} Address string
   * @example
   * signature.tellTxn()
   * // returns
   */
  tellTxn: function recoverTransaction(sign, hash){
    var totalB= Buffer.from(sign, 'base64')
    var signB = totalB.slice(0,64)
    var rcvrB = totalB.slice(64)
    var hashB = Buffer.from(hash.slice(2), 'hex')
    var rcvr  = [...rcvrB]
    var pubk  = secp256k1.recover(hashB, signB, rcvr[0], false).slice(1)
    var addr  = publicToAddress('0x'+pubk.toString('hex'))
    return addr
  },


  /**
   * @method
   * @param {string} from Sender address
   * @param {string} to Receiver address
   * @param {number} amount Send amount
   * @return {object} transaction object
   * @example
   * signature.initTxn()
   * // returns
   */
  initTxn: function initiateTransaction(from, to, amount){
    //verify from, to, amount, payload?
    return {
          "Type":         0,
          "From":         from,
          "To":           to,
          "Amount":       amount,
          "AccountNonce": 0,
          "GasPrice":     10,
          "GasLimit":     200000,
          "Timestamp":    0,
          "Payload":      ''
    }
  }
}

function publicToAddress(pub){
  var buf = Buffer.from(pub.slice(2), 'hex');
  var add = "0x" + createKeccakHash('keccak256').update(RLP.encode(buf)).digest().slice(12).toString('hex').replace(/.$/i,"1")
  return add;
}

module.exports = signature