/**
   * * Initializes the scheme
   *
   * @param password user given password
   * @return
   */
  public static boolean initScheme(String password, long[] features) {
    Position[] positions = new Position[Constants.M];
    Arrays.fill(
        positions,
        Position
            .BOTH); /* Initially both Alpha and Beta positions are filled with correct entries */
    BigInteger hpwd = Generator.getHPWD(Constants.Q); /* generate a random hardened password */

    initFunctions(password);

    HistoryData histData = new HistoryData(features);
    histData.persist(new File(Constants.HISTORY_FILE_PATH), hpwd);
    generateScheme(hpwd, positions, password);

    LoginHandler.getPreferences().put(Constants.PREF_INITIALIZED, "true");
    return true;
  }
  /**
   * @param password
   * @param features : array of current login features
   * @return true if successfully authenticated
   */
  private static boolean _authenticate(String password, long[] features) {
    initFunctions(password);

    BigInteger hpwd = extractHardenedPwd(features, password);

    File historyFile = new File(Constants.HISTORY_FILE_PATH);

    HistoryData historyData = HistoryData.loadHistory(historyFile, hpwd);
    if (historyData == null) {
        /* returns null if decryption of history file fails*/
      return false;
    }

    historyData.addEntry(features);
    Position[] positions = computeDistFeatures(historyData);

    historyData.persist(historyFile, hpwd);
    generateScheme(hpwd, positions, password);

    return true;
  }
  /**
   * * computes the distinguishing features from History File Data
   *
   * @param histData
   * @return Position[] containing which features are distinguishing
   */
  private static Position[] computeDistFeatures(HistoryData histData) {
    Position[] positions = new Position[Constants.M];

    if (histData == null || histData.numEntries() < Constants.H) {
      Arrays.fill(positions, Position.BOTH); /* If num of entries in history file < 10 */
    } else {
      double mean, sd;
      for (int i = 0; i < Constants.M; i++) {
        mean = histData.getMean(i);
        sd = histData.getStandardDeviation(i);
        if ((Constants.THRESHOLD_FEATURE_VALUES[i] - (Constants.K * sd)) > mean) {
          positions[i] = Position.ALPHA;
        } else if ((Constants.THRESHOLD_FEATURE_VALUES[i] + (Constants.K * sd)) < mean) {
          positions[i] = Position.BETA;
        } else {
          positions[i] = Position.BOTH;
        }
      }
    }

    return positions;
  }