miniLockLib/KeyPairOperation.coffee

module.exports = class KeyPairOperation
  BLAKE2s = require "./BLAKE2s"
  NaCl = require "tweetnacl"
  scrypt = require "scrypt-async"
  EmailAddress = require "./EmailAddress"
  SecretPhrase = require "./SecretPhrase"

  constructor: (params) ->
    {@secretPhrase, @emailAddress} = params

Decode secret phrase input string into a Uint8Array of bytes.

  secret: ->
    NaCl.util.decodeUTF8(@secretPhrase)

Decode email address input string into a Uint8Array of bytes.

  salt: ->
    NaCl.util.decodeUTF8(@emailAddress)

Hash digest of the secret() to increase its potential complexity.

  hashDigestOfSecret: ->
    (new BLAKE2s length: 32).update(@secret()).digest()

Start the operation. callback receives error or keys when the operation is complete.

  start: (callback) ->
    if callback?.constructor isnt Function
      throw "Can’t make keys without a callback function."
    if @secretPhrase is undefined
      callback "Can’t make keys without a secret phrase."
      return no
    if SecretPhrase.isAcceptable(@secretPhrase) is no
      callback "Can’t make keys because '#{@secretPhrase}' is not an acceptable secret phrase."
      return no
    if @emailAddress is undefined
      callback "Can’t make keys without an email address."
      return no
    if EmailAddress.isAcceptable(@emailAddress) is no
      callback "Can’t make keys because '#{@emailAddress}' is not an acceptable email address."
      return no
    if @secretPhrase and @emailAddress and callback
      calculateCurve25519KeyPair @hashDigestOfSecret(), @salt(), (keys) ->
        callback(undefined, keys)
      return this

Calculate a curve25519 key pair for the given secret and salt.

  calculateCurve25519KeyPair = (secret, salt, callback) ->
    whenKeysAreReady = (encodedBytes) ->
      decodedBytes = NaCl.util.decodeBase64(encodedBytes)
      keys = NaCl.box.keyPair.fromSecretKey(decodedBytes)
      callback(keys)
    logN          = 17       # CPU/memory cost parameter (1 to 31).
    r             = 8        # Block size parameter. (I don’t know about this).
    dkLen         = 32       # Length of derived keys. (A miniLock key is 32 numbers).
    interruptStep = 1000     # Steps to split calculation with timeouts (default 1000).
    encoding      = "base64" # Output encoding ("base64", "hex", or null).
    scrypt(secret, salt, logN, r, dkLen, interruptStep, whenKeysAreReady, encoding)