merge conflict (#240)
This commit is contained in:
10
config.json
10
config.json
@@ -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": [
|
||||
|
||||
74
exercises/practice/affine-cipher/.docs/instructions.md
Normal file
74
exercises/practice/affine-cipher/.docs/instructions.md
Normal 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
|
||||
13
exercises/practice/affine-cipher/.meta/config.json
Normal file
13
exercises/practice/affine-cipher/.meta/config.json
Normal 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"
|
||||
}
|
||||
@@ -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.
|
||||
10
exercises/practice/affine-cipher/package.devc.xml
Normal file
10
exercises/practice/affine-cipher/package.devc.xml
Normal 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>
|
||||
36
exercises/practice/affine-cipher/zcl_affine_cipher.clas.abap
Normal file
36
exercises/practice/affine-cipher/zcl_affine_cipher.clas.abap
Normal 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.
|
||||
@@ -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.
|
||||
17
exercises/practice/affine-cipher/zcl_affine_cipher.clas.xml
Normal file
17
exercises/practice/affine-cipher/zcl_affine_cipher.clas.xml
Normal 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>
|
||||
Reference in New Issue
Block a user