
class SBoxDist 
{
     SBox sbox ;
     int sboxNumber ;
     long [][] distribution ;

     SBoxDist( int sboxNumber )
     {
         sbox = new SBox(sboxNumber) ;
         this.sboxNumber = sboxNumber ;
         distribution = new long[64][16] ;
         for ( int xorInput=0; xorInput<64; xorInput++ )
         {
            for ( int xorOutput=0; xorOutput<16; xorOutput++ )
            {
                distribution[xorInput][xorOutput] = 
                    possibleAux( xorInput, xorOutput ) ;
            }
         }
     } 

     long possible( int xorInput, int xorOutput )
     {
         return distribution[xorInput][xorOutput] ;
     }

     private long possibleAux( int xorInput, int xorOutput )
     {
         long result = 0L ;
         long bit = 0x01L ;

         for ( int sboxIn=0; sboxIn<64; sboxIn++ )
         {
             if ( (sbox.map( sboxIn )^sbox.map( sboxIn^xorInput ))
                   == xorOutput )
             {
                 result |= bit ;
             }
             bit <<=1 ; 
         }
         return result  ;
     }

     int distribution( int xorInput, int xorOutput )
     {
        int count = 0 ;

         for ( int sboxIn=0; sboxIn<64; sboxIn++ )
         {
             if ( (sbox.map( sboxIn )^sbox.map( sboxIn ^ xorInput ))
                   == xorOutput )
             {
                 count++ ;
             }
         }
         return count  ;
     }

     static void printDistribution( int sboxNumber )
     {
        SBoxDist sbd = new SBoxDist( sboxNumber ) ;
        for ( int xin=0; xin<64; xin++ )
        {
            String xin_ = Integer.toString( xin, 16 ) ;
            if ( xin_.length()==1 ) xin_ = "0" + xin_ ;
            System.out.print( xin_ + ": " ) ;
            for ( int xout=0; xout<16; xout++ )
            {
                String d_ = Integer.toString( sbd.distribution( xin, xout )) ;
                if ( d_.length()==1 ) d_ = " " + d_ ;
                System.out.print( d_ + " " ) ;
            }
            System.out.println() ;
        } 
     }

     static void printPossible( int sboxNumber, int inputXor ) 
     {
        SBoxDist sbd = new SBoxDist( sboxNumber ) ;
        for ( int xout=0; xout<16; xout++ )
        {
            System.out.print(Integer.toString( xout, 16 ) + ": " ) ;
            long pos = sbd.possible( inputXor, xout ) ;
            int [] pos_ = DesEtc.unpackAux( pos, 64 ) ;
            for ( int i=63; i>=0; i-- )
            {
                if ( pos_[i]!=0 ) 
                {
                   String s = Integer.toString( 64-i-1, 16 ) ;
                   if ( s.length()==1 ) s = "0" + s ;
                   System.out.print( s + " " ) ;
                }
            }
            System.out.println() ;
        } 
     }
}

