---
# System prepended metadata

title: ELLIPTIC CURVES - CRYPTOHACK

---

# ELLIPTIC CURVES - CRYPTOHACK
## Background Reading
 The flag is the name we give groups with a commutative operation.
 `flag: crypto{Abelian}`

## Point Negation
![image](https://hackmd.io/_uploads/SycyCf0op.png)
Để $P+Q=0$ thì $Q=-P$ tức là Q sẽ có tọa độ $Q(xP,-yP)$ => Q = (8045, -6936) = (8045, 2803).
`flag: cryto{8045, 2803}`
## Point Addition
Bài yêu cầu tính tổng $S = P + P + Q + R$ trên đường cong Elliptic E:$Y^{2} = X^{3} + 497X + 1768$, p: 9739 và P = (493, 5564), Q = (1539, 4742), R = (4403,5202).
Ta sẽ sử dụng thuật toán:
![image](https://hackmd.io/_uploads/HynUzYWnp.png)

```python!
from Crypto.Util.number import inverse

def PointAdd(P, Q, a, b, p):
    x1 = P[0]
    y1 = P[1]

    x2 = Q[0]
    y2 = Q[1]

    lamda = 0

    if x1 == 0 and y1 == 0:
        return Q
    
    if x2 == 0 and y2 == 0:
        return P
    
    if x1 == x2 and y1 == -y2:
        return [0, 0]
    
    if x1 == x2 and y1 == y2:
        lamda = ((3 * pow(x1, 2) + a) * inverse(2*y1, p))%p
    
    if x1 != x2 and y1 != y2:
        lamda =  ((y2 - y1) * inverse(x2 - x1, p))%p

    x3 = (lamda**2 - x1 - x2)%p
    y3 = (lamda*(x1 - x3) - y1)%p

    return [x3, y3]

a = 497
b = 1768
p = 9739
P = [493, 5564]
Q = [1539, 4742]
R = [4403, 5202]
double_P = PointAdd(P, P, a, b, p)
S1 = PointAdd(double_P, Q, a, b, p)
S2 = PointAdd(S1, R, a, b, p)
print(S2)
```

`flag: (4215, 2162)`

## Scalar Multiplication
Bài yêu cầu tính $Q(x,y) = 7863P$ trên đường cong Elliptic E:$Y^{2} = X^{3} + 497X + 1768$, p: 9739 và P = (2339, 2213).
Ta sử dụng thuật toán:
![image](https://hackmd.io/_uploads/S1CVtKW2a.png)
```python!
from Crypto.Util.number import inverse

def PointAdd(P, Q, a, b, p):
    x1 = P[0]
    y1 = P[1]

    x2 = Q[0]
    y2 = Q[1]

    lamda = 0

    if x1 == 0 and y1 == 0:
        return Q
    
    if x2 == 0 and y2 == 0:
        return P
    
    if x1 == x2 and y1 == -y2:
        return [0, 0]
    
    if x1 == x2 and y1 == y2:
        lamda = ((3 * pow(x1, 2) + a) * inverse(2*y1, p))%p
    
    if x1 != x2 and y1 != y2:
        lamda =  ((y2 - y1) * inverse(x2 - x1, p))%p

    x3 = (lamda**2 - x1 - x2)%p
    y3 = (lamda*(x1 - x3) - y1)%p

    return [x3, y3]

def DAA(P, n, a, b, p):
    Q = P
    R = [0, 0]
    while n > 0:
        if n%2 == 1:
            R = PointAdd(R, Q, a, b, p)
        Q = PointAdd(Q, Q, a, b, p)
        n = n // 2
    
    return R

a = 497
b = 1768
p = 9739
P = [2339, 2213]
n = 7863
print(DAA(P, n, a, b, p))
```

`flag: crypto{9467, 2742}`

## Curves and Logs
Bài cho đường cong Elliptic E:$Y^{2} = X^{3} + 497X + 1768$, p: 9739,  G: (1804,5368) và QA = (815, 3190), nB = 1829.
Bài yêu cầu tính $s(x, y) = nA*Qb = nB * Qa$ và dùng hàm hash SHA1 để tính giá trị của x chính là flag.
```python!
from Crypto.Util.number import inverse
from Crypto.Hash import SHA1

def PointAdd(P, Q, a, b, p):
    x1 = P[0]
    y1 = P[1]

    x2 = Q[0]
    y2 = Q[1]

    lamda = 0

    if x1 == 0 and y1 == 0:
        return Q
    
    if x2 == 0 and y2 == 0:
        return P
    
    if x1 == x2 and y1 == -y2:
        return [0, 0]
    
    if x1 == x2 and y1 == y2:
        lamda = ((3 * pow(x1, 2) + a) * inverse(2*y1, p))%p
    
    if x1 != x2 and y1 != y2:
        lamda =  ((y2 - y1) * inverse(x2 - x1, p))%p

    x3 = (lamda**2 - x1 - x2)%p
    y3 = (lamda*(x1 - x3) - y1)%p

    return [x3, y3]

def DAA(P, n, a, b, p):
    Q = P
    R = [0, 0]
    while n > 0:
        if n%2 == 1:
            R = PointAdd(R, Q, a, b, p)
        Q = PointAdd(Q, Q, a, b, p)
        n = n // 2
    
    return R

a = 497
b = 1768
p = 9739
Qa = [815, 3190]
nB = 1829
s = DAA(Qa, nB, a, b, p)
print(s)
```
`x: 7929`
![image](https://hackmd.io/_uploads/r1zoEEzhp.png)

`flag: crypto{80e5212754a824d3a4aed185ace4f9cac0f908bf}`

## Efficient Exchange
Bài cho đường cong Elliptic E:$Y^{2} = X^{3} + 497X + 1768$, p: 9739,  G: (1804,5368) và q_x = 4726, nB = 6534 và file code:
```python!
def is_pkcs7_padded(message):
    padding = message[-message[-1]:]
    return all(padding[i] == len(padding) for i in range(0, len(padding)))


def decrypt_flag(shared_secret: int, iv: str, ciphertext: str):
    # Derive AES key from shared secret
    sha1 = hashlib.sha1()
    sha1.update(str(shared_secret).encode('ascii'))
    key = sha1.digest()[:16]
    # Decrypt flag
    ciphertext = bytes.fromhex(ciphertext)
    iv = bytes.fromhex(iv)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    plaintext = cipher.decrypt(ciphertext)

    if is_pkcs7_padded(plaintext):
        return unpad(plaintext, 16).decode('ascii')
    else:
        return plaintext.decode('ascii')

shared_secret = ?
iv = ?
ciphertext = ?

print(decrypt_flag(shared_secret, iv, ciphertext))
```
`'iv': 'cd9da9f1c60925922377ea952afc212c'`
`'encrypted_flag': 'febcbe3a3414a730b125931dccf912d2239f3e969c4334d95ed0ec86f6449ad8'`
Để tìm được `flag` thì đầu tiên ta cần phải tìm được `s = shared_secret` mà bài chỉ cho q_x nên ta phải tìm `q_y` bằng cách thay `q_x` vào phương trình đường cong Elliptic.
Sau khi thu được $q_y^{2}$, do p = 3 mod 4 nên ta có thể áp dụng thuật toán:
![image](https://hackmd.io/_uploads/SkouiVzn6.png)
với p = 9739, a = $q_y^{2}$, ta sẽ thu được (y, -y).
Sử dụng thuật toán `double and add` để tìm ra $s(x, y) = n_b * Q_a$. Thay giá trị x vừa tính được vào `shared_secret` và dùng file bài cho để lấy `flag`
```python!
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Util.number import inverse
import hashlib

def PointAdd(P, Q, a, b, p):
    x1 = P[0]
    y1 = P[1]

    x2 = Q[0]
    y2 = Q[1]

    lamda = 0

    if x1 == 0 and y1 == 0:
        return Q
    
    if x2 == 0 and y2 == 0:
        return P
    
    if x1 == x2 and y1 == -y2:
        return [0, 0]
    
    if x1 == x2 and y1 == y2:
        lamda = ((3 * pow(x1, 2) + a) * inverse(2*y1, p))%p
    
    if x1 != x2 and y1 != y2:
        lamda =  ((y2 - y1) * inverse(x2 - x1, p))%p

    x3 = (lamda**2 - x1 - x2)%p
    y3 = (lamda*(x1 - x3) - y1)%p

    return [x3, y3]

def DAA(P, n, a, b, p):
    Q = P
    R = [0, 0]
    while n > 0:
        if n%2 == 1:
            R = PointAdd(R, Q, a, b, p)
        Q = PointAdd(Q, Q, a, b, p)
        n = n // 2
    
    return R

def is_pkcs7_padded(message):
    padding = message[-message[-1]:]
    return all(padding[i] == len(padding) for i in range(0, len(padding)))


def decrypt_flag(shared_secret: int, iv: str, ciphertext: str):
    # Derive AES key from shared secret
    sha1 = hashlib.sha1()
    sha1.update(str(shared_secret).encode('ascii'))
    key = sha1.digest()[:16]
    # Decrypt flag
    ciphertext = bytes.fromhex(ciphertext)
    iv = bytes.fromhex(iv)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    plaintext = cipher.decrypt(ciphertext)

    if is_pkcs7_padded(plaintext):
        return unpad(plaintext, 16).decode('ascii')
    else:
        return plaintext.decode('ascii')

a = 497
b = 1768
p = 9739
G = [1804,5368]
q_x = 4726
nB = 6534
y2 = (q_x**3 + 497*q_x + 1768)%p
y = (y2**((p + 1)//4))%p
q_y1 = y
q_y2 = -y+p
Qa1 = [q_x, q_y1]
Qa2 = [q_x, q_y2]

s1 = DAA(Qa1, nB, a, b, p)
s2 = DAA(Qa2, nB, a, b, p)

shared_secret1 = s1[0]
shared_secret2 = s2[0]
iv = 'cd9da9f1c60925922377ea952afc212c'
ciphertext = 'febcbe3a3414a730b125931dccf912d2239f3e969c4334d95ed0ec86f6449ad8'

print(decrypt_flag(shared_secret1, iv, ciphertext))

print(decrypt_flag(shared_secret2, iv, ciphertext))
```

`flag: crypto{3ff1c1ent_k3y_3xch4ng3}`