# Path: crysp/utils/operators.py
# def rol(x,n):
#     return (x<<n | x>>(x.size-n))
# 
# Path: crysp/padding.py
# class MDpadding(blockiterator):
#     def __init__(self,l,wsize):
#         self.wsize = wsize
#         super(MDpadding,self).__init__(l)
#     # add sha1 padding:
#     def lastblock(self,m,**kargs):
#         bitlen = kargs.get('bitlen',None)
#         if bitlen is None:
#             bitlen = self.bitcnt+len(m)*8
#         assert self.bitcnt<=bitlen
#         needed = bitlen-self.bitcnt
#         mb = Bits(m,size=needed)
#         countersize = self.wsize*2
#         N = self.blocksize-1-countersize-needed
#         if N<0: N += self.blocksize
#         pad = mb//Bits(1,1)//Bits(0,N)
#         self.padflag = True
#         self.bitcnt += needed
#         return pad.bytes()+pack(Bits(bitlen,countersize))
#     # remove sha1 padding:
#     def remove(self,c):
#         clen = self.wsize//4
#         counter,_ = unpack(c[-clen:])
#         c = list(c[:-clen])
#         while Bits(c[-1]).ival==0:
#             c.pop()
#         if len(c)==0: raise PaddingError("failed to remove padding")
#         b = Bits(c.pop())
#         b.size=str(b).rfind('1')
#         return b''.join(c)+b.bytes()
# 
# Path: crysp/poly.py
# class Poly(SubPoly):
# 
#   def __getitem__(self,i):
#       if isinstance(i,int):
#           return Poly(self.ival[i],self.size)
#       elif isinstance(i,slice):
#           return Poly(self.span(i),self.size)
#       else:
#           return Poly([self.ival[j] for j in i],self.size)
# 
# Path: crysp/padding.py
# class Nullpadding(blockiterator):
#     def lastblock(self,m,**kargs):
#         bitlen = kargs.get('bitlen',None)
#         if bitlen is None:
#             bitlen = len(m)*8
#         else:
#             bitlen = bitlen-self.bitcnt
#         q = self.blocksize-bitlen
#         b = (Bits(m,bitlen)//Bits(0,q)).bytes()
#         assert len(b)==self.blocklen
#         self.bitcnt += bitlen
#         self.padflag = True
#         self.padcnt = q
#         return b
#     # remove padding:
#     def remove(self,m):
#         b=Bits(m[-self.blocklen:])
#         b.size -= self.padcnt
#         return m[:-self.blocklen]+b.bytes()
# 
# Path: crysp/utils/operators.py
# def concat(L,bigend=False):
#     if len(L)==1: return L[0]
#     if bigend: L = reversed(L)
#     return reduce(lambda x,y: x//y, L)


from crysp.bits import *
from crysp.utils.operators import rol
from crysp.padding import MDpadding
from crysp.poly import Poly
from crysp.padding import Nullpadding
from crysp.utils.operators import concat
                h = Bits(M)>>(1024-self.size)
                h.size = self.size
                return h.bytes()

    def SEQ(self,M,bitlen=None):
        pad = Nullpadding(3072)
        B = [struct.unpack('>48Q',X) for X in pad.iterblocks(M,bitlen=bitlen)]
        j = len(B)
        z = 0
        d,keylen,L,r = self.size,self.keylen,self.L,self.rounds
        V = Bits(d,12)//Bits(keylen,8)//Bits(0,16)//Bits(z,4)//Bits(L,8)//Bits(r,12)//Bits(0,4)
        C = Poly(0,64,dim=16)
        W = Poly(Q,64,dim=89)//Poly(self.K,64)
        W.dim = 89
        W[24]  = V
        U = (self.L+1)<<56
        for i in range(j):
            if i==(j-1):
                V[20:36]=pad.padcnt
                V[36:40]=Bits(1,4)
                W[24]  = V
            W[23] = U+i
            W[25:41] = C
            W[41:89] = B[i]
            C = self.f(W)
        h = concat(list(C)[::-1])
        h.size = self.size
        return pack(h,'>L')

    def PAR(self,l,M,bitlen=None):

# Path: crysp/utils/operators.py
# def rol(x,n):
#     return (x<<n | x>>(x.size-n))
# 
# Path: crysp/padding.py
# class MDpadding(blockiterator):
#     def __init__(self,l,wsize):
#         self.wsize = wsize
#         super(MDpadding,self).__init__(l)
#     # add sha1 padding:
#     def lastblock(self,m,**kargs):
#         bitlen = kargs.get('bitlen',None)
#         if bitlen is None:
#             bitlen = self.bitcnt+len(m)*8
#         assert self.bitcnt<=bitlen
#         needed = bitlen-self.bitcnt
#         mb = Bits(m,size=needed)
#         countersize = self.wsize*2
#         N = self.blocksize-1-countersize-needed
#         if N<0: N += self.blocksize
#         pad = mb//Bits(1,1)//Bits(0,N)
#         self.padflag = True
#         self.bitcnt += needed
#         return pad.bytes()+pack(Bits(bitlen,countersize))
#     # remove sha1 padding:
#     def remove(self,c):
#         clen = self.wsize//4
#         counter,_ = unpack(c[-clen:])
#         c = list(c[:-clen])
#         while Bits(c[-1]).ival==0:
#             c.pop()
#         if len(c)==0: raise PaddingError("failed to remove padding")
#         b = Bits(c.pop())
#         b.size=str(b).rfind('1')
#         return b''.join(c)+b.bytes()
# 
# Path: crysp/poly.py
# class Poly(SubPoly):
# 
#   def __getitem__(self,i):
#       if isinstance(i,int):
#           return Poly(self.ival[i],self.size)
#       elif isinstance(i,slice):
#           return Poly(self.span(i),self.size)
#       else:
#           return Poly([self.ival[j] for j in i],self.size)
# 
# Path: crysp/padding.py
# class Nullpadding(blockiterator):
#     def lastblock(self,m,**kargs):
#         bitlen = kargs.get('bitlen',None)
#         if bitlen is None:
#             bitlen = len(m)*8
#         else:
#             bitlen = bitlen-self.bitcnt
#         q = self.blocksize-bitlen
#         b = (Bits(m,bitlen)//Bits(0,q)).bytes()
#         assert len(b)==self.blocklen
#         self.bitcnt += bitlen
#         self.padflag = True
#         self.padcnt = q
#         return b
#     # remove padding:
#     def remove(self,m):
#         b=Bits(m[-self.blocklen:])
#         b.size -= self.padcnt
#         return m[:-self.blocklen]+b.bytes()
# 
# Path: crysp/utils/operators.py
# def concat(L,bigend=False):
#     if len(L)==1: return L[0]
#     if bigend: L = reversed(L)
#     return reduce(lambda x,y: x//y, L)


# Path: crysp/md.py
from crysp.bits import *
from crysp.utils.operators import rol
from crysp.padding import MDpadding
from crysp.poly import Poly
from crysp.padding import Nullpadding
from crysp.utils.operators import concat

                h = Bits(M)>>(1024-self.size)
                h.size = self.size
                return h.bytes()

    def SEQ(self,M,bitlen=None):
        pad = Nullpadding(3072)
        B = [struct.unpack('>48Q',X) for X in pad.iterblocks(M,bitlen=bitlen)]
        j = len(B)
        z = 0
        d,keylen,L,r = self.size,self.keylen,self.L,self.rounds
        V = Bits(d,12)//Bits(keylen,8)//Bits(0,16)//Bits(z,4)//Bits(L,8)//Bits(r,12)//Bits(0,4)
        C = Poly(0,64,dim=16)
        W = Poly(Q,64,dim=89)//Poly(self.K,64)
        W.dim = 89
        W[24]  = V
        U = (self.L+1)<<56
        for i in range(j):
            if i==(j-1):
                V[20:36]=pad.padcnt
                V[36:40]=Bits(1,4)
                W[24]  = V
            W[23] = U+i
            W[25:41] = C
            W[41:89] = B[i]
            C = self.f(W)
        h = concat(list(C)[::-1])
        h.size = self.size
        return pack(h,'>L')

    def PAR(self,l,M,bitlen=None):

        pad = Nullpadding(4096)