package com.atolsystems.memop;
import com.atolsystems.atolutilities.AArrayUtilities;
import com.atolsystems.atolutilities.ATimeUtilities;
import com.atolsystems.atolutilities.ProgrammingChunk;
import java.io.PrintStream;
import java.util.List;
/**
*
* @author sebastien.riou
*/
public class NonLinearity {
final static boolean DEBUG = false;
int outputWidth;
int storageSize;
int inputWidth;
PrintStream ps;
public static void main(String[] args){
NonLinearity nl = new NonLinearity(System.out, 0, 0, 0);
nl.computeNonLinearity((List<ProgrammingChunk>)null);
}
NonLinearity(PrintStream ps, int inputWidth, int outputWidth, int storageSize){
this.ps=ps;
this.outputWidth=outputWidth;
this.storageSize=storageSize;
this.inputWidth=inputWidth;
}
final static String ZEROES = "00000000000000000000000000000000";
public int computeNonLinearity(List<ProgrammingChunk> image) {
ps.println("Non linearity report");
ps.println("Start time:" + ATimeUtilities.getTimeForUi());
ps.println();
if(DEBUG & (null==image)){
ps.println("\nWARNING: image=null, DEBUG mode --> run with hardcoded test vector.\n");
int []temp = {1,0,0,1,1,1,0,0};//new int[n];
outputWidth=1;
storageSize=1;
inputWidth=3;
computeNonLinearity(temp);
}
ps.println("inputWidth="+inputWidth);
ps.println("outputWidth="+outputWidth);
ps.println("storageSize="+storageSize);
int n=(int) Math.pow(2, inputWidth);
int []bFunction=new int[n];
ProgrammingChunk.pack(image);//reduce to one chunk
if(1!=image.size()){
if(image.isEmpty()){
ps.println();
ps.println("FATAL ERROR: image does not contain any data.");
ps.println();
return -1;
}
ps.println();
ps.println("WARNING: image contain non contiguous data, only first chunk will be evaluated.");
ps.println();
}
ProgrammingChunk chunk=image.get(0);
//store each element in a int
int []elems=new int[n];
{//scope
int j = 0;
for(int i=0;i<n*storageSize;i+=storageSize){
int e=chunk.getData()[i];
if(1<storageSize){
e=e<<8;
e=e+chunk.getData()[i+1];
}
if(2<storageSize){
e=e<<8;
e=e+chunk.getData()[i+2];
}
if(3<storageSize){
e=e<<8;
e=e+chunk.getData()[i+3];
}
elems[j++]=e;
}
}
ps.println("Processing sbox:");
for (int j = 0; j < n-1; j++) {
ps.append(Integer.toString(elems[j]) + ", ");
}
ps.println(Integer.toString(elems[n - 1]));
int nComboFuncs=(int) Math.pow(2, outputWidth)-1;
int []nlComboFuncs=new int [nComboFuncs];
int minNl=Integer.MAX_VALUE;
for(int mask=1;mask<=nComboFuncs;mask++){
ps.println();
ps.print("MASK=");
int nZeroes=outputWidth-32+Integer.numberOfLeadingZeros(mask);
ps.append(ZEROES, 0, nZeroes);
ps.println(Integer.toBinaryString(mask));
for(int j=0;j<n;j++){
int outputCombo=elems[j] & mask;
int xorReduced=Integer.bitCount(outputCombo) & 0x01;
bFunction[j]=xorReduced;
}
int nl=computeNonLinearityAndReport(bFunction);
nlComboFuncs[mask-1]=nl;
if(nl<minNl)
minNl=nl;
}
ps.println();
ps.println("Non linearity over all outputs: "+minNl);
ps.println();
ps.println("End of report:" + ATimeUtilities.getTimeForUi());
return minNl;
}
static public int computeNonLinearity(int sbox[], int outputWidth) {
int bFunction[]=new int[sbox.length];
int nComboFuncs=(int) Math.pow(2, outputWidth)-1;
int []nlComboFuncs=new int [nComboFuncs];
int minNl=Integer.MAX_VALUE;
for(int mask=1;mask<=nComboFuncs;mask++){
for(int j=0;j<sbox.length;j++){
int outputCombo=sbox[j] & mask;
int xorReduced=Integer.bitCount(outputCombo) & 0x01;
bFunction[j]=xorReduced;
}
int nl=computeNonLinearity(bFunction);
nlComboFuncs[mask-1]=nl;
if(nl<minNl)
minNl=nl;
}
return minNl;
}
static public int computeNonLinearity(boolean bFunction[]) {
return computeNonLinearity(AArrayUtilities.bools2Ints(bFunction,1));
}
static public int computeNonLinearity(int bFunction[]) {
int non_linearity=Integer.MIN_VALUE;
int size=bFunction.length;
int bitSize=Integer.bitCount(size-1);
if(size!=(1<<bitSize)) throw new RuntimeException("function incompletely defined (wrong length)");
int[] data2 = FWT(bFunction);
non_linearity = nonLinearity(data2);
return non_linearity;
}
static public int maxNonLinearity(boolean []bFunction){
int nBits=AArrayUtilities.nBits(bFunction);
int nPoints=1<<(nBits-1);
int nLinearPoints=1<<((nBits/2)-1);
return nPoints-nLinearPoints;
}
static int maxNonLinearity(int nBits){
int nPoints=1<<(nBits-1);
int nLinearPoints=1<<((nBits/2)-1);
return nPoints-nLinearPoints;
}
int computeNonLinearityAndReport(boolean bFunction[]) {
return computeNonLinearityAndReport(AArrayUtilities.bools2Ints(bFunction,1));
}
int computeNonLinearityAndReport(int bFunction[]) {
int non_linearity=Integer.MIN_VALUE;
int n=bFunction.length;
ps.println("Processing boolean function:");
for (int j = 0; j < n-1; j++) {
ps.append(Integer.toString(bFunction[j]) + ", ");
}
ps.println(Integer.toString(bFunction[n - 1]));
if (!isBooleanFunction(bFunction)) {
ps.println();
ps.println("WARNING: this is not a boolean function.");
ps.println();
}
ps.println("Number of elements: " + Integer.toString(n));
int total = totalBits(bFunction);
ps.append("Number of non-zero elements: " + Integer.toString(totalBits(bFunction)) + "");
if ((n >>> 1) == total) {
ps.append(" (balanced)");
}
ps.println();
if (isRightSize(bFunction)) {
int[] data2 = FWT(bFunction);
ps.println("Fast Walsh Transform:");
for (int j = 0; j < n - 1; j++) {
ps.append(Integer.toString(data2[j]) + ", ");
}
ps.println(Integer.toString(data2[n - 1]));
non_linearity = nonLinearity(data2);
ps.append("Non-linearity:" + Integer.toString(nonLinearity(data2)));
int nBits=AArrayUtilities.nBits(data2);
int maxNl=maxNonLinearity(nBits);
if (non_linearity == 0) {
ps.append(" (i.e. linear)");
}else if(non_linearity == maxNl){
ps.append(" (bent function)");
}else{
ps.append(" (max non linearity is "+maxNl+")");
}
ps.println();
} else {
String msg="FATAL ERROR: the size of the input array (" + Integer.toString(n) + ") is not a power of two.";
ps.println();
ps.println();
ps.println(msg);
throw new RuntimeException(msg);
}
return non_linearity;
}
static public int bitCount(int z) {
int ret_val = 0;
while (z > 0) {
if ((z & 1) == 1) {
ret_val++;
}
z = z >>> 1;
}
return ret_val;
}
static public int totalBits(int[] data) {
int data_size = data.length;
int temp = 0;
for (int i = 0; i < data_size; i++) {
if (data[i] != 0) {
temp++;
}
}
return temp;
}
static public boolean isBooleanFunction(int[] data) {
int data_size = data.length;
for (int i = 0; i < data_size; i++) {
if ((data[i] != 0) && (data[i] != 1)) {
return false;
}
}
return true;
}
static public boolean isRightSize(int[] data) {
int data_size = data.length;
if (bitCount(data_size) == 1) {
return true;
}
return false;
}
static public int nonLinearity(boolean[] bFunction){
int []temp=FWT(bFunction);
return nonLinearity(temp);
}
static public int[] FWT(boolean[] data){
return FWT(AArrayUtilities.bools2Ints(data,1));
}
static public int[] FWT(int[] data) {
int data_size = data.length;
int data_sizemo = data_size - 1;
int data_sizeo2 = data_size >>> 1;
if (isRightSize(data)) {
if (DEBUG) {
System.out.println("Debug: array size = (0 ... " + data_sizemo + ")");
}
int straddle_width = 1;
int blockstart = data_sizemo;
do {
int left_index = 0;
blockstart = blockstart >>> 1;
for (int block = blockstart; block >= 0; block--) {
int right_index = left_index + straddle_width;
for (int pair = 0; pair < straddle_width; pair++) {
int a = data[left_index];
int b = data[right_index];
data[left_index] = a + b;
data[right_index] = a - b;
left_index++;
right_index++;
}
left_index = right_index;
}
straddle_width = (straddle_width << 1) & data_sizemo;
} while (straddle_width != 0);
data[0] = data_sizeo2 - data[0];
return data;
} else {
String msg="FATAL ERROR: Array size is '" + data_size + "' - which is not a power of two.";
System.out.println();
System.out.println();
System.out.println(msg);
throw new RuntimeException(msg);
}
}
static public int nonLinearity(int[] ftwOutput) {
int data_size = ftwOutput.length;
int data_sizeo2 = data_size >>> 1;
int max = 0;
for (int i = 0; i < data_size; i++) {
int temp = ftwOutput[i];
temp = (temp >= 0) ? temp : 0 - temp;
if (temp > max) {
max = temp;
}
}
return data_sizeo2 - max;
}
}