~shreyasminocha/haskell-crypto

f9a305dbced6a358176044dfc6038dea52fd3213 — Shreyas Minocha 10 months ago 67019a8
Implement elliptic curves and ECDH
3 files changed, 79 insertions(+), 0 deletions(-)

A Ecdh.hs
A EllipticCurves.hs
M README.md
A Ecdh.hs => Ecdh.hs +12 -0
@@ 0,0 1,12 @@
import EllipticCurves (Point, Curve, scalePoint)

type SharedPublic = Point
type PersonalSecret = Int
type PersonalPublic = Point
type SharedSecret = Point

ecdhPersonalPublic :: (Int, Curve) -> SharedPublic -> PersonalSecret -> PersonalPublic
ecdhPersonalPublic pc p1 na = scalePoint pc p1 na

ecdhSharedSecret :: (Int, Curve) -> PersonalSecret -> PersonalPublic -> SharedSecret
ecdhSharedSecret pc na qb = scalePoint pc qb na
\ No newline at end of file

A EllipticCurves.hs => EllipticCurves.hs +49 -0
@@ 0,0 1,49 @@
module EllipticCurves (Point, Curve, scalePoint) where

import Data.List (elemIndex)
import Data.Maybe (fromJust)
import LinearCongruences (inverse)

type Point = (Int, Int)
type Curve = (Int, Int)

ecdlpBruteforce :: (Int, Curve) -> Point -> Point -> Int
ecdlpBruteforce (p, c) a b = 1 + fromJust (b `elemIndex` pointMultiples (p, c) a)

scalePoint :: (Int, Curve) -> Point -> Int -> Point
scalePoint _ _ 0 = (0, 0)
scalePoint _ p1 1 = p1
scalePoint pc p1 n
    | r == (-1, -1)  = (-1, -1)
    | not (canAddPoints pc r r) = (-1, -1)
    | n `mod` 2 == 0 = twiceR
    | not (canAddPoints pc p1 twiceR) = (-1, -1)
    | otherwise      = addPoints pc p1 twiceR
    where r = scalePoint pc p1 (n `div` 2)
          twiceR = addPoints pc r r

pointMultiples :: (Int, Curve) -> Point -> [Point]
pointMultiples (p, c) p1 = iterate (addPoints (p, c) p1) p1

addPoints :: (Int, Curve) -> Point -> Point -> Point
addPoints (p, (a, b)) p1@(x1, y1) p2@(x2, y2)
    | p1 == (0, 0) = p2
    | p2 == (0, 0) = p1
    | x1 == x2 && y1 == -y2 = (0, 0)
    | otherwise = (x3 `mod` p, y3 `mod` p)
    where x3 = lambda^2 - x1 - x2
          y3 = lambda * (x1 - x3) - y1
          lambda = if p1 /= p2
              then modDiv p (y2 - y1) (x2 - x1)
              else modDiv p (3 * (x1^2) + a) (2 * y1)

canAddPoints :: (Int, Curve) -> Point -> Point -> Bool
canAddPoints (p, (a, b)) p1@(x1, y1) p2@(x2, y2)
    | p1 == (0, 0) = True
    | p2 == (0, 0) = True
    | x1 == x2 && y1 == -y2 = True
    | p1 /= p2  = gcd p (x2 - x1) == 1
    | otherwise = gcd p (2 * y1) == 1

modDiv :: Int -> Int -> Int -> Int
modDiv p a b = (a * (inverse p b)) `mod` p

M README.md => README.md +18 -0
@@ 158,6 158,24 @@ isPowerSmooth 10 84 -- True
quadraticSieve 493 11 [23..38] -- [(23,36),(25,132)]
```

## Elliptic Curves

```hs
ecdlpBruteforce (73, (8, 7)) (32, 53) (39, 17) -- 11
scalePoint (3623, (14, 19)) (6, 730) 947 -- (3492,60)
```

```hs
pc = (3851, (324, 1287))
p = (920, 303)

ecdhPersonalPublic pc p 1194 -- (2067,2178)
ecdhPersonalPublic pc p 1759 -- (3684,3125)

ecdhSharedSecret pc 1194 (3684, 3125) -- (3347,1242)
ecdhSharedSecret pc 1759 (2067, 2178) -- (3347,1242)
```

## Miscellaneous

### Fast Powering