Fixes to linearity tests
authorPaul Crowley <paul@ciphergoth.org>
Mon Dec 22 13:14:38 2008 +0000 (2008-12-22)
changeset 109ffaab5071a8a
parent 108 82f26af4fbb9
child 110 7f65e0879f15
Fixes to linearity tests
linearitytest.py
     1.1 --- a/linearitytest.py	Sun Dec 21 11:13:27 2008 +0000
     1.2 +++ b/linearitytest.py	Mon Dec 22 13:14:38 2008 +0000
     1.3 @@ -1,10 +1,5 @@
     1.4  import random
     1.5  
     1.6 -# NB a linear function is one in which
     1.7 -# f(x) + f(y) = f(x + y)
     1.8 -# An affine one is one in which 
     1.9 -# f(x) + f(y) = f(x + y) + f(0)
    1.10 -
    1.11  class IsNonLinearException(Exception):
    1.12      pass
    1.13  
    1.14 @@ -28,6 +23,14 @@
    1.15                  break
    1.16          return x, vv
    1.17      
    1.18 +    def useValue(x, vv):
    1.19 +        k, v = self.predict(x)
    1.20 +        if k == 0:
    1.21 +            if v != vv:
    1.22 +                raise IsNonLinearException()
    1.23 +        else:
    1.24 +            self._entries.append((k, v ^ vv))
    1.25 +
    1.26      def gotBasis(self):
    1.27          return len(self._entries) == self._bits
    1.28      
    1.29 @@ -51,22 +54,57 @@
    1.30              if random.randrange(2) == 1:
    1.31                  kk ^= k; vv ^= v
    1.32          if self._f(kk) != vv:
    1.33 -            raise isNonLinearException()
    1.34 +            raise IsNonLinearException()
    1.35  
    1.36      def testLinearity(self):
    1.37 -        self.addLinearTerm()
    1.38 +        if len(self._entries) == 0:
    1.39 +            self.addLinearTerm()
    1.40          while not self.gotBasis():
    1.41              self.addLinearTermAndTest()
    1.42          for i in range(self._bits):
    1.43              self.testTerms()           
    1.44  
    1.45 +# NB a linear function is one in which
    1.46 +# f(x) + f(y) = f(x + y)
    1.47 +# An affine one is one in which 
    1.48 +# f(x) + f(y) = f(x + y) + f(0)
    1.49 +
    1.50 +def testLinearity(bits, f):
    1.51 +    # FIXME: adapt to use useValue
    1.52 +    LinearityTester(bits, f).testLinearity()
    1.53 +
    1.54 +class ZeroTester(object):
    1.55 +    def __init__(self, f):
    1.56 +        self._f = f
    1.57 +        self._zeroes = 0
    1.58 +        self._seenOne = False
    1.59 +    
    1.60 +    def __call__(self, x):
    1.61 +        res = self._f(x)
    1.62 +        if not self._seenOne:
    1.63 +            if res != 0:
    1.64 +                self._seenOne = True
    1.65 +            else:
    1.66 +                self._zeroes += 1
    1.67 +                if self._zeroes > 6:
    1.68 +                    raise IsConstantException()
    1.69 +        return res
    1.70 +
    1.71 +def testLinearityOrZero(bits, f):
    1.72 +    testLinearity(bits, ZeroTester(f))
    1.73 +    
    1.74 +def testAffineness(bits, f):
    1.75 +    # FIXME: adapt to use known vals where available    
    1.76 +    x = random.randrange(1<<bits)
    1.77 +    v = f(x)
    1.78 +    testLinearityOrZero(bits, lambda xx: v^f(x^xx))
    1.79 +
    1.80  #def doLinearityTest(f, bits):
    1.81  #    counts = [0, 0]
    1.82  #    for i in 
    1.83  
    1.84  if __name__ == "__main__":
    1.85 -    lt = LinearityTester(20, lambda x: (x ^ (x >>1))&1)
    1.86 -    lt.testLinearity()
    1.87 -    lt = LinearityTester(20, lambda x: (x & (x >>1))&1)
    1.88 -    lt.testLinearity()
    1.89 +    testLinearity(20, lambda x: (x ^ (x >>1))&1)
    1.90 +    testAffineness(20, lambda x: 1^(x ^ (x >>1))&1)
    1.91 +    #testLinearity(20, lambda x: (x & (x >>1))&1)
    1.92