From 21f2a5a0fb3354eedd4e20d7ae0b01a4f22ac690 Mon Sep 17 00:00:00 2001 From: Kasim Kaizer <155087257+KasimKaizer@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:07:17 +0400 Subject: [PATCH 1/8] feat(exercises): add testcases and metadata files for affine-cipher --- .../affine-cipher/.docs/instructions.md | 74 +++++++++ .../practice/affine-cipher/.meta/config.json | 17 ++ exercises/practice/affine-cipher/.meta/gen.go | 93 +++++++++++ .../practice/affine-cipher/.meta/tests.toml | 55 +++++++ .../practice/affine-cipher/affine_cipher.go | 1 + .../affine-cipher/affine_cipher_test.go | 1 + .../practice/affine-cipher/cases_test.go | 149 ++++++++++++++++++ exercises/practice/affine-cipher/go.mod | 3 + 8 files changed, 393 insertions(+) create mode 100644 exercises/practice/affine-cipher/.docs/instructions.md create mode 100644 exercises/practice/affine-cipher/.meta/config.json create mode 100644 exercises/practice/affine-cipher/.meta/gen.go create mode 100644 exercises/practice/affine-cipher/.meta/tests.toml create mode 100644 exercises/practice/affine-cipher/affine_cipher.go create mode 100644 exercises/practice/affine-cipher/affine_cipher_test.go create mode 100644 exercises/practice/affine-cipher/cases_test.go create mode 100644 exercises/practice/affine-cipher/go.mod diff --git a/exercises/practice/affine-cipher/.docs/instructions.md b/exercises/practice/affine-cipher/.docs/instructions.md new file mode 100644 index 000000000..26ce15342 --- /dev/null +++ b/exercises/practice/affine-cipher/.docs/instructions.md @@ -0,0 +1,74 @@ +# Instructions + +Create an implementation of the affine cipher, an ancient encryption system created in the Middle East. + +The affine cipher is a type of monoalphabetic substitution cipher. +Each character is mapped to its numeric equivalent, encrypted with a mathematical function and then converted to the letter relating to its new numeric value. +Although all monoalphabetic ciphers are weak, the affine cipher is much stronger than the atbash cipher, because it has many more keys. + +[//]: # " monoalphabetic as spelled by Merriam-Webster, compare to polyalphabetic " + +## Encryption + +The encryption function is: + +```text +E(x) = (ai + b) mod m +``` + +Where: + +- `i` is the letter's index from `0` to the length of the alphabet - 1 +- `m` is the length of the alphabet. + For the Roman alphabet `m` is `26`. +- `a` and `b` are integers which make the encryption key + +Values `a` and `m` must be _coprime_ (or, _relatively prime_) for automatic decryption to succeed, i.e., they have number `1` as their only common factor (more information can be found in the [Wikipedia article about coprime integers][coprime-integers]). +In case `a` is not coprime to `m`, your program should indicate that this is an error. +Otherwise it should encrypt or decrypt with the provided key. + +For the purpose of this exercise, digits are valid input but they are not encrypted. +Spaces and punctuation characters are excluded. +Ciphertext is written out in groups of fixed length separated by space, the traditional group size being `5` letters. +This is to make it harder to guess encrypted text based on word boundaries. + +## Decryption + +The decryption function is: + +```text +D(y) = (a^-1)(y - b) mod m +``` + +Where: + +- `y` is the numeric value of an encrypted letter, i.e., `y = E(x)` +- it is important to note that `a^-1` is the modular multiplicative inverse (MMI) of `a mod m` +- the modular multiplicative inverse only exists if `a` and `m` are coprime. + +The MMI of `a` is `x` such that the remainder after dividing `ax` by `m` is `1`: + +```text +ax mod m = 1 +``` + +More information regarding how to find a Modular Multiplicative Inverse and what it means can be found in the [related Wikipedia article][mmi]. + +## General Examples + +- Encrypting `"test"` gives `"ybty"` with the key `a = 5`, `b = 7` +- Decrypting `"ybty"` gives `"test"` with the key `a = 5`, `b = 7` +- Decrypting `"ybty"` gives `"lqul"` with the wrong key `a = 11`, `b = 7` +- Decrypting `"kqlfd jzvgy tpaet icdhm rtwly kqlon ubstx"` gives `"thequickbrownfoxjumpsoverthelazydog"` with the key `a = 19`, `b = 13` +- Encrypting `"test"` with the key `a = 18`, `b = 13` is an error because `18` and `26` are not coprime + +## Example of finding a Modular Multiplicative Inverse (MMI) + +Finding MMI for `a = 15`: + +- `(15 * x) mod 26 = 1` +- `(15 * 7) mod 26 = 1`, ie. `105 mod 26 = 1` +- `7` is the MMI of `15 mod 26` + +[mmi]: https://en.wikipedia.org/wiki/Modular_multiplicative_inverse +[coprime-integers]: https://en.wikipedia.org/wiki/Coprime_integers diff --git a/exercises/practice/affine-cipher/.meta/config.json b/exercises/practice/affine-cipher/.meta/config.json new file mode 100644 index 000000000..bcb6ea87b --- /dev/null +++ b/exercises/practice/affine-cipher/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": [], + "files": { + "solution": [ + "affine_cipher.go" + ], + "test": [ + "affine_cipher_test.go" + ], + "example": [ + ".meta/example.go" + ] + }, + "blurb": "Create an implementation of the Affine cipher, an ancient encryption algorithm from the Middle East.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Affine_cipher" +} diff --git a/exercises/practice/affine-cipher/.meta/gen.go b/exercises/practice/affine-cipher/.meta/gen.go new file mode 100644 index 000000000..96eb0ac50 --- /dev/null +++ b/exercises/practice/affine-cipher/.meta/gen.go @@ -0,0 +1,93 @@ +package main + +import ( + "log" + "text/template" + + "../../../../gen" +) + +func main() { + t, err := template.New("").Parse(tmpl) + if err != nil { + log.Fatal(err) + } + j := map[string]interface{}{ + "encode": &[]testCase{}, + "decode": &[]testCase{}, + } + if err := gen.Gen("affine-cipher", j, t); err != nil { + log.Fatal(err) + } +} + +type testCase struct { + Description string `json:"description"` + Input struct { + Phrase string `json:"phrase"` + Key struct { + Num1 int `json:"a"` + Num2 int `json:"b"` + } `json:"key"` + } `json:"input"` + Expected interface{} `json:"expected"` +} + +func (t testCase) ExpectedString() string { + m, ok := t.Expected.(string) + if !ok { + return "" + } + return m +} + +func (t testCase) Error() bool { + m, ok := t.Expected.(map[string]interface{}) + if !ok { + return false + } + _, ok = m["error"].(string) + if !ok { + return false + } + return true +} + +// Template to generate encode and decode test cases. +var tmpl = `package affinecipher + +{{.Header}} + +type testCase struct { + description string + inputPhrase string + inputA int + inputB int + expectError bool + expected string +} + +var encodeTests = []testCase{ +{{range .J.encode}}{ + description: {{printf "%q" .Description}}, + inputPhrase: {{printf "%q" .Input.Phrase}}, + inputA: {{printf "%d" .Input.Key.Num1}}, + inputB: {{printf "%d" .Input.Key.Num2}}, + expectError: {{printf "%t" .Error}}, + expected: {{printf "%q" .ExpectedString}}, + }, +{{end}} +} + +var decodeTests = []testCase{ +{{range .J.decode}}{ + description: {{printf "%q" .Description}}, + inputPhrase: {{printf "%q" .Input.Phrase}}, + inputA: {{printf "%d" .Input.Key.Num1}}, + inputB: {{printf "%d" .Input.Key.Num2}}, + expectError: {{printf "%t" .Error}}, + expected: {{printf "%q" .ExpectedString}}, + }, +{{end}} +} +` diff --git a/exercises/practice/affine-cipher/.meta/tests.toml b/exercises/practice/affine-cipher/.meta/tests.toml new file mode 100644 index 000000000..8e5ca02f5 --- /dev/null +++ b/exercises/practice/affine-cipher/.meta/tests.toml @@ -0,0 +1,55 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[2ee1d9af-1c43-416c-b41b-cefd7d4d2b2a] +description = "encode -> encode yes" + +[785bade9-e98b-4d4f-a5b0-087ba3d7de4b] +description = "encode -> encode no" + +[2854851c-48fb-40d8-9bf6-8f192ed25054] +description = "encode -> encode OMG" + +[bc0c1244-b544-49dd-9777-13a770be1bad] +description = "encode -> encode O M G" + +[381a1a20-b74a-46ce-9277-3778625c9e27] +description = "encode -> encode mindblowingly" + +[6686f4e2-753b-47d4-9715-876fdc59029d] +description = "encode -> encode numbers" + +[c93a8a4d-426c-42ef-9610-76ded6f7ef57] +description = "encode -> encode all the letters" + +[0673638a-4375-40bd-871c-fb6a2c28effb] +description = "encode -> encode with a not coprime to m" + +[3f0ac7e2-ec0e-4a79-949e-95e414953438] +description = "decode -> decode exercism" + +[241ee64d-5a47-4092-a5d7-7939d259e077] +description = "decode -> decode a sentence" + +[33fb16a1-765a-496f-907f-12e644837f5e] +description = "decode -> decode numbers" + +[20bc9dce-c5ec-4db6-a3f1-845c776bcbf7] +description = "decode -> decode all the letters" + +[623e78c0-922d-49c5-8702-227a3e8eaf81] +description = "decode -> decode with no spaces in input" + +[58fd5c2a-1fd9-4563-a80a-71cff200f26f] +description = "decode -> decode with too many spaces" + +[b004626f-c186-4af9-a3f4-58f74cdb86d5] +description = "decode -> decode with a not coprime to m" diff --git a/exercises/practice/affine-cipher/affine_cipher.go b/exercises/practice/affine-cipher/affine_cipher.go new file mode 100644 index 000000000..a0b516850 --- /dev/null +++ b/exercises/practice/affine-cipher/affine_cipher.go @@ -0,0 +1 @@ +package affinecipher diff --git a/exercises/practice/affine-cipher/affine_cipher_test.go b/exercises/practice/affine-cipher/affine_cipher_test.go new file mode 100644 index 000000000..a0b516850 --- /dev/null +++ b/exercises/practice/affine-cipher/affine_cipher_test.go @@ -0,0 +1 @@ +package affinecipher diff --git a/exercises/practice/affine-cipher/cases_test.go b/exercises/practice/affine-cipher/cases_test.go new file mode 100644 index 000000000..f4c169cee --- /dev/null +++ b/exercises/practice/affine-cipher/cases_test.go @@ -0,0 +1,149 @@ +package affinecipher + +// This is an auto-generated file. Do not change it manually. Run the generator to update the file. +// See https://github.com/exercism/go#synchronizing-tests-and-instructions +// Source: exercism/problem-specifications +// Commit: d137db1 Format using prettier (#1917) + +type testCase struct { + description string + inputPhrase string + inputA int + inputB int + expectError bool + expected string +} + +var encodeTests = []testCase{ + { + description: "encode yes", + inputPhrase: "yes", + inputA: 5, + inputB: 7, + expectError: false, + expected: "xbt", + }, + { + description: "encode no", + inputPhrase: "no", + inputA: 15, + inputB: 18, + expectError: false, + expected: "fu", + }, + { + description: "encode OMG", + inputPhrase: "OMG", + inputA: 21, + inputB: 3, + expectError: false, + expected: "lvz", + }, + { + description: "encode O M G", + inputPhrase: "O M G", + inputA: 25, + inputB: 47, + expectError: false, + expected: "hjp", + }, + { + description: "encode mindblowingly", + inputPhrase: "mindblowingly", + inputA: 11, + inputB: 15, + expectError: false, + expected: "rzcwa gnxzc dgt", + }, + { + description: "encode numbers", + inputPhrase: "Testing,1 2 3, testing.", + inputA: 3, + inputB: 4, + expectError: false, + expected: "jqgjc rw123 jqgjc rw", + }, + { + description: "encode deep thought", + inputPhrase: "Truth is fiction.", + inputA: 5, + inputB: 17, + expectError: false, + expected: "iynia fdqfb ifje", + }, + { + description: "encode all the letters", + inputPhrase: "The quick brown fox jumps over the lazy dog.", + inputA: 17, + inputB: 33, + expectError: false, + expected: "swxtj npvyk lruol iejdc blaxk swxmh qzglf", + }, + { + description: "encode with a not coprime to m", + inputPhrase: "This is a test.", + inputA: 6, + inputB: 17, + expectError: true, + expected: "", + }, +} + +var decodeTests = []testCase{ + { + description: "decode exercism", + inputPhrase: "tytgn fjr", + inputA: 3, + inputB: 7, + expectError: false, + expected: "exercism", + }, + { + description: "decode a sentence", + inputPhrase: "qdwju nqcro muwhn odqun oppmd aunwd o", + inputA: 19, + inputB: 16, + expectError: false, + expected: "anobstacleisoftenasteppingstone", + }, + { + description: "decode numbers", + inputPhrase: "odpoz ub123 odpoz ub", + inputA: 25, + inputB: 7, + expectError: false, + expected: "testing123testing", + }, + { + description: "decode all the letters", + inputPhrase: "swxtj npvyk lruol iejdc blaxk swxmh qzglf", + inputA: 17, + inputB: 33, + expectError: false, + expected: "thequickbrownfoxjumpsoverthelazydog", + }, + { + description: "decode with no spaces in input", + inputPhrase: "swxtjnpvyklruoliejdcblaxkswxmhqzglf", + inputA: 17, + inputB: 33, + expectError: false, + expected: "thequickbrownfoxjumpsoverthelazydog", + }, + { + description: "decode with too many spaces", + inputPhrase: "vszzm cly yd cg qdp", + inputA: 15, + inputB: 16, + expectError: false, + expected: "jollygreengiant", + }, + { + description: "decode with a not coprime to m", + inputPhrase: "Test", + inputA: 13, + inputB: 5, + expectError: true, + expected: "", + }, +} diff --git a/exercises/practice/affine-cipher/go.mod b/exercises/practice/affine-cipher/go.mod new file mode 100644 index 000000000..8aff52e85 --- /dev/null +++ b/exercises/practice/affine-cipher/go.mod @@ -0,0 +1,3 @@ +module affine-cipher + +go 1.18 From a4a4375050327a0819ee3a1023695bafcb81e58c Mon Sep 17 00:00:00 2001 From: Kasim Kaizer <155087257+KasimKaizer@users.noreply.github.com> Date: Mon, 22 Apr 2024 19:16:59 +0400 Subject: [PATCH 2/8] update(affine-cipher): add tests and a stud file for the exercise --- .../practice/affine-cipher/affine_cipher.go | 8 +++ .../affine-cipher/affine_cipher_test.go | 60 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/exercises/practice/affine-cipher/affine_cipher.go b/exercises/practice/affine-cipher/affine_cipher.go index a0b516850..aa33a045a 100644 --- a/exercises/practice/affine-cipher/affine_cipher.go +++ b/exercises/practice/affine-cipher/affine_cipher.go @@ -1 +1,9 @@ package affinecipher + +func Encode(text string, a, b int) (string, error) { + panic("Please implement the Encode function") +} + +func Decode(text string, a, b int) (string, error) { + panic("Please implement the Decode function") +} diff --git a/exercises/practice/affine-cipher/affine_cipher_test.go b/exercises/practice/affine-cipher/affine_cipher_test.go index a0b516850..99241ee8d 100644 --- a/exercises/practice/affine-cipher/affine_cipher_test.go +++ b/exercises/practice/affine-cipher/affine_cipher_test.go @@ -1 +1,61 @@ package affinecipher + +import ( + "log" + "testing" +) + +func testRunner( + t *testing.T, + name string, + op func(string, int, int) (string, error), + testCases []testCase, +) { + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + got, err := op(tc.inputPhrase, tc.inputA, tc.inputB) + if err != nil { + if !tc.expectError { + log.Fatalf("%s(%s, %d, %d) returned unexpected error %v", name, tc.inputPhrase, tc.inputA, tc.inputB, err) + } + return + } + if tc.expectError { + log.Fatalf("%s(%s, %d, %d) expected error, got %v", name, tc.inputPhrase, tc.inputA, tc.inputB, got) + } + if tc.expected != got { + log.Fatalf("%s(%s, %d, %d) = %s, expected: %s", name, tc.inputPhrase, tc.inputA, tc.inputB, got, tc.expected) + } + }) + } +} +func TestEncode(t *testing.T) { + testRunner(t, "Encode", Encode, encodeTests) +} + +func TestDecode(t *testing.T) { + testRunner(t, "Decode", Decode, decodeTests) +} + +func benchmarkRunner( + b *testing.B, + op func(string, int, int) (string, error), + testCases []testCase, +) { + if testing.Short() { + b.Skip("skipping benchmark in short mode.") + } + for i := 0; i < b.N; i++ { + for _, tc := range testCases { + op(tc.inputPhrase, tc.inputA, tc.inputB) + } + } +} + +func BenchmarkEncode(b *testing.B) { + benchmarkRunner(b, Encode, encodeTests) +} + +func BenchmarkDecode(b *testing.B) { + benchmarkRunner(b, Decode, decodeTests) +} From c9e2be5ff8d85e63a24a06a12c05870a384762fb Mon Sep 17 00:00:00 2001 From: Kasim Kaizer <155087257+KasimKaizer@users.noreply.github.com> Date: Mon, 22 Apr 2024 19:20:32 +0400 Subject: [PATCH 3/8] update(config): add affine-cipher to config.json --- config.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/config.json b/config.json index bbf538156..a4152d4b0 100644 --- a/config.json +++ b/config.json @@ -1255,6 +1255,15 @@ "transforming" ] }, + { + "slug": "affine-cipher", + "name": "Affine Cipher", + "uuid": "C92E0683-45B8-4E37-84B8-96B5B062C015", + "practices": [], + "prerequisites": [], + "difficulty": 4, + "topics": ["algorithms", "cryptography", "strings"] + }, { "slug": "flatten-array", "name": "Flatten Array", From b15bdf9f76c8ef3e120bf121cd25a557fc654bab Mon Sep 17 00:00:00 2001 From: Kasim Kaizer <155087257+KasimKaizer@users.noreply.github.com> Date: Mon, 22 Apr 2024 23:20:54 +0400 Subject: [PATCH 4/8] fix(affine-cipher): fix tests --- .../affine-cipher/affine_cipher_test.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/exercises/practice/affine-cipher/affine_cipher_test.go b/exercises/practice/affine-cipher/affine_cipher_test.go index 99241ee8d..bb8dc5d08 100644 --- a/exercises/practice/affine-cipher/affine_cipher_test.go +++ b/exercises/practice/affine-cipher/affine_cipher_test.go @@ -1,11 +1,10 @@ package affinecipher import ( - "log" "testing" ) -func testRunner( +func runTests( t *testing.T, name string, op func(string, int, int) (string, error), @@ -16,28 +15,28 @@ func testRunner( got, err := op(tc.inputPhrase, tc.inputA, tc.inputB) if err != nil { if !tc.expectError { - log.Fatalf("%s(%s, %d, %d) returned unexpected error %v", name, tc.inputPhrase, tc.inputA, tc.inputB, err) + t.Fatalf("%s(%s, %d, %d) returned unexpected error %v", name, tc.inputPhrase, tc.inputA, tc.inputB, err) } return } if tc.expectError { - log.Fatalf("%s(%s, %d, %d) expected error, got %v", name, tc.inputPhrase, tc.inputA, tc.inputB, got) + t.Fatalf("%s(%s, %d, %d) expected error, got %v", name, tc.inputPhrase, tc.inputA, tc.inputB, got) } if tc.expected != got { - log.Fatalf("%s(%s, %d, %d) = %s, expected: %s", name, tc.inputPhrase, tc.inputA, tc.inputB, got, tc.expected) + t.Fatalf("%s(%s, %d, %d) = %s, expected: %s", name, tc.inputPhrase, tc.inputA, tc.inputB, got, tc.expected) } }) } } func TestEncode(t *testing.T) { - testRunner(t, "Encode", Encode, encodeTests) + runTests(t, "Encode", Encode, encodeTests) } func TestDecode(t *testing.T) { - testRunner(t, "Decode", Decode, decodeTests) + runTests(t, "Decode", Decode, decodeTests) } -func benchmarkRunner( +func runBenchmark( b *testing.B, op func(string, int, int) (string, error), testCases []testCase, @@ -53,9 +52,9 @@ func benchmarkRunner( } func BenchmarkEncode(b *testing.B) { - benchmarkRunner(b, Encode, encodeTests) + runBenchmark(b, Encode, encodeTests) } func BenchmarkDecode(b *testing.B) { - benchmarkRunner(b, Decode, decodeTests) + runBenchmark(b, Decode, decodeTests) } From 58c64101a1f3f6f2959a147da27af6543c71f15d Mon Sep 17 00:00:00 2001 From: Kasim Kaizer <155087257+KasimKaizer@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:45:30 +0400 Subject: [PATCH 5/8] update(affine-cipher): add an example solution for this exercise in example.go --- .../practice/affine-cipher/.meta/example.go | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 exercises/practice/affine-cipher/.meta/example.go diff --git a/exercises/practice/affine-cipher/.meta/example.go b/exercises/practice/affine-cipher/.meta/example.go new file mode 100644 index 000000000..042c920e4 --- /dev/null +++ b/exercises/practice/affine-cipher/.meta/example.go @@ -0,0 +1,113 @@ +// Package affinecipher contains tools that implement affine-cipher. +package affinecipher + +import ( + "errors" + "strings" +) + +type operation int + +const ( + encode operation = iota + 1 + decode +) + +const _totalAlphabets = 26 // total number of letters in alphabet. + +// Encode encode the provided message with the provided keys, using affine-cipher. +func Encode(text string, a, b int) (string, error) { + if gcd(a, _totalAlphabets) != 1 { + return "", errors.New("affinecipher.Encode: a and b must be co-prime") + } + return cipher(encode, text, a, b) +} + +// Decode decodes the provided encoded message with the provided keys, using affine-cipher. +func Decode(text string, a, b int) (string, error) { + if gcd(a, _totalAlphabets) != 1 { + return "", errors.New("affinecipher.Decode: a and b must be co-prime") + } + mmi := multiInv(a, _totalAlphabets) + return cipher(decode, text, mmi, b) +} + +// cipher functions takes a operation, the text and as well as key values, and performs the +// operation on the text using the provided keys. +func cipher(op operation, text string, a, b int) (string, error) { + text = strings.ToLower(text) + var output strings.Builder + accum := 0 + opFunc := operationFunc(op) + for _, char := range []byte(text) { + if !(char >= 'a' && char <= 'z') && // if not a letter and + !(char >= '1' && char <= '9') { // if not a number + continue + } + + // if its encoding then write a space every 5 letters. + if op == encode && accum != 0 && (accum%5) == 0 { + output.WriteByte(' ') + } + accum++ + + if char >= '1' && char <= '9' { // write numbers as it is. + output.WriteByte(char) + continue + } + output.WriteByte(opFunc(char, a, b)) + } + return output.String(), nil +} + +// gcd function finds the greatest common divisor for the numbers passed into it. +func gcd(a, b int) int { + if a < b { + a, b = b, a + } + for b > 0 { + a, b = b, (a % b) + } + return a +} + +// multiInv finds the modular multiple inverse of the passed num and mod. +func multiInv(num, mod int) int { + t1, t2 := 0, 1 + a, b := num, mod + + if a < b { + a, b = b, a + } + + for b > 0 { + t := t1 - (t2 * (a / b)) + a, b = b, (a % b) + t1, t2 = t2, t + } + + return t1 +} + +// operationFunc function returns the appropriate function for the passed operation. +func operationFunc(op operation) func(byte, int, int) byte { + if op == encode { + return encryptionFunc + } + return decryptionFunc +} + +// encryptionFunc function is for encrypting text. +func encryptionFunc(letter byte, num1, num2 int) byte { + temp := ((num1 * int(letter-'a')) + num2) % _totalAlphabets + return byte(temp) + 'a' +} + +// decryptionFunc function is for decrypting text. +func decryptionFunc(letter byte, mmi, num2 int) byte { + temp := (mmi * (int(letter-'a') - num2)) % _totalAlphabets + if temp < 0 { + temp += _totalAlphabets + } + return byte(temp) + 'a' +} From abe01f6090ec170e993eae9cddc5c3d481d08792 Mon Sep 17 00:00:00 2001 From: Kasim Kaizer <155087257+KasimKaizer@users.noreply.github.com> Date: Tue, 23 Apr 2024 17:20:41 +0400 Subject: [PATCH 6/8] fix(affine-cipher): fix gen.go --- exercises/practice/affine-cipher/.meta/example.go | 2 +- exercises/practice/affine-cipher/.meta/gen.go | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/exercises/practice/affine-cipher/.meta/example.go b/exercises/practice/affine-cipher/.meta/example.go index 042c920e4..5de654e09 100644 --- a/exercises/practice/affine-cipher/.meta/example.go +++ b/exercises/practice/affine-cipher/.meta/example.go @@ -15,7 +15,7 @@ const ( const _totalAlphabets = 26 // total number of letters in alphabet. -// Encode encode the provided message with the provided keys, using affine-cipher. +// Encode encodes the provided message with the provided keys, using affine-cipher. func Encode(text string, a, b int) (string, error) { if gcd(a, _totalAlphabets) != 1 { return "", errors.New("affinecipher.Encode: a and b must be co-prime") diff --git a/exercises/practice/affine-cipher/.meta/gen.go b/exercises/practice/affine-cipher/.meta/gen.go index 96eb0ac50..d41d97472 100644 --- a/exercises/practice/affine-cipher/.meta/gen.go +++ b/exercises/practice/affine-cipher/.meta/gen.go @@ -44,13 +44,10 @@ func (t testCase) ExpectedString() string { func (t testCase) Error() bool { m, ok := t.Expected.(map[string]interface{}) if !ok { - return false + return ok } _, ok = m["error"].(string) - if !ok { - return false - } - return true + return ok } // Template to generate encode and decode test cases. From 505733158c75f503ba0f11fee2301c8501434f29 Mon Sep 17 00:00:00 2001 From: Kasim Kaizer <155087257+KasimKaizer@users.noreply.github.com> Date: Tue, 23 Apr 2024 18:13:46 +0400 Subject: [PATCH 7/8] fix(config): fix the uuid for the affine-cipher exercise --- config.json | 2 +- exercises/practice/affine-cipher/.meta/tests.toml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config.json b/config.json index a4152d4b0..e875e83ec 100644 --- a/config.json +++ b/config.json @@ -1258,7 +1258,7 @@ { "slug": "affine-cipher", "name": "Affine Cipher", - "uuid": "C92E0683-45B8-4E37-84B8-96B5B062C015", + "uuid": "cf62a3c5-af1a-4d05-a004-11b35eb79442", "practices": [], "prerequisites": [], "difficulty": 4, diff --git a/exercises/practice/affine-cipher/.meta/tests.toml b/exercises/practice/affine-cipher/.meta/tests.toml index 8e5ca02f5..07cce7c77 100644 --- a/exercises/practice/affine-cipher/.meta/tests.toml +++ b/exercises/practice/affine-cipher/.meta/tests.toml @@ -27,6 +27,9 @@ description = "encode -> encode mindblowingly" [6686f4e2-753b-47d4-9715-876fdc59029d] description = "encode -> encode numbers" +[ae23d5bd-30a8-44b6-afbe-23c8c0c7faa3] +description = "encode -> encode deep thought" + [c93a8a4d-426c-42ef-9610-76ded6f7ef57] description = "encode -> encode all the letters" From 226a47fe3e0ecfebf3447d3a5ca7c18fb21dc35c Mon Sep 17 00:00:00 2001 From: Kasim Kaizer <155087257+KasimKaizer@users.noreply.github.com> Date: Wed, 1 May 2024 15:17:58 +0400 Subject: [PATCH 8/8] update(affine-cipher): add authors --- exercises/practice/affine-cipher/.meta/config.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/exercises/practice/affine-cipher/.meta/config.json b/exercises/practice/affine-cipher/.meta/config.json index bcb6ea87b..569df52bb 100644 --- a/exercises/practice/affine-cipher/.meta/config.json +++ b/exercises/practice/affine-cipher/.meta/config.json @@ -1,5 +1,7 @@ { - "authors": [], + "authors": [ + "KasimKaizer" + ], "files": { "solution": [ "affine_cipher.go" @@ -14,4 +16,4 @@ "blurb": "Create an implementation of the Affine cipher, an ancient encryption algorithm from the Middle East.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Affine_cipher" -} +} \ No newline at end of file