# 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
# -*- coding: utf-8 -*-

# This code is part of crysp
# Copyright (C) 2008 Axel Tillequin (bdcht3@gmail.com)
# published under GPLv2 license



#------------------------------------------------------------------------------
class MD4(object):
    def __init__(self):
        self.size = 128
        self.blocksize = 512
        self.wsize = 32
        # set functions and constants:
        f = lambda x,y,z: z^(x&(y^z))
        g = lambda x,y,z: (x&y)|(x&z)|(y&z)
        h = lambda x,y,z: x^y^z
        self.ft = [f,g,h]
        self.K = [0,0x5a827999,0x6ed9eba1]
        self.st = [(3,7,11,19),(3,5,9,13),(3,9,11,15)]
        self.initstate()

    def initstate(self):
        H = [0x67452301,0xefcdab89,0x98badcfe,0x10325476]
        self.H = [Bits(v,self.wsize) for v in H]

# 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

# -*- coding: utf-8 -*-

# This code is part of crysp
# Copyright (C) 2008 Axel Tillequin (bdcht3@gmail.com)
# published under GPLv2 license



#------------------------------------------------------------------------------
class MD4(object):
    def __init__(self):
        self.size = 128
        self.blocksize = 512
        self.wsize = 32
        # set functions and constants:
        f = lambda x,y,z: z^(x&(y^z))
        g = lambda x,y,z: (x&y)|(x&z)|(y&z)
        h = lambda x,y,z: x^y^z
        self.ft = [f,g,h]
        self.K = [0,0x5a827999,0x6ed9eba1]
        self.st = [(3,7,11,19),(3,5,9,13),(3,9,11,15)]
        self.initstate()

    def initstate(self):
        H = [0x67452301,0xefcdab89,0x98badcfe,0x10325476]
        self.H = [Bits(v,self.wsize) for v in H]

        self.padmethod = MDpadding(self.blocksize,self.wsize)