返回文章列表

文章

Get Programming with Haskell-15

每个人都喜欢能与朋友秘密通信的想法。在这个总结项目中,你将运用你对类型和类型类的知识,构建几个示例密码。密码(cipher)在密码学中是一种对信息进行编码的方法,使他人无法阅读。密码是密码学的基础,但它们本身也非常有趣、值得玩味。你将首先接触一个容易实现也容易破解的密码,然后进一步了解字符加密的基础知识,最后你将构建一个不可破解的密码!

#
总结篇:**秘密信息!** ## 1. 给初学者的密码术:ROT13 大多数人第一次接触密码术是在小学时,当他们试图给朋友发送秘密消息时。最常见的一种加密方法就是 ROT13。ROT 是 “rotation”(旋转)的缩写,而 13 则表示每个字母要向后“旋转”13位。 ROT13 的加密方式是将句子中的每个字母向后移动13个字母。例如,字母 `a` 是字母表中的第一个字母,向后数13个字母是 `n`,所以在编码时,`a` 就会被替换成 `n`。 让我们尝试使用 ROT13 发送一条秘密消息来帮助你理解它。你要发送的消息是: **“Jean-Paul likes Simone.”** 在这个例子中,我们将**大写字母视作小写字母**,并**忽略空格和任何特殊字符**。想象一个“解码环”可以帮助你更好地理解 ROT13 的原理,就像下图中展示的那样。 ![](https://prod-files-secure.s3.us-west-2.amazonaws.com/4b1b167f-4b52-4031-8233-f4f2689af574/47932e61-b5e2-4cf0-a29f-9356ad179d37/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4664IR6CEF3%2F20260827%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260827T175111Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEHEaCXVzLXdlc3QtMiJHMEUCIFVbBsI%2Fh%2Bok3ljLxggAzdrkTjKUW%2FvMRlhnqZaX%2BN0uAiEAzKRhuWU2gjvHQRV2g9a5xEuxTyQ4skogSeUg2fogyvEq%2FwMIOhAAGgw2Mzc0MjMxODM4MDUiDMqrFk0Q%2Fu%2ByahgxNSrcA1hfVY4VrTYTd6mHY3yAxVl1xHm04IrkdFidRVRqaHXhtP5X%2BvASTBdTxBuVKhnppo6pCtDOdQmrikFjReh94NL9t4r17RYE4zlmbBmEXD2mhHooRv5Yk1Tf0T62PBCDjdb8UtkOyattmyUm8E1rIJ3HHjNwzcx95qFfw%2Bwwb9CZzwr7hvuQbIsopyw0tuAfjOvzIHX6wwSNgyicPZf66tq9s4eoFOV2kbW%2BJJuYO5BGjtfWnf8ViDCWWyc%2F9knxtfCw856EzVOCtm0wh%2F5B2yjEgtyZQ%2FOQnir70mSnHNn3qI%2FctDCCK8MH4dsJPsrmGQSbfQYqSYZMbIvnmFpmmTYgrqGBbAdcpHQ0FUh%2ByR8clU%2BfuFtdWqirjPlZESnT3MDJfriGiLRJP%2FNZxkSPCPbx2o2SdI3oCYYpyOEQx2CGI%2BMORLGQ5MwzXR1NopEetAFHpok3S7YG%2Fi8tdFGxYGtMMDSSckUa%2BYM1caN8w80f%2B909yH7PE81K%2B2t%2FVPMxh2umriVggbrg75iYTMg82KjmQi1cMCj7s7OEefykCk%2BHlayUbJWRL%2FePOC%2Fgp%2FaQX0WPUu5RRQVKtU1rO3Jkob9gG%2FwN29icJ1t37FpzFy4zUy5F7NOPPKcd0eygMOvMwdQGOqUBl397%2FK5bwF7xnlMWo7joLiTu1aCl3PuafsTikarY8ruDc%2FPl3DtZw5uiuSj3obXlBwENCYFclIzsGuv9JsjVnOJ1mBMTIbrDttktHnzmHzdNHiXV9PM6%2FHjtTb8tdjGUMmJWfXX9mPYAThJste8tExujG4ydLgbKjbPdJgXijEIUj%2FG38Uv0AylTmwKlMGZkZyDl0jBbmm%2FMf5V5z%2BoKyfh%2F3dNQ&X-Amz-Signature=dbb016c04c090bb378591977a5f30fdac308973e69b1ee879c70eaa085ddfead&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) 利用这个解码环,你可以逐个翻译每个字母,例如: - `j` 对应 `w` - `e` 对应 `r` - `a` 对应 `n` - `n` 对应 `a` - `p` 对应 `c` - ……以此类推 最终,你得到加密后的信息: **“Wrna-Cnhy yvxrf Fvzbar.”** 之所以选择旋转 13 位,是因为英语字母有26个,旋转13位正好是一半。所以**执行两次 ROT13 加密会得到原始信息**。比如对 `n` 进行 ROT13,会回到 `a`。更有趣的是,对加密后的“Wrna-Cnhy yvxrf Fvzbar”再次执行 ROT13,你会得到原文:“Jean-Paul likes Simone”。这种**对称性**在密码系统中很常见,也非常重要。 ### 1. 实现你自己的 ROT 密码 现在你已经了解了 ROT13 是如何工作的,我们来为 Haskell 的 `Char` 类型实现一个类似的密码,这样你就可以对字符串进行编码和解码了。在前面的例子中,你使用了 13 作为旋转的值,是因为英文字母共有 26 个字符,而你想将字符绕字母表旋转一半来加密信息。在处理 `"Jean-Paul likes Simone"` 这个句子时,你已经遇到一个问题:必须忽略空格和特殊字符。 理想情况下,你希望能够在任意字符系统中对所有 N 个字符进行旋转。你想要的,是一个通用的 `rotN` 函数,它可以在具有 N 个元素的任意“字母表”系统中进行旋转。我们先来看一下如何创建一个简单的四字符字母表,供你用来进行实验。 ```haskell -- 定义四字母的字母表 data FourLetterAlphabet = L1 | L2 | L3 | L4 deriving (Show, Enum, Bounded) ``` 重要的是要注意你派生了哪些类型类以及为什么要这么做: - 你为你的字母表添加了 `deriving Show`,这样可以更方便地在 GHCi 中使用这个类型。 - 你添加了 `deriving Enum`,因为这允许你将数据构造器自动转换为 `Int` 类型。能够将字母转换为整数,意味着你可以通过简单的数学运算来实现字母的轮换。你可以使用 `fromEnum` 将字母转换成整数,再用 `toEnum` 把整数转换回字母。 - 最后,你添加了 `deriving Bounded`,因为它提供了 `maxBound` 和 `minBound`,帮助你知道字母表的循环范围。 现在你已经有了一个可以操作的字母表类型,接下来可以考虑这个密码如何实际工作了。 ### 2. rotN算法 这是 `rotN` 函数的实现方式: 1. 你传入字母表的大小和一个你想要轮换的字母。 2. 使用 `div` 函数来计算字母表的中间位置。记住,`div` 与 `/` 不同,它会将整数除法结果舍去小数部分。例如,`4 div 2` 是 `2`,而 `5 div 2` 也是 `2`。 `div` 的结果告诉你轮换字母时的偏移量。 3. 要进行轮换,你将字母的 `Enum` 值(整数表示)加上字母表大小的一半。由于枚举的大小是有限的,添加一半的字母表大小可能会导致结果超出 `Enum` 范围。为了解决这个问题,你可以通过字母表的大小取模,来确保偏移量不会超过字母表的范围。 4. 最后,使用 `toEnum` 将计算得到的整数值转换回字母。 这个 `rotN` 函数可以应用于任何同时属于 `Bounded` 和 `Enum` 类型类的类型。 示例代码: ```haskell -- 可以工作在所有字符表上的通用的ortN函数 rotN :: (Bounded a, Enum a) => Int -> a -> a rotN alphabetSize c = toEnum rotation where halfAlphabet = alphabetSize `div` 2 offset = fromEnum c + halfAlphabet rotation = offset `mod` alphabetSize ``` ghci的测试结果如下: ![](https://prod-files-secure.s3.us-west-2.amazonaws.com/4b1b167f-4b52-4031-8233-f4f2689af574/cb2743de-ed30-4dbb-a98a-ff342f527c2f/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4664IR6CEF3%2F20260827%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260827T175111Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEHEaCXVzLXdlc3QtMiJHMEUCIFVbBsI%2Fh%2Bok3ljLxggAzdrkTjKUW%2FvMRlhnqZaX%2BN0uAiEAzKRhuWU2gjvHQRV2g9a5xEuxTyQ4skogSeUg2fogyvEq%2FwMIOhAAGgw2Mzc0MjMxODM4MDUiDMqrFk0Q%2Fu%2ByahgxNSrcA1hfVY4VrTYTd6mHY3yAxVl1xHm04IrkdFidRVRqaHXhtP5X%2BvASTBdTxBuVKhnppo6pCtDOdQmrikFjReh94NL9t4r17RYE4zlmbBmEXD2mhHooRv5Yk1Tf0T62PBCDjdb8UtkOyattmyUm8E1rIJ3HHjNwzcx95qFfw%2Bwwb9CZzwr7hvuQbIsopyw0tuAfjOvzIHX6wwSNgyicPZf66tq9s4eoFOV2kbW%2BJJuYO5BGjtfWnf8ViDCWWyc%2F9knxtfCw856EzVOCtm0wh%2F5B2yjEgtyZQ%2FOQnir70mSnHNn3qI%2FctDCCK8MH4dsJPsrmGQSbfQYqSYZMbIvnmFpmmTYgrqGBbAdcpHQ0FUh%2ByR8clU%2BfuFtdWqirjPlZESnT3MDJfriGiLRJP%2FNZxkSPCPbx2o2SdI3oCYYpyOEQx2CGI%2BMORLGQ5MwzXR1NopEetAFHpok3S7YG%2Fi8tdFGxYGtMMDSSckUa%2BYM1caN8w80f%2B909yH7PE81K%2B2t%2FVPMxh2umriVggbrg75iYTMg82KjmQi1cMCj7s7OEefykCk%2BHlayUbJWRL%2FePOC%2Fgp%2FaQX0WPUu5RRQVKtU1rO3Jkob9gG%2FwN29icJ1t37FpzFy4zUy5F7NOPPKcd0eygMOvMwdQGOqUBl397%2FK5bwF7xnlMWo7joLiTu1aCl3PuafsTikarY8ruDc%2FPl3DtZw5uiuSj3obXlBwENCYFclIzsGuv9JsjVnOJ1mBMTIbrDttktHnzmHzdNHiXV9PM6%2FHjtTb8tdjGUMmJWfXX9mPYAThJste8tExujG4ydLgbKjbPdJgXijEIUj%2FG38Uv0AylTmwKlMGZkZyDl0jBbmm%2FMf5V5z%2BoKyfh%2F3dNQ&X-Amz-Signature=91e973e25dea39f668b1f861ae4486e84a9870f462ca2eb1cacd9d55aed56f99&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject)