Klefki is a playground for researching elliptic curve group based algorithms & applications, such as MPC, HE, ZKP, and Bitcoin/Ethereum. All data types & structures are based on mathematical defination of abstract algebra.

# Klefki Klefki (Japanese: クレッフィ Cleffy) is a dual-type Steel/Fairy Pokémon introduced in Generation VI. It is not known to evolve into or from any other Pokémon.

# TL; DR

Klefki is a playground for researching elliptic curve group based algorithms & applications, such as MPC, HE, ZKP, and Bitcoin/Ethereum. All data types & structures are based on mathematical defination of abstract algebra.

#### For Installation (require python>=3.6):

```pip3 install klefki

klefki shell
```

Have Fun!!!!

## Elliptic Curve Group Example

• Test pairing
```from klefki.curves.barreto_naehrig import bn128

G1 = bn128.ECGBN128.G1
G2 = bn128.ECGBN128.G2
G = G1
e = bn128.ECGBN128.e

one = bn128.BN128FP12.one()
p1 = e(G2, G1)
p2 = e(G2, G1 @ 2)
assert p1 * p1 == p2
```
• Create Custom Groups
```import klefki.const as const
from klefki.algebra.fields import FiniteField
from klefki.algebra.groups import EllipticCurveGroup
from klefki.algebra.groups import EllipicCyclicSubgroup

class FiniteFieldSecp256k1(FiniteField):
P = const.SECP256K1_P

class FiniteFieldCyclicSecp256k1(FiniteField):
P = const.SECP256K1_N

class EllipticCurveGroupSecp256k1(EllipticCurveGroup):
"""
y^2 = x^3 + A * x + B
"""

N = const.SECP256K1_N
A = const.SECP256K1_A
B = const.SECP256K1_B

def op(self, g):
field = self.id.__class__
self.x, self.y,
g.x, g.y,
field.zero(),
field.zero(),
field.zero(),
field(self.A),
field(self.B),
field
)
if x == y == field(0):
return self.__class__(0)
return self.__class__((x, y))
```

## ZKP Examples

• Play with r1cs
```from klefki.zkp.r1cs import R1CS
from functools import partial

@R1CS.r1cs
def t(x):
y = x**3
return y + x + 5

s = t.witness(3)
assert R1CS.verify(s, *t.r1cs)
assert s == t(3)
```

## MPC Examples (SSSS/VSS)

``````from klefki.crypto.ssss import SSSS
from klefki.const import SECP256K1_P as P
from klefki.algebra.utils import randfield
from klefki.algebra.meta import field
import random

def test_ssss():
F = field(P)
s = SSSS(F)
k = random.randint(1, 100)
n = k * 3
secret = randfield(F)

s.setup(secret, k, n)

assert s.decrypt([s.join() for _ in range(k-1)]) != secret
assert s.decrypt([s.join() for _ in range(k+1)]) == secret
assert s.decrypt([s.join() for _ in range(k+2)]) == secret

``````

## PubKey/PrivKey Examples

With `AAT(Abstract Algebra Type)` you can easily implement the bitcoin `priv/pub key` and `sign/verify` algorithms like this:

```import random
from klefki.utils import to_sha256int
from klefki.algebra.concrete import (
JacobianGroupSecp256k1 as JG,
EllipticCurveCyclicSubgroupSecp256k1 as CG,
EllipticCurveGroupSecp256k1 as ECG,
FiniteFieldCyclicSecp256k1 as CF
)

N = CG.N
G = CG.G

def random_privkey() -> CF:
return CF(random.randint(1, N))

def pubkey(priv: CF) -> ECG:
return ECG(JG(G @ priv))

def sign(priv: CF, m: str) -> tuple:
k = CF(random.randint(1, N))
z = CF(to_sha256int(m))
r = CF((G @ k).value)  # From Secp256k1Field to CyclicSecp256k1Field
s = z / k + priv * r / k
return r, s

def verify(pub: ECG, sig: tuple, mhash: int):
r, s = sig
z = CF(mhash)
u1 = z / s
u2 = r / s
rp = G @ u1 + pub @ u2
return r == rp.value
```

Even proof the `Sign/Verify` algorithm mathematically.

```def proof():
priv = random_privkey()
m = 'test'
k = CF(random_privkey())
z = CF(to_sha256int(m))
r = CF((G @ k).value)
s = z / k + priv * r / k

assert k == z / s + priv * r / s
assert G @ k == G @ (z / s + priv * r / s)
assert G @ k == G @ (z / s) + G @ priv @ (r / s)

pub = G @ priv
assert pub == pubkey(priv)
assert G @ k == G @ (z / s) + pub @ (r / s)
u1 = z / s
u2 = r / s
assert G @ k == G @ u1 + pub @ u2
```

Or transform your Bitcoin Private Key to EOS Private/Pub key (or back)

```from klefki.bitcoin.private import decode_privkey
from klefki.eos.public import gen_pub_key
from klefki.eos.private import encode_privkey

def test_to_eos(priv):
key = decode_privkey(priv)
eos_priv = encode_privkey(key)
eos_pub = gen_pub_key(key)
print(eos_priv, eos_pub)
```

## Project details

This version 1.7.1 1.7 1.6.2 1.6.1 1.5.6 1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5 1.4.5 1.4.1 1.2.1 1.2 1.1.3 1.1.2 1.1.1 1.1 1.0 0.9.1 0.9 0.8 0.7.1 0.7 0.6 0.5.1 0.0.5 0.0.4.3 0.0.4.2 0.0.4.0 0.0.3.2 0.0.3.1 0.0.3 0.0.2.3 0.0.2.2 0.0.2.1 0.0.2 0.0.1