------------------------------------------------------------------------------- -- -- The RC6 Encryption algorithm -- ------------------------------------------------------------------------------- package RC6 (sysRC6, IO, RequestType, WordSize, OperationType, ResultType, TextType ) where import RegFile sysRC6 :: Module (IO RequestType ResultType) sysRC6 = mkRC6 {- Like RC5, RC6 is a fully parameterized family of encryption algorithms. A version of RC6 is more accurately specified as RC6-w/r/b where the word size is "w" bits, encryption consists of a nonnegative number of rounds "r," and "b" denotes the length of the encryption key in bytes. Since the AES submission is targetted at w=32, and r=20, we shall use RC6 as shorthand to refers to such versions. When any other value of "w" or "r" is intended in the text, the parameter values will be specified as RC6-w/r. Of particular relevance to the AES effort will be the versions of RC6 with 16-, 21-, and 32-byte keys. For all variants, RC6-w/r/b operates on units of four w-bit words using the following six basic operations. The base-two logarithm of "w" will be denoted by "lg w." a + b integer addition modulo 2 *w a - b integer subtraction modulo 2 *w a b bitwise exclusive-or of w-bit words a x b integer multiplication modulo 2 *w a <<< b rotate the w-bit word a to the left by the amount given by the least significant lg w bits of b a >>> b rotate the w-bit word a to the right by the amount given by the least significant lg w bit of b Note that in the descriptions of RC6 the term "round" is somewhat analogous to the usual DES-like idea of a round: half of the data is updated by the other half; and the two are then swapped. In RC5, the term "half-round" was used to describe this style of action, and an RC5 round was deemed to consist of two half-rounds. This seems to have become a potential cause of confusion, and so RC6 reverts to using the term "round" in a more established way. -} ----------- -- TYPES -- ----------- type WordSize = 32; -- word size in bits type RoundSize = 5; -- number of bits to represent the number of rounds type Rounds = 20; -- non-negative number of rounds of encryption data OperationType = Decode | Encode deriving (Eq, Bits) struct RequestType = op :: OperationType a :: UInt WordSize b :: UInt WordSize c :: UInt WordSize d :: UInt WordSize deriving (Bits) struct TextType = a :: UInt WordSize b :: UInt WordSize c :: UInt WordSize d :: UInt WordSize deriving (Bits) type ResultType = TextType data StepType = Ready | Round (Bit RoundSize) | Final | Done deriving (Eq, Bits) --------------- -- FUNCTIONS -- --------------- logW :: (Log WordSize k) => Integer logW = valueOf k {- -- These general rotate functions, which use toNat to extract the -- right number of Bits for performing the extraction, do not currently -- compile. toNat :: Bit n -> Nat toNat bs = if (valueOf n > 32) then bs[31:0] else bs[fromInteger (valueOf n - 1):0] rotateLeft :: UInt n -> UInt n -> UInt n rotateLeft (UInt a) (UInt b) = UInt ((a << toNat b) | (a >> (fromInteger (valueOf n) - toNat b))) rotateRight :: UInt n -> UInt n -> UInt n rotateRight (UInt a) (UInt b) = UInt ((a >> toNat b) | (a << (fromInteger (valueOf n) - toNat b))) -} rotateLeft :: UInt 32 -> UInt 32 -> UInt 32 rotateLeft a b = (a << pack b) | (a >> pack (32 - b)) rotateRight :: UInt 32 -> UInt 32 -> UInt 32 rotateRight a b = (a >> pack b) | (a << pack (32 - b)) ---------------- -- INTERFACES -- ---------------- interface IO i o = input :: i -> Action output :: Maybe o mkRC6 :: Module (IO RequestType ResultType) mkRC6 = module op :: Reg OperationType -- True for Enc, False for Dec op <- mkRegU a :: Reg (UInt WordSize) a <- mkRegU b :: Reg (UInt WordSize) b <- mkRegU c :: Reg (UInt WordSize) c <- mkRegU d :: Reg (UInt WordSize) d <- mkRegU -- don't ask how these values got here, that's for version 2.0 keyArr :: RegFile (Bit RoundSize) (UInt WordSize) keyArr <- mkRegFile minBound maxBound step :: Reg StepType step <- mkReg Done addRules $ mkRC6Rules op a b c d keyArr step interface input i = action op := i.op a := i.a b := i.b c := i.c d := i.d step := Ready output = if (step == Done) then Valid (TextType { a = a; b = b; c = c; d = d; }) else Invalid ------------ -- RULES --- ------------ mkRC6Rules :: Reg OperationType -> Reg (UInt WordSize) -> Reg (UInt WordSize) -> Reg (UInt WordSize) -> Reg (UInt WordSize) -> RegFile (Bit RoundSize) (UInt WordSize) -> Reg StepType -> Rules mkRC6Rules op a b c d keyArr step = mkRC6EncRules op a b c d keyArr step <+> mkRC6DecRules op a b c d keyArr step ------------------ -- Encode Rules -- ------------------ mkRC6EncRules :: Reg OperationType -> Reg (UInt WordSize) -> Reg (UInt WordSize) -> Reg (UInt WordSize) -> Reg (UInt WordSize) -> RegFile (Bit RoundSize) (UInt WordSize) -> Reg StepType -> Rules mkRC6EncRules op a b c d keyArr step = let isEnc :: Bool isEnc = (op == Encode) t = (b * ((b << 1) + 1)) `rotateLeft` (fromInteger logW) u = (d * ((d << 1) + 1)) `rotateLeft` (fromInteger logW) lastRound :: Bit RoundSize lastRound = fromInteger (valueOf Rounds) in rules when isEnc, step == Ready ==> action b := b + keyArr.sub 0 d := d + keyArr.sub 1 step := Round 1 when isEnc, Round r <- step ==> action a := b b := ((c ^ u) `rotateLeft` t) + keyArr.sub ((r << 1) + 1) c := d d := ((a ^ t) `rotateLeft` u) + keyArr.sub (r << 1) step := if r < lastRound then Round (r + 1) else Final when isEnc, step == Final ==> action a := a + keyArr.sub ((lastRound << 1) + 2) c := c + keyArr.sub ((lastRound << 1) + 3) step := Done ------------------ -- Decode Rules -- ------------------ mkRC6DecRules :: Reg OperationType -> Reg (UInt WordSize) -> Reg (UInt WordSize) -> Reg (UInt WordSize) -> Reg (UInt WordSize) -> RegFile (Bit RoundSize) (UInt WordSize) -> Reg StepType -> Rules mkRC6DecRules op a b c d keyArr step = let isDec :: Bool isDec = (op == Decode) t = (a * ((a << 1) + 1)) `rotateLeft` (fromInteger logW) u = (c * ((c << 1) + 1)) `rotateLeft` (fromInteger logW) lastRound :: Bit RoundSize lastRound = fromInteger (valueOf Rounds) in rules when isDec, step == Ready ==> action a := a - keyArr.sub ((lastRound << 1) + 2) c := c - keyArr.sub ((lastRound << 1) + 3) step := Round lastRound when isDec, Round r <- step ==> action a := ((d - keyArr.sub (r << 1)) `rotateRight` u) ^ t b := a c := ((b - keyArr.sub ((r << 1) + 1)) `rotateRight` t) ^ u d := c step := if r > 1 then Round (r - 1) else Final when isDec, step == Final ==> action b := b - keyArr.sub 0 d := d - keyArr.sub 1 step := Done