def _anf_from_poly(self, polynomial): #build tap set fn from polynomial newFn = [[[i + 1]] for i in range(self.size - 1)] + [[]] for i in range(self.size): if polynomial[i + 1]: newFn[i] += [[0]] self.anf = [ANF(bitFn) for bitFn in newFn]
def __init__(self, size, nonlinear=True, permute=False): self.anf = [[[i], list(range(i))] for i in range(size)] self.anf[0][1] = True self.size = size self.induction_order = list(range(self.size)) if nonlinear: self.GenerateNonlinearity() if permute: shuffle(self.induction_order) newAnf = [] for bitFn in self.anf: newFn = [] for term in bitFn: if type(term) == bool: newFn.append(term) else: newTerm = [] for var in term: newTerm.append(self.induction_order[var]) newFn.append(newTerm) newAnf.append(newFn) for i in range(self.size): self.anf[self.induction_order[i]] = newAnf[i] #convert to ANF objects: self.anf = [ANF(bitFn) for bitFn in self.anf]
def shiftTerms(self, terms, idxA, idxB): for term in terms: valid = True for var in term: valid &= (var >= (idxA - idxB)) if not valid: raise ValueError("Invalid shift attempted for term: " + str(term)) newTerm = frozenset([(i - idxA + idxB) for i in term]) self.anf[idxA].remove(term) self.anf[idxB] += ANF([newTerm])
def _anf_from_poly(self, size, primitive_polynomial): #Create the top function: # Example: [1,0,1,1] -> [0,2,3] -> [[3],[1],[0]] topFn = [[size - idx] for (idx, t) in enumerate(primitive_polynomial) if t == 1] # Example: [[3],[1],[0]] -> [[0],[1],[3]] topFn = topFn[::-1] # Example: [[0],[1],[3]] -> [[[0],[1]]] topFn = [topFn[:-1]] #create the shift for all other bits shiftFn = [[[i + 1]] for i in range(size - 1)] return [ANF(bitFn) for bitFn in (shiftFn + topFn)]
def __init__(self, size, primitive_poly, \ nonlinear = True, maxAnds = 4, tapDensity = .75): #convert koopman string into polynomial: if type(primitive_poly) == str: primitive_poly = list( BitVector(intVal=int(primitive_poly, 16), size=size)) + [1] self.primitive_polynomial = primitive_poly #same as fibonacci ANF generation: top_fn = [[size - idx] for (idx, t) in enumerate(primitive_poly) if t == 1][::-1][:-1] self.anf = [[[(i + 1) % size]] for i in range(size - 1)] + [top_fn] self.anf = [ANF(bitFn) for bitFn in self.anf] self.size = size self.tau = self.size - 1 if nonlinear: self.generateNonlinearity(maxAnds, tapDensity)
def addNonLinearTerm(self, maxAnds): minDest = maxDest = 0 while not (minDest < maxDest): numTaps = randint(2, maxAnds) newTerm = frozenset(sample(range(1, self.size), numTaps)) maxDest = self.getMaxDestination(newTerm) minDest = self.getMinDestination(newTerm) idx1, idx2 = sample(range(minDest, maxDest + 1), 2) #add first copy self.anf[self.size - 1].add(newTerm) self.shiftTerms([newTerm], self.size - 1, idx1) #add second copy self.anf[self.size - 1].add(newTerm) self.shiftTerms([newTerm], self.size - 1, idx2) #fix edge case caused by set merging if idx1 == self.size - 1: self.anf[self.size - 1] += ANF([newTerm])
def _inverted_from_poly(self, polynomial): newFn = [[]] + [[[i - 1]] for i in range(1, self.size)] for i in range(self.size): if polynomial[i]: newFn[i] += [[self.size - 1]] self.anf = [ANF(bitFn) for bitFn in newFn]