Haskell 哈斯克尔Enigma编码机的时钟式计数器
我正在试着给Enigma编码机编程。我已经设法使转子和反射器工作良好,但我正在努力解决转子的进展 对于任何不熟悉这一点的人。Enigma机器由3个替换密码转子和一个包含13对字符的反射器组成。要对字符进行编码,首先由第一个转子对其进行编码,然后将编码字符传递给第二个转子,然后依次通过一个或多个转子传递给反射器,反射器将此新字符与其配对的字符交换。然后,该成对字符通过转子以相反的方式反向编码,直到最终得到最终编码字符 在对单个字符进行编码之前,转子会移动。如果您有一条很长的消息,在编码任何东西之前,第一个转子会移动一个位置,然后这个字符会通过系统进行编码。然后,在第二个字符编码之前,第一个转子再次移位。转子不断移动,直到再次达到起动位置。第25个字符编码后,第一个转子到达其起始位置,但现在第二个转子移动一个位置。在第二个转子再次转动之前,第一个转子再转动26次。当第二个转子转动26次时,第三个转子转动一次。这种情况会一直发生,直到达到25,此时它们会重置回0,循环再次开始。这让我想起了一个分为小时、分钟和秒的时钟,其中秒在不断地转动,分钟变慢,小时变慢Haskell 哈斯克尔Enigma编码机的时钟式计数器,haskell,character-encoding,encryption,modular-arithmetic,Haskell,Character Encoding,Encryption,Modular Arithmetic,我正在试着给Enigma编码机编程。我已经设法使转子和反射器工作良好,但我正在努力解决转子的进展 对于任何不熟悉这一点的人。Enigma机器由3个替换密码转子和一个包含13对字符的反射器组成。要对字符进行编码,首先由第一个转子对其进行编码,然后将编码字符传递给第二个转子,然后依次通过一个或多个转子传递给反射器,反射器将此新字符与其配对的字符交换。然后,该成对字符通过转子以相反的方式反向编码,直到最终得到最终编码字符 在对单个字符进行编码之前,转子会移动。如果您有一条很长的消息,在编码任何东西之前
我知道这可能可以用模运算编程,但我不知道怎么做?因此,任何帮助都将不胜感激。您可以在命令式语言中使用Haskell的通用计数器 假设你有一些命令代码
def f(x) {
c = 0 ;
while ( c<k ) {
x = g(x,c) ;
c +=1;
return z(x);
}
所以你可以把转子的位置作为一个内部参数
你也可以使用模式匹配
RotorState = (Int,Int,Int)
turnRotor :: RotorState ->RotorState
turnRotor (25, 25 , 25 ) = (0 , 0 , 0)
turnRotor (_ , 25 , 25 ) = (_+1, 0 , 0)
turnRotor (_ , __ , 25 ) = (_ , __+1,0)
turnRotor (_ , __ , ___ ) = (_ , __, ___+1)
玩得开心!我希望这是有帮助的 您可以在命令式语言中使用Haskell的通用计数器等价物 假设你有一些命令代码
def f(x) {
c = 0 ;
while ( c<k ) {
x = g(x,c) ;
c +=1;
return z(x);
}
所以你可以把转子的位置作为一个内部参数
你也可以使用模式匹配
RotorState = (Int,Int,Int)
turnRotor :: RotorState ->RotorState
turnRotor (25, 25 , 25 ) = (0 , 0 , 0)
turnRotor (_ , 25 , 25 ) = (_+1, 0 , 0)
turnRotor (_ , __ , 25 ) = (_ , __+1,0)
turnRotor (_ , __ , ___ ) = (_ , __, ___+1)
玩得开心!我希望这是有帮助的 从机器的角度来看,转子是两件事:
- 它是从一个符号到另一个符号的函数
- 它可以成为另一个功能
newtype Symbol = Symbol {representation :: Int}
data Rotor = Rotor {
transformation :: Symbol -> Symbol,
next :: Rotor
}
如果机器从反射中知道对称性,它可能是这样的
data Rotor = Rotor {
forward :: Symbol -> Symbol,
backward :: Symbol -> Symbol,
next :: Rotor
}
(您也可以使用类似于[(Symbol->Symbol,Symbol->Symbol)]
)
现在,我们如何构造一个转子?让我们来定义一个示例转子,IC
rotorICdefinition = map symbol $ "DMTWSILRUYQNKFEJCAZBPGXOHV"
现在,symbol需要有类型Char->symbol
。像这样的事情应该可以
symbol :: Char -> Symbol
symbol x = Symbol $ ord x - ord 'A'
ord
中有一堆魔力。它已经知道字母表的顺序了。例如:
Prelude Data.Char> map ord "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
[65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90]
接下来,我们希望能够根据转子的定义来制作转子
rotorIC :: Rotor
rotorIC = makeRotor rotorICdefinition
因此,makeRotor
应具有以下类型
makeRotor :: [Symbol] -> Rotor
我们可以把它定义为
makeRotor definition = makeRotor' 0
where
makeRotor' steps = Rotor {
forward = forwardLookup steps,
backward = reverseLookup steps,
next = makeRotor' ((steps+1) `mod` symbolModulus)
}
forwardLookupTable = array (minBound, maxBound) (zip symbols definition)
reverseLookupTable = array (minBound, maxBound) (zip definition symbols)
forwardLookup = lookup forwardLookupTable
reverseLookup = lookup reverseLookupTable
lookup lookupTable steps = (lookupTable !) . Symbol . (`mod` symbolModulus) . (+ steps) . representation
这里发生了很多事情。我们制造了一个无限的转子流,每一个转子都比前一个旋转一步,从一个旋转了0步的转子开始<makeRotor'
中的code>steps
正在跟踪其旋转了多少步。转子
包括向前
和向后
变换,其中考虑了转子旋转的步数。下一个
转子是相同的,但又旋转了一步。为了避免最终溢出一个整数,我们取它的模mod
存在的符号数,symboldommodule
。(有更有效的方法可以做到这一点)。这两个查找基于一次构建的查找表,将范围(minBound,maxBound)
中的每个符号映射到它根据定义应该是什么。lookup
本身就是获取输入,添加步骤数,获取符号数,然后返回查找表中该位置的内容
这要求我们定义新出现的minBound
、maxBound
、symbols
和symbolModules
:
instance Bounded (Symbol) where
minBound = symbol 'A'
maxBound = symbol 'Z'
symbolModulus = (representation maxBound) - (representation minBound) + 1
-- This could have some other definition
symbols = map symbol $ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
我们将添加一个小UI,并将整个程序放在一起:
module Main (
main
) where
import Data.Char
import Data.Array -- requires array package
import System.IO
main = go rotorIC
where go rotor = do
putStr "Input : "
hFlush stdout
command <- getLine
case command of
"next" -> go (next rotor)
[] -> return ()
text -> case all (inRange (char minBound, char maxBound)) text of
True -> do
putStrLn . ("Forward : " ++) $ map (char . forward rotor . symbol) text
putStrLn . ("Backward: " ++)$ map (char . backward rotor . symbol) text
go rotor
_ -> do
putStrLn "Not all of the input was symbols"
go rotor
newtype Symbol = Symbol {representation :: Int} deriving (Eq, Ord, Ix)
symbol :: Char -> Symbol
symbol x = Symbol $ ord x - ord 'A'
char :: Symbol -> Char
char x = chr $ representation x + ord 'A'
instance Bounded (Symbol) where
minBound = symbol 'A'
maxBound = symbol 'Z'
symbolModulus = (representation maxBound) - (representation minBound) + 1
-- This could have some other definition
symbols = map symbol $ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
data Rotor = Rotor {
forward :: Symbol -> Symbol,
backward :: Symbol -> Symbol,
next :: Rotor
}
rotorICdefinition = map symbol $ "DMTWSILRUYQNKFEJCAZBPGXOHV"
rotorIC :: Rotor
rotorIC = makeRotor rotorICdefinition
makeRotor :: [Symbol] -> Rotor
makeRotor definition = makeRotor' 0
where
makeRotor' steps = Rotor {
forward = forwardLookup steps,
backward = reverseLookup steps,
next = makeRotor' ((steps+1) `mod` symbolModulus)
}
forwardLookupTable = array (minBound, maxBound) (zip symbols definition)
reverseLookupTable = array (minBound, maxBound) (zip definition symbols)
forwardLookup = lookup forwardLookupTable
reverseLookup = lookup reverseLookupTable
lookup lookupTable steps = (lookupTable !) . Symbol . (`mod` symbolModulus) . (+ steps) . representation
如果我们把rotorICdefinition
放在开头,我们将返回字母表的前六个字母作为向后转换:
Input : DMTWSIL
Forward : WKBXZUN
Backward: ABCDEFG
如果我们进入转子的下一步,我们会得到非常不同的结果:
Input : next
Input : ABCDEFG
Forward : MTWSILR
Backward: TQAONVY
但如果我们在“A”前面加上以1开头的字母,我们又会得到我们的定义:
Input : ZABCDEF
Forward : DMTWSIL
Backward: RTQAONV
在转子上再进行25次下一步后,我们回到了开始的位置:
Input : next
(25 times total)
Input : next
Input : ABCDEFG
Forward : DMTWSIL
Backward: RTQAONV
从机器的角度来看,转子是两件事:
- 它是从一个符号到另一个符号的函数
- 它可以成为另一个功能
我们可以为它编写一个类型,如下所示:
newtype Symbol = Symbol {representation :: Int}
data Rotor = Rotor {
transformation :: Symbol -> Symbol,
next :: Rotor
}
如果机器从反射中知道对称性,它可能是这样的
data Rotor = Rotor {
forward :: Symbol -> Symbol,
backward :: Symbol -> Symbol,
next :: Rotor
}
(您也可以使用类似于[(Symbol->Symbol,Symbol->Symbol)]
)
现在,我们如何构造一个转子?让我们来定义一个示例转子,IC
rotorICdefinition = map symbol $ "DMTWSILRUYQNKFEJCAZBPGXOHV"
现在,symbol需要有类型Char->symbol
。像这样的事情应该可以
symbol :: Char -> Symbol
symbol x = Symbol $ ord x - ord 'A'
ord
中有一堆魔力。它已经知道字母表的顺序了。例如:
Prelude Data.Char> map ord "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
[65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90]
接下来,我们希望能够根据转子的定义来制作转子
rotorIC :: Rotor
rotorIC = makeRotor rotorICdefinition
因此,makeRotor
应具有以下类型
makeRotor :: [Symbol] -> Rotor
我们可以