merge conflict (#240)

This commit is contained in:
Rahul Dwivedi
2022-12-02 18:53:31 +05:30
committed by GitHub
parent 91d0152d38
commit 0c80fef3c6
8 changed files with 453 additions and 1 deletions

View File

@@ -336,7 +336,15 @@
"practices": [],
"prerequisites": [],
"difficulty": 3
}
},
{
"slug": "affine-cipher",
"name": "Affine Cipher",
"uuid": "85dae1ac-f9e5-411d-920e-bfa988c49876",
"practices": [],
"prerequisites": [],
"difficulty": 5
}
]
},
"concepts": [

View File

@@ -0,0 +1,74 @@
# Description
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.
[comment]: # ( 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

View File

@@ -0,0 +1,13 @@
{
"blurb": "Create an implementation of the Affine cipher, an ancient encryption algorithm from the Middle East.",
"authors": ["dwivedirahul44"],
"contributors": [
],
"files": {
"solution": ["zcl_affine_cipher.clas.abap"],
"test": ["zcl_affine_cipher.clas.testclasses.abap"],
"example": [".meta/zcl_affine_cipher.clas.abap"]
},
"source": "Wikipedia",
"source_url": "http://en.wikipedia.org/wiki/Affine_cipher"
}

View File

@@ -0,0 +1,133 @@
CLASS zcl_affine_cipher DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF key,
a TYPE i,
b TYPE i,
END OF key.
METHODS:
encode IMPORTING phrase TYPE string
key TYPE key
RETURNING VALUE(cipher) TYPE string
RAISING cx_parameter_invalid,
decode IMPORTING cipher TYPE string
key TYPE key
RETURNING VALUE(phrase) TYPE string
RAISING cx_parameter_invalid.
PROTECTED SECTION.
PRIVATE SECTION.
TYPES: ty_char1 TYPE c LENGTH 1.
CONSTANTS:
max_len TYPE i VALUE 26.
METHODS:
is_coprime IMPORTING VALUE(a) TYPE i
RETURNING VALUE(flag) TYPE abap_bool,
ret_mmi IMPORTING VALUE(a) TYPE i
RETURNING VALUE(mmi) TYPE i,
ret_upper_nth_char IMPORTING str TYPE string
n TYPE i
RETURNING VALUE(letter) TYPE ty_char1,
ret_nth_letter IMPORTING n TYPE i
RETURNING VALUE(letter) TYPE ty_char1,
ret_letter_index IMPORTING letter TYPE ty_char1
RETURNING VALUE(index) TYPE i.
ENDCLASS.
CLASS zcl_affine_cipher IMPLEMENTATION.
METHOD encode.
IF is_coprime( key-a ) = abap_false.
RAISE EXCEPTION TYPE cx_parameter_invalid.
ENDIF.
DATA(str) = replace( val = phrase
with = ``
regex = '[\,\s\.]'
occ = 0 ).
cipher = REDUCE string(
INIT result TYPE string
cur_letter = ''
FOR i = 0 UNTIL i = strlen( str )
NEXT cur_letter = ret_upper_nth_char( str = str
n = i )
result &&= |{
COND string(
WHEN i MOD 5 = 0 AND i > 0
THEN ` `
ELSE `` ) }{
to_lower(
COND string(
WHEN cur_letter CA sy-abcde
THEN ret_nth_letter(
( ( ( key-a * ret_letter_index( cur_letter ) ) + key-b ) MOD max_len ) )
ELSE cur_letter ) ) }| ).
ENDMETHOD.
METHOD ret_upper_nth_char.
letter = to_upper( substring( val = str off = n len = 1 ) ).
ENDMETHOD.
METHOD ret_nth_letter.
letter = substring( val = sy-abcde off = n len = 1 ).
ENDMETHOD.
METHOD ret_letter_index.
index = find( val = sy-abcde sub = letter ).
ENDMETHOD.
METHOD decode.
DATA(mmi) = ret_mmi( key-a ).
IF mmi = 0.
RAISE EXCEPTION TYPE cx_parameter_invalid.
ENDIF.
DATA(str) = condense( val = cipher from = ` ` to = `` ).
phrase = REDUCE string(
INIT result TYPE string
cur_letter = ''
FOR i = 0 UNTIL i = strlen( str )
NEXT cur_letter = ret_upper_nth_char( str = str
n = i )
result &&= |{
COND string(
WHEN cur_letter CA sy-abcde
THEN to_lower(
ret_nth_letter(
( ( mmi * ( ret_letter_index( cur_letter ) - key-b ) MOD max_len ) ) ) )
ELSE cur_letter ) }| ).
ENDMETHOD.
METHOD is_coprime.
DATA(m) = max_len.
WHILE a <> 0 AND m <> 0.
IF a = nmax( val1 = a val2 = m ).
a = a MOD m.
ELSE.
m = m MOD a.
ENDIF.
ENDWHILE.
IF nmax( val1 = a val2 = m ) = 1.
flag = abap_true.
ENDIF.
ENDMETHOD.
METHOD ret_mmi.
DATA(i) = 0.
DATA(x) = 0.
WHILE i < max_len.
x = ( ( a MOD max_len ) * ( i MOD max_len ) ) MOD max_len.
IF x = 1.
mmi = i.
EXIT.
ENDIF.
i += 1.
ENDWHILE.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<abapGit version="v1.0.0" serializer="LCL_OBJECT_DEVC" serializer_version="v1.0.0">
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
<asx:values>
<DEVC>
<CTEXT>Exercism: Affine-Cipher</CTEXT>
</DEVC>
</asx:values>
</asx:abap>
</abapGit>

View File

@@ -0,0 +1,36 @@
CLASS zcl_affine_cipher DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF key,
a TYPE i,
b TYPE i,
END OF key.
METHODS:
encode IMPORTING phrase TYPE string
key TYPE key
RETURNING VALUE(cipher) TYPE string
RAISING cx_parameter_invalid,
decode IMPORTING cipher TYPE string
key TYPE key
RETURNING VALUE(phrase) TYPE string
RAISING cx_parameter_invalid.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_affine_cipher IMPLEMENTATION.
METHOD encode.
"Implement solution
ENDMETHOD.
METHOD decode.
"Implement solution
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,161 @@
CLASS ltcl_crypto_square DEFINITION FINAL FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA cut TYPE REF TO zcl_affine_cipher.
METHODS setup.
METHODS:
encode_yes FOR TESTING,
encode_no FOR TESTING,
encode_omg FOR TESTING,
encode_o_m_g FOR TESTING,
encode_string FOR TESTING,
encode_sentence_with_number FOR TESTING,
encode_sentence FOR TESTING,
encode_all_letters FOR TESTING,
encode_no_coprime FOR TESTING,
decode_exercism FOR TESTING,
decode_sentence FOR TESTING,
decode_sentence_with_number FOR TESTING,
decode_all_letters FOR TESTING,
decode_multi_space FOR TESTING,
decode_no_coprime FOR TESTING.
ENDCLASS.
CLASS ltcl_crypto_square IMPLEMENTATION.
METHOD setup.
cut = NEW zcl_affine_cipher( ).
ENDMETHOD.
METHOD encode_yes.
cl_abap_unit_assert=>assert_equals(
exp = `xbt`
act = cut->encode(
phrase = `yes`
key = VALUE #( a = 5 b = 7 ) ) ).
ENDMETHOD.
METHOD encode_no.
cl_abap_unit_assert=>assert_equals(
exp = `fu`
act = cut->encode(
phrase = `no`
key = VALUE #( a = 15 b = 18 ) ) ).
ENDMETHOD.
METHOD encode_omg.
cl_abap_unit_assert=>assert_equals(
exp = `lvz`
act = cut->encode(
phrase = `OMG`
key = VALUE #( a = 21 b = 3 ) ) ).
ENDMETHOD.
METHOD encode_o_m_g.
cl_abap_unit_assert=>assert_equals(
exp = `hjp`
act = cut->encode(
phrase = `O M G`
key = VALUE #( a = 25 b = 47 ) ) ).
ENDMETHOD.
METHOD encode_string.
cl_abap_unit_assert=>assert_equals(
exp = `rzcwa gnxzc dgt`
act = cut->encode(
phrase = `mindblowingly`
key = VALUE #( a = 11 b = 15 ) ) ).
ENDMETHOD.
METHOD encode_sentence_with_number.
cl_abap_unit_assert=>assert_equals(
exp = `jqgjc rw123 jqgjc rw`
act = cut->encode(
phrase = `Testing,1 2 3, testing.`
key = VALUE #( a = 3 b = 4 ) ) ).
ENDMETHOD.
METHOD encode_sentence.
cl_abap_unit_assert=>assert_equals(
exp = `iynia fdqfb ifje`
act = cut->encode(
phrase = `Truth is fiction.`
key = VALUE #( a = 5 b = 17 ) ) ).
ENDMETHOD.
METHOD encode_all_letters.
DATA(exp) = `swxtj npvyk lruol iejdc blaxk swxmh qzglf`.
DATA(phrase) = `The quick brown fox jumps over the lazy dog.`.
cl_abap_unit_assert=>assert_equals(
exp = exp
act = cut->encode(
phrase = phrase
key = VALUE #( a = 17 b = 33 ) ) ).
ENDMETHOD.
METHOD encode_no_coprime.
TRY.
cut->encode(
phrase = `Test`
key = VALUE #( a = 6 b = 17 ) ).
cl_abap_unit_assert=>fail( ).
CATCH cx_parameter_invalid.
ENDTRY.
ENDMETHOD.
METHOD decode_exercism.
cl_abap_unit_assert=>assert_equals(
exp = `exercism`
act = cut->decode(
cipher = `tytgn fjr`
key = VALUE #( a = 3 b = 7 ) ) ).
ENDMETHOD.
METHOD decode_sentence.
DATA(cipher) = `qdwju nqcro muwhn odqun oppmd aunwd o`.
cl_abap_unit_assert=>assert_equals(
exp = `anobstacleisoftenasteppingstone`
act = cut->decode(
cipher = cipher
key = VALUE #( a = 19 b = 16 ) ) ).
ENDMETHOD.
METHOD decode_sentence_with_number.
cl_abap_unit_assert=>assert_equals(
exp = `testing123testing`
act = cut->decode(
cipher = `odpoz ub123 odpoz ub`
key = VALUE #( a = 25 b = 7 ) ) ).
ENDMETHOD.
METHOD decode_all_letters.
DATA(cipher) = `swxtj npvyk lruol iejdc blaxk swxmh qzglf`.
cl_abap_unit_assert=>assert_equals(
exp = `thequickbrownfoxjumpsoverthelazydog`
act = cut->decode(
cipher = cipher
key = VALUE #( a = 17 b = 33 ) ) ).
ENDMETHOD.
METHOD decode_multi_space.
DATA(cipher) = `vszzm cly yd cg qdp`.
cl_abap_unit_assert=>assert_equals(
exp = `jollygreengiant`
act = cut->decode(
cipher = cipher
key = VALUE #( a = 15 b = 16 ) ) ).
ENDMETHOD.
METHOD decode_no_coprime.
TRY.
cut->decode(
cipher = `Test`
key = VALUE #( a = 13 b = 5 ) ).
cl_abap_unit_assert=>fail( ).
CATCH cx_parameter_invalid.
ENDTRY.
ENDMETHOD.
ENDCLASS.

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
<asx:values>
<VSEOCLASS>
<CLSNAME>ZCL_AFFINE_CIPHER</CLSNAME>
<LANGU>E</LANGU>
<DESCRIPT>Exercism: Affine Cipher</DESCRIPT>
<STATE>1</STATE>
<CLSCCINCL>X</CLSCCINCL>
<FIXPT>X</FIXPT>
<UNICODE>X</UNICODE>
<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
</VSEOCLASS>
</asx:values>
</asx:abap>
</abapGit>