vigenere加密

  1. //! Vigenère Cipher
  2. //!
  3. //! # Algorithm
  4. //!
  5. //! Rotate each ascii character by the offset of the corresponding key character.
  6. //! When we reach the last key character, we start over from the first one.
  7. //! This implementation does not rotate unicode characters.
  8. /// Vigenère cipher to rotate plain_text text by key and return an owned String.
  9. pub fn vigenere(plain_text: &str, key: &str) -> String {
  10. // Remove all unicode and non-ascii characters from key
  11. let key: String = key.chars().filter(|&c| c.is_ascii_alphabetic()).collect();
  12. key.to_ascii_lowercase();
  13. let key_len = key.len();
  14. if key_len == 0 {
  15. return String::from(plain_text);
  16. }
  17. let mut index = 0;
  18. plain_text
  19. .chars()
  20. .map(|c| {
  21. if c.is_ascii_alphabetic() {
  22. let first = if c.is_ascii_lowercase() { b'a' } else { b'A' };
  23. let shift = key.as_bytes()[index % key_len] - b'a';
  24. index += 1;
  25. // modulo the distance to keep character range
  26. (first + (c as u8 + shift - first) % 26) as char
  27. } else {
  28. c
  29. }
  30. })
  31. .collect()
  32. }
  33. #[cfg(test)]
  34. mod tests {
  35. use super::*;
  36. #[test]
  37. fn empty() {
  38. assert_eq!(vigenere("", "test"), "");
  39. }
  40. #[test]
  41. fn vigenere_base() {
  42. assert_eq!(
  43. vigenere("LoremIpsumDolorSitAmet", "base"),
  44. "MojinIhwvmVsmojWjtSqft"
  45. );
  46. }
  47. #[test]
  48. fn vigenere_with_spaces() {
  49. assert_eq!(
  50. vigenere(
  51. "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
  52. "spaces"
  53. ),
  54. "Ddrgq ahhuo hgddr uml sbev, ggfheexwljr chahxsemfy tlkx."
  55. );
  56. }
  57. #[test]
  58. fn vigenere_unicode_and_numbers() {
  59. assert_eq!(
  60. vigenere("1 Lorem ⏳ ipsum dolor sit amet Ѡ", "unicode"),
  61. "1 Fbzga ⏳ ltmhu fcosl fqv opin Ѡ"
  62. );
  63. }
  64. #[test]
  65. fn vigenere_unicode_key() {
  66. assert_eq!(
  67. vigenere("Lorem ipsum dolor sit amet", "😉 key!"),
  68. "Vspoq gzwsw hmvsp cmr kqcd"
  69. );
  70. }
  71. #[test]
  72. fn vigenere_empty_key() {
  73. assert_eq!(vigenere("Lorem ipsum", ""), "Lorem ipsum");
  74. }
  75. }