//Generates the reliability training data for ONION attack only
        public static List <ReliabilityDataPoint> GenerateReliabilityTrainingDataOnion(XORArbiterPUF xPUF, int numberOfMeasurements, double[][] trainingData, double[][] trainingReliability, Random randomGenerator)
        {
            List <ReliabilityDataPoint> ReliabilityDataPointList = new List <ReliabilityDataPoint>(); //This stores all the noisy and non noisy data points with appropriate APUF labels
            int trainingSize = trainingData.Length;
            int bitNum       = xPUF.BitNumber;

            for (int i = 0; i < trainingSize; i++)
            {
                double sumOfResponses = 0;
                trainingData[i] = GenerateRandomPhiVector(bitNum, randomGenerator);
                int[]             previousAPUFResponses = new int[xPUF.GetPUFNum()]; //this stores all previous PUF responses to see if flip occured
                List <ArbiterPUF> currentNoisyAPUFList  = new List <ArbiterPUF>();   //this stores all the APUFs making the challenge noisy
                for (int m = 0; m < numberOfMeasurements; m++)
                {
                    int finalResult = 0;
                    for (int p = 0; p < xPUF.GetPUFNum(); p++)
                    {
                        int currentResult = xPUF.GetAPUFAtIndex(p).ComputeNoisyResponse(trainingData[i]);
                        finalResult = finalResult ^ currentResult;

                        //this is the extra part for the onion attack
                        if (m == 0) //this is the first time measurement being done so record responses
                        {
                            previousAPUFResponses[p] = currentResult;
                        }
                        else //compare to see if flipping occured
                        {
                            if (previousAPUFResponses[p] == currentResult)
                            {
                                //This APUF is reliable for this challenge, do nothing
                            }
                            else //This APUF is noisy for this phi
                            {
                                previousAPUFResponses[p] = currentResult; //store the new flip
                                if (currentNoisyAPUFList.Contains(xPUF.GetAPUFAtIndex(p)) == false) //make sure the APUF hasn't been duplicated
                                {
                                    currentNoisyAPUFList.Add(xPUF.GetAPUFAtIndex(p));               //note this does NOT copy, only puts pointer in memory
                                }
                            }
                        }
                    }
                    //sumOfResponses = sumOfResponses + xPUF.ComputeNoisyResponse(trainingData[i]); //sum the measurements
                    sumOfResponses = sumOfResponses + finalResult;
                }
                trainingReliability[i]    = new double[1];
                trainingReliability[i][0] = Math.Abs(numberOfMeasurements / 2.0 - sumOfResponses);

                //All measurements have been done, time to store the data point for onion analysis
                if (!currentNoisyAPUFList.Any() == true) //this means no APUFs made this challenge noisy so it is reliable
                {
                    ReliabilityDataPointList.Add(new ReliabilityDataPoint(trainingData[i], trainingReliability[i][0], false));
                }
                else
                {
                    ReliabilityDataPointList.Add(new ReliabilityDataPoint(trainingData[i], trainingReliability[i][0], true, currentNoisyAPUFList));
                }
            }
            return(ReliabilityDataPointList);
        }