code: function decryptRaw (buffer, passphrase, progressCallback, scryptParams) {
    // 39 bytes: 2 bytes prefix, 37 bytes payload
    if (buffer.length !== 39) throw new Error('Invalid BIP38 data length')
    if (buffer.readUInt8(0) !== 0x01) throw new Error('Invalid BIP38 prefix')
    scryptParams = scryptParams || SCRYPT_PARAMS
  
    // check if BIP38 EC multiply
    var type = buffer.readUInt8(1)
    if (type === 0x43) return decryptECMult(buffer, passphrase, progressCallback, scryptParams)
    if (type !== 0x42) throw new Error('Invalid BIP38 type')
  
    passphrase = Buffer.from(passphrase, 'utf8')
  
    var flagByte = buffer.readUInt8(2)
    var compressed = flagByte === 0xe0
    if (!compressed && flagByte !== 0xc0) throw new Error('Invalid BIP38 compression flag')
  
    var N = scryptParams.N
    var r = scryptParams.r
    var p = scryptParams.p
  
    var salt = buffer.slice(3, 7)
    var scryptBuf = scrypt(passphrase, salt, N, r, p, 64, progressCallback)
    var derivedHalf1 = scryptBuf.slice(0, 32)
    var derivedHalf2 = scryptBuf.slice(32, 64)
  
    var privKeyBuf = buffer.slice(7, 7 + 32)
    var decipher = aes.createDecipheriv('aes-256-ecb', derivedHalf2, NULL)
    decipher.setAutoPadding(false)
    decipher.end(privKeyBuf)
  
    var plainText = decipher.read()
    var privateKey = xor(derivedHalf1, plainText)
  
    // verify salt matches address
    var d = BigInteger.fromBuffer(privateKey)
    var address = getAddress(d, compressed)
    var checksum = hash256(address).slice(0, 4)
    assert.deepEqual(salt, checksum)
  
    return {
      privateKey: privateKey,
      compressed: compressed
    }
  }
docs: some of the techniques borrowed from: https://github.com/pointbiz/bitaddress.org