From c256a33bc9ffb870f90307cd227232398a39f269 Mon Sep 17 00:00:00 2001 From: kusti8 Date: Fri, 6 Oct 2017 17:34:57 -0400 Subject: [PATCH 1/8] Implement exercise diffie-hellman From bd97b39833c6489738c62ff8010c00bae220cee4 Mon Sep 17 00:00:00 2001 From: kusti8 Date: Sat, 7 Oct 2017 09:28:53 -0400 Subject: [PATCH 2/8] Add diffie-hellman exercise --- exercises/diffie-hellman/README.md | 54 ++++++++++++++++ exercises/diffie-hellman/diffie_hellman.py | 8 +++ .../diffie-hellman/diffie_hellman_test.py | 64 +++++++++++++++++++ exercises/diffie-hellman/example.py | 10 +++ 4 files changed, 136 insertions(+) create mode 100644 exercises/diffie-hellman/README.md create mode 100644 exercises/diffie-hellman/diffie_hellman.py create mode 100644 exercises/diffie-hellman/diffie_hellman_test.py create mode 100644 exercises/diffie-hellman/example.py diff --git a/exercises/diffie-hellman/README.md b/exercises/diffie-hellman/README.md new file mode 100644 index 00000000000..ce73b2e3b3d --- /dev/null +++ b/exercises/diffie-hellman/README.md @@ -0,0 +1,54 @@ +# Diffie Hellman + +Diffie-Hellman key exchange. + +Alice and Bob use Diffie-Hellman key exchange to share secrets. They +start with prime numbers, pick private keys, generate and share public +keys, and then generate a shared secret key. + +## Step 0 + +The test program supplies prime numbers p and g. + +## Step 1 + +Alice picks a private key, a, greater than 1 and less than p. Bob does +the same to pick a private key b. + +## Step 2 + +Alice calculates a public key A. + + A = g**a mod p + +Using the same p and g, Bob similarly calculates a public key B from his +private key b. + +## Step 3 + +Alice and Bob exchange public keys. Alice calculates secret key s. + + s = B**a mod p + +Bob calculates + + s = A**b mod p + +The calculations produce the same result! Alice and Bob now share +secret s. + +### Submitting Exercises + +Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/` directory. + +For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit /python/bob/bob.py`. + + +For more detailed information about running tests, code style and linting, +please see the [help page](http://exercism.io/languages/python). +## Source + +Wikipedia, 1024 bit key from www.cryptopp.com/wiki. [http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange](http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. \ No newline at end of file diff --git a/exercises/diffie-hellman/diffie_hellman.py b/exercises/diffie-hellman/diffie_hellman.py new file mode 100644 index 00000000000..a86c35e1a20 --- /dev/null +++ b/exercises/diffie-hellman/diffie_hellman.py @@ -0,0 +1,8 @@ +def private_key(p): + pass + +def public_key(p, g, private): + pass + +def secret(p, public, private): + pass \ No newline at end of file diff --git a/exercises/diffie-hellman/diffie_hellman_test.py b/exercises/diffie-hellman/diffie_hellman_test.py new file mode 100644 index 00000000000..2f1bd14691f --- /dev/null +++ b/exercises/diffie-hellman/diffie_hellman_test.py @@ -0,0 +1,64 @@ +import unittest + +import diffie_hellman + +class DiffieHellmanTest(unittest.TestCase): + + def test_private_in_range(self): + primes = [5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] + for i in primes: + self.assertTrue(1 < diffie_hellman.private_key(i) < i) + + # Can fail due to randomness, but most likely will not, due to pseudo-randomness + # and the large number chosen + def test_private_key_randomness(self): + p = 2147483647 + private_keys = [] + for i in range(5): + private_keys.append(diffie_hellman.private_key(p)) + self.assertEqual(len(list(set(private_keys))), len(private_keys)) + + def test_public_key_correct(self): + p = 23 + g = 5 + private = 6 + expected = 8 + + actual = diffie_hellman.public_key(p, g, private) + self.assertEqual(actual, expected) + + def test_secret_key_correct(self): + p = 23 + public = 19 + private = 6 + expected = 2 + + actual = diffie_hellman.secret(p, public, private) + self.assertEqual(actual, expected) + + def test_secret_key_correct_large_nums(self): + p = 120227323036150778550155526710966921740030662694578947298423549235265759593711587341037426347114541533006628856300552706996143592240453345642869233562886752930249953227657883929905072620233073626594386072962776144691433658814261874113232461749035425712805067202910389407991986070558964461330091797026762932543 + public = 75205441154357919442925546169208711235485855904969178206313309299205868312399046149367516336607966149689640419216591714331722664409474612463910928128055994157922930443733535659848264364106037925315974095321112757711756912144137705613776063541350548911512715512539186192176020596861210448363099541947258202188 + private = 2483479393625932939911081304356888505153797135447327501792696199190469015215177630758617902200417377685436170904594686456961202706692908603181062371925882 + expected = 70900735223964890815905879227737819348808518698920446491346508980461201746567735331455825644429877946556431095820785835497384849778344216981228226252639932672153547963980483673419756271345828771971984887453014488572245819864454136618980914729839523581263886740821363010486083940557620831348661126601106717071 + + actual = diffie_hellman.secret(p, public, private) + self.assertEqual(actual, expected) + + def test_exchange(self): + p = 23 + g = 5 + + privateA = diffie_hellman.private_key(p) + privateB = diffie_hellman.private_key(p) + + publicA = diffie_hellman.public_key(p, g, privateA) + publicB = diffie_hellman.public_key(p, g, privateB) + + secretA = diffie_hellman.secret(p, publicB, privateA) + secretB = diffie_hellman.secret(p, publicA, privateB) + + self.assertEqual(secretA, secretB) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/exercises/diffie-hellman/example.py b/exercises/diffie-hellman/example.py new file mode 100644 index 00000000000..96db1578ada --- /dev/null +++ b/exercises/diffie-hellman/example.py @@ -0,0 +1,10 @@ +import random + +def private_key(p): + return random.randint(2, p-1) + +def public_key(p, g, a): + return pow(g, a, p) + +def secret(p, B, a): + return pow(B, a, p) \ No newline at end of file From ce3d511fa77ebcf06020ae73b6b71976e727b5df Mon Sep 17 00:00:00 2001 From: kusti8 Date: Sat, 7 Oct 2017 10:02:42 -0400 Subject: [PATCH 3/8] Fix flake8 errors --- exercises/diffie-hellman/diffie_hellman.py | 4 ++- .../diffie-hellman/diffie_hellman_test.py | 36 ++++++++++++++----- exercises/diffie-hellman/example.py | 5 ++- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/exercises/diffie-hellman/diffie_hellman.py b/exercises/diffie-hellman/diffie_hellman.py index a86c35e1a20..a12455249fd 100644 --- a/exercises/diffie-hellman/diffie_hellman.py +++ b/exercises/diffie-hellman/diffie_hellman.py @@ -1,8 +1,10 @@ def private_key(p): pass + def public_key(p, g, private): pass + def secret(p, public, private): - pass \ No newline at end of file + pass diff --git a/exercises/diffie-hellman/diffie_hellman_test.py b/exercises/diffie-hellman/diffie_hellman_test.py index 2f1bd14691f..fbf06b200d4 100644 --- a/exercises/diffie-hellman/diffie_hellman_test.py +++ b/exercises/diffie-hellman/diffie_hellman_test.py @@ -2,6 +2,7 @@ import diffie_hellman + class DiffieHellmanTest(unittest.TestCase): def test_private_in_range(self): @@ -9,8 +10,8 @@ def test_private_in_range(self): for i in primes: self.assertTrue(1 < diffie_hellman.private_key(i) < i) - # Can fail due to randomness, but most likely will not, due to pseudo-randomness - # and the large number chosen + # Can fail due to randomness, but most likely will not, + # due to pseudo-randomness and the large number chosen def test_private_key_randomness(self): p = 2147483647 private_keys = [] @@ -23,7 +24,7 @@ def test_public_key_correct(self): g = 5 private = 6 expected = 8 - + actual = diffie_hellman.public_key(p, g, private) self.assertEqual(actual, expected) @@ -37,10 +38,28 @@ def test_secret_key_correct(self): self.assertEqual(actual, expected) def test_secret_key_correct_large_nums(self): - p = 120227323036150778550155526710966921740030662694578947298423549235265759593711587341037426347114541533006628856300552706996143592240453345642869233562886752930249953227657883929905072620233073626594386072962776144691433658814261874113232461749035425712805067202910389407991986070558964461330091797026762932543 - public = 75205441154357919442925546169208711235485855904969178206313309299205868312399046149367516336607966149689640419216591714331722664409474612463910928128055994157922930443733535659848264364106037925315974095321112757711756912144137705613776063541350548911512715512539186192176020596861210448363099541947258202188 - private = 2483479393625932939911081304356888505153797135447327501792696199190469015215177630758617902200417377685436170904594686456961202706692908603181062371925882 - expected = 70900735223964890815905879227737819348808518698920446491346508980461201746567735331455825644429877946556431095820785835497384849778344216981228226252639932672153547963980483673419756271345828771971984887453014488572245819864454136618980914729839523581263886740821363010486083940557620831348661126601106717071 + p = int("""120227323036150778550155526710966921740030662\ + 69457894729842354923526575959371158734103742634711454153\ + 30066288563005527069961435922404533456428692335628867529\ + 30249953227657883929905072620233073626594386072962776144\ + 69143365881426187411323246174903542571280506720291038940\ + 7991986070558964461330091797026762932543""".replace("\n", "")) + public = int("""7520544115435791944292554616920871123548\ + 58559049691782063133092992058683123990461493675163366079\ + 66149689640419216591714331722664409474612463910928128055\ + 99415792293044373353565984826436410603792531597409532111\ + 27577117569121441377056137760635413505489115127155125391\ + 86192176020596861210448363099541947258202188""".replace("\n", "")) + private = int("""248347939362593293991108130435688850515\ + 37971354473275017926961991904690152151776307586179022004\ + 17377685436170904594686456961202706692908603181062371925\ + 882""".replace("\n", "")) + expected = int("""70900735223964890815905879227737819348\ + 80851869892044649134650898046120174656773533145582564442\ + 98779465564310958207858354973848497783442169812282262526\ + 39932672153547963980483673419756271345828771971984887453\ + 01448857224581986445413661898091472983952358126388674082\ + 1363010486083940557620831348661126601106717071""".replace("\n", "")) actual = diffie_hellman.secret(p, public, private) self.assertEqual(actual, expected) @@ -60,5 +79,6 @@ def test_exchange(self): self.assertEqual(secretA, secretB) + if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/exercises/diffie-hellman/example.py b/exercises/diffie-hellman/example.py index 96db1578ada..3a443b92586 100644 --- a/exercises/diffie-hellman/example.py +++ b/exercises/diffie-hellman/example.py @@ -1,10 +1,13 @@ import random + def private_key(p): return random.randint(2, p-1) + def public_key(p, g, a): return pow(g, a, p) + def secret(p, B, a): - return pow(B, a, p) \ No newline at end of file + return pow(B, a, p) From d1151658261b3dec82e91508a41e3598542dee38 Mon Sep 17 00:00:00 2001 From: kusti8 Date: Sat, 7 Oct 2017 10:11:29 -0400 Subject: [PATCH 4/8] Add to config.json --- config.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/config.json b/config.json index 1d22c21285f..a37d295c66a 100644 --- a/config.json +++ b/config.json @@ -834,6 +834,16 @@ "mathematics" ] }, + { + "uuid": "92e2d5f8-7d8a-4e81-a55c-52fa6be80c74", + "slug": "diffie-hellman", + "core": false, + "unlocked_by": "book-store", + "difficulty": 7, + "topics": [ + "Algorithms" + ] + } { "uuid": "e7351e8e-d3ff-4621-b818-cd55cf05bffd", "slug": "accumulate", From 8a0c198a483d831fa99a3af4e710c48a789a481c Mon Sep 17 00:00:00 2001 From: kusti8 Date: Sat, 7 Oct 2017 10:13:09 -0400 Subject: [PATCH 5/8] Add comma --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index a37d295c66a..7dae9a97aa9 100644 --- a/config.json +++ b/config.json @@ -843,7 +843,7 @@ "topics": [ "Algorithms" ] - } + }, { "uuid": "e7351e8e-d3ff-4621-b818-cd55cf05bffd", "slug": "accumulate", From 86eb852bfb819a3b90e45fdace162c5bd7c78242 Mon Sep 17 00:00:00 2001 From: kusti8 Date: Sat, 7 Oct 2017 10:18:46 -0400 Subject: [PATCH 6/8] Remove number whitespace --- exercises/diffie-hellman/diffie_hellman_test.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/exercises/diffie-hellman/diffie_hellman_test.py b/exercises/diffie-hellman/diffie_hellman_test.py index fbf06b200d4..191d865107b 100644 --- a/exercises/diffie-hellman/diffie_hellman_test.py +++ b/exercises/diffie-hellman/diffie_hellman_test.py @@ -43,23 +43,26 @@ def test_secret_key_correct_large_nums(self): 30066288563005527069961435922404533456428692335628867529\ 30249953227657883929905072620233073626594386072962776144\ 69143365881426187411323246174903542571280506720291038940\ - 7991986070558964461330091797026762932543""".replace("\n", "")) + 7991986070558964461330091797026762932543""".replace( + "\n", "").replace(" ", "")) public = int("""7520544115435791944292554616920871123548\ 58559049691782063133092992058683123990461493675163366079\ 66149689640419216591714331722664409474612463910928128055\ 99415792293044373353565984826436410603792531597409532111\ 27577117569121441377056137760635413505489115127155125391\ - 86192176020596861210448363099541947258202188""".replace("\n", "")) + 86192176020596861210448363099541947258202188""".replace( + "\n", "").replace(" ", "")) private = int("""248347939362593293991108130435688850515\ 37971354473275017926961991904690152151776307586179022004\ 17377685436170904594686456961202706692908603181062371925\ - 882""".replace("\n", "")) + 882""".replace("\n", "").replace(" ", "")) expected = int("""70900735223964890815905879227737819348\ 80851869892044649134650898046120174656773533145582564442\ 98779465564310958207858354973848497783442169812282262526\ 39932672153547963980483673419756271345828771971984887453\ 01448857224581986445413661898091472983952358126388674082\ - 1363010486083940557620831348661126601106717071""".replace("\n", "")) + 1363010486083940557620831348661126601106717071""".replace( + "\n", "").replace(" ", "")) actual = diffie_hellman.secret(p, public, private) self.assertEqual(actual, expected) From ea45584bc92c47149ac81941684c9cba41df1b5a Mon Sep 17 00:00:00 2001 From: kusti8 Date: Sun, 8 Oct 2017 16:01:22 -0400 Subject: [PATCH 7/8] Add pseudo-random note --- exercises/diffie-hellman/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/exercises/diffie-hellman/README.md b/exercises/diffie-hellman/README.md index ce73b2e3b3d..169bcf801f1 100644 --- a/exercises/diffie-hellman/README.md +++ b/exercises/diffie-hellman/README.md @@ -37,6 +37,10 @@ Bob calculates The calculations produce the same result! Alice and Bob now share secret s. +## Notes + +Python, as of version 3.6, includes two different random modules. The module called `random` is pseudo-random, meaning it does not generate true randomness, but follows and algorithm that simulates randomness. Since random numbers are generated through a known algorithm, they are not truly random. The `random` module is not correctly suited for crypotography and should not be used, because it is pseudo-random. In version 3.6, Python introduced the `secrets` module which is more cryptographically secure and produces more random numbers suited for cryptography. Since this is only an exercise, `random` is fine to use, but note that it would be very insecure if actually used for crypotgraphy. + ### Submitting Exercises Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/` directory. From 64f526dca5964bae9536b3600bcaef4a4f8b7ea1 Mon Sep 17 00:00:00 2001 From: Gustav Hansen Date: Mon, 9 Oct 2017 12:40:38 -0400 Subject: [PATCH 8/8] Fix note and typos --- exercises/diffie-hellman/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/diffie-hellman/README.md b/exercises/diffie-hellman/README.md index 169bcf801f1..0a793540a7b 100644 --- a/exercises/diffie-hellman/README.md +++ b/exercises/diffie-hellman/README.md @@ -39,7 +39,7 @@ secret s. ## Notes -Python, as of version 3.6, includes two different random modules. The module called `random` is pseudo-random, meaning it does not generate true randomness, but follows and algorithm that simulates randomness. Since random numbers are generated through a known algorithm, they are not truly random. The `random` module is not correctly suited for crypotography and should not be used, because it is pseudo-random. In version 3.6, Python introduced the `secrets` module which is more cryptographically secure and produces more random numbers suited for cryptography. Since this is only an exercise, `random` is fine to use, but note that it would be very insecure if actually used for crypotgraphy. +Python, as of version 3.6, includes two different random modules. The module called `random` is pseudo-random, meaning it does not generate true randomness, but follows and algorithm that simulates randomness. Since random numbers are generated through a known algorithm, they are not truly random. The `random` module is not correctly suited for cryptography and should not be used, because it is pseudo-random. In version 3.6, Python introduced the `secrets` module, which generates cryptographically strong random numbers that provide the greater security required for cryptography. Since this is only an exercise, `random` is fine to use, but note that it would be very insecure if actually used for cryptography. ### Submitting Exercises @@ -55,4 +55,4 @@ please see the [help page](http://exercism.io/languages/python). Wikipedia, 1024 bit key from www.cryptopp.com/wiki. [http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange](http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange) ## Submitting Incomplete Solutions -It's possible to submit an incomplete solution so you can see how others have completed the exercise. \ No newline at end of file +It's possible to submit an incomplete solution so you can see how others have completed the exercise.