From 8a09fc5b22d50047f3762db3d8348f92955c5598 Mon Sep 17 00:00:00 2001
From: Maximilian Stauss <max.stauss@gmail.com>
Date: Sun, 3 Sep 2017 19:55:56 +0200
Subject: [PATCH] usable UOV

---
 .gitignore                              |   1 +
 bsp_UOV.py                              |  33 ++++++++++
 classes/MatsumotoImaiA.py               |  83 ++++++++++++++++++++++++
 classes/UnbalancedOilAndVinegar.py      |  14 ++--
 classes/__init__.py                     |   0
 classes/helpers/AffineTransformation.py |  19 +++---
 classes/helpers/EncryptionScheme.py     |   2 +
 classes/helpers/PolynomialSystem.py     |  20 ++++++
 classes/helpers/PrivateKey.py           |  17 +++--
 classes/helpers/PublicKey.py            |  17 +++--
 classes/helpers/SignatureScheme.py      |   7 +-
 classes/helpers/sage_extensions.py      |   3 +
 keys/bsp_uov.priv                       | Bin 0 -> 2023 bytes
 keys/bsp_uov2.priv                      | Bin 0 -> 2030 bytes
 test.py                                 |  28 ++++++++
 test_UOV.py                             |  43 ++++++++++++
 16 files changed, 263 insertions(+), 24 deletions(-)
 create mode 100644 bsp_UOV.py
 create mode 100644 classes/MatsumotoImaiA.py
 create mode 100644 classes/__init__.py
 create mode 100644 classes/helpers/PolynomialSystem.py
 create mode 100644 keys/bsp_uov.priv
 create mode 100644 keys/bsp_uov2.priv
 create mode 100644 test.py
 create mode 100644 test_UOV.py

diff --git a/.gitignore b/.gitignore
index e43b0f9..dde3895 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 .DS_Store
+*.pyc
diff --git a/bsp_UOV.py b/bsp_UOV.py
new file mode 100644
index 0000000..4d9b5d2
--- /dev/null
+++ b/bsp_UOV.py
@@ -0,0 +1,33 @@
+#!/usr/bin/sage
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, print_function
+from sage.all import *
+
+from classes.helpers.PublicKey import PublicKey
+from classes.helpers.PrivateKey import PrivateKey
+from classes.UnbalancedOilAndVinegar import UnbalancedOilAndVinegar
+
+# Endlicher Körper mit 5 Elementen:
+finite_field = GF(5, 'a')
+
+m = 2  # Zwei Gleichungen
+n = 3  # Drei Variablen
+
+"""TEST UOV"""
+
+# Initialize simple UOV
+UOV = UnbalancedOilAndVinegar(finite_field, n, m, keyfile="./keys/bsp_uov2.priv")
+private_key = UOV.private_key
+public_key = UOV.public_key
+
+# use a random vector
+msg = vector(finite_field, [1, 4])
+
+# generate Signature
+sig = UOV.sign(msg)
+
+# verify signature is valid
+print("msg =", msg)
+print("sig =", sig)
+print("UOV.verify(msg, sig):", UOV.verify(msg, sig))
diff --git a/classes/MatsumotoImaiA.py b/classes/MatsumotoImaiA.py
new file mode 100644
index 0000000..3eec629
--- /dev/null
+++ b/classes/MatsumotoImaiA.py
@@ -0,0 +1,83 @@
+#!/usr/bin/sage
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, print_function
+from sage.all import *
+
+from .helpers.AffineTransformation import AffineTransformation
+from .helpers.PrivateKey import PrivateKey
+from .helpers.PrivateKey import PublicKey
+from .helpers.EncryptionScheme import EncryptionScheme
+
+
+class MatsumotoImaiA(EncryptionScheme):
+    """Matsumoto Imai Scheme A Implementation"""
+
+    def phi(self, polynomail_a):
+        return polynomail_a.list()
+
+    def phi_inv(self, vector_a):
+        return self.extension_field(vector_a)
+
+    def __init__(self, finite_field, n, keyfile=None):
+        self.finite_field = finite_field
+        self.n = n
+
+        # generate or load private & public key
+        if keyfile is not None:
+            self.private_key = PrivateKey(None, None, None, keyfile)
+            self.public_key = self.private_key.generate_public_key()
+        else:
+            self.generate_keys(n)
+
+    def generate_keys(self, n):
+        k = self.finite_field
+        (a,) = k.gens()
+
+        ring = PolynomialRing(k, 'x')
+        (x,) = ring.gens()
+
+        q = len(k)
+
+        # alle Kandidaten für theta werden gesucht
+        thetas = []
+        qn = q**n - 1
+        for theta in xrange(1, n - 1):
+            qd = q**theta + 1
+            (common_divider, t, _) = xgcd(qd, qn)
+            if common_divider == 1:
+                thetas.append((theta, t))
+
+        # ein zufälliges Theta wird ausgewählt
+        print(len(thetas))
+        (self.theta, self.theta_invers) = thetas[int(random() * len(thetas))]
+
+        S = AffineTransformation(
+            random_invertible_matrix(k, n), random_vector(k, n))
+        T = AffineTransformation(
+            random_invertible_matrix(k, n), random_vector(k, n))
+
+        # der Erweiterungskörper wird gebaut
+        gx = ring.irreducible_element(n)
+        multivariate_ring = PolynomialRing(k, n)
+        extension_field = PolynomialRing(multivariate_ring, 't').quotient_ring(gx, 'T')
+        self.extension_field = extension_field
+        multi_vars = multivariate_ring.gens()
+
+        Sx = list(S(vector(multi_vars)))
+
+        pre_F = self.phi_invers(Sx)
+
+        '''Now the MAGIC happens'''
+        post_F = pre_F * pre_F**(4**theta)
+
+        Pr = S.inverse(vector(post_F.list()))
+        SPTx = T(vector(post_F.list()))
+
+        self.private_key = PrivateKey(S, Pr, T)
+        self.public_key = PublicKey(SPTx)
+
+    def invert_MQ(self, msg):
+        X = self.phi_inv(list(msg))
+        X = X**self.theta_invers
+        return vector(self.phi(X))
diff --git a/classes/UnbalancedOilAndVinegar.py b/classes/UnbalancedOilAndVinegar.py
index a243b9e..e9bfd92 100644
--- a/classes/UnbalancedOilAndVinegar.py
+++ b/classes/UnbalancedOilAndVinegar.py
@@ -1,3 +1,6 @@
+#!/usr/bin/sage
+# -*- coding: utf-8 -*-
+
 from __future__ import absolute_import, print_function
 from sage.all import *
 import copy as cp
@@ -12,7 +15,7 @@ from .helpers.SignatureScheme import SignatureScheme
 class UnbalancedOilAndVinegar(SignatureScheme):
     """Unalanced Oil and Vinegar Implementation"""
 
-    def __init__(self, finite_field, ring, n, m, keyfile=None):
+    def __init__(self, finite_field, n, m, keyfile=None):
         """
         UOV wird mit dem Grundkörper `F`, Länge der Nachrichten `n`
         und Länge der Signatur `m` initialisiert
@@ -98,7 +101,7 @@ class UnbalancedOilAndVinegar(SignatureScheme):
         F = self.finite_field
 
         # wichtig ist, dass private_key.Pr `UOV`-Gestalt hat
-        Pr = cp.copy(self.private_key.P)
+        Pr = cp.copy(self.private_key.Pr)
 
         sig = []
 
@@ -109,8 +112,10 @@ class UnbalancedOilAndVinegar(SignatureScheme):
             x[i] = random_value(F)
             sig.append(x[i])
 
+        print("random_values =", sig )
+
         # Durch einsetzen der belegten Variablen wird P linearisiert
-        for i in xrange(0, len(P)):
+        for i in xrange(0, len(Pr)):
             Pr[i] = Pr[i](x)
 
         # Die gelösten Variablen werden entfernt
@@ -134,8 +139,9 @@ class UnbalancedOilAndVinegar(SignatureScheme):
         b = msg - b
 
         # sagemath bietet eine einfache Methode die Lösung des GS zu finden
+        # sollte keine Lösung gefunden werden können muss die
         for x in A.solve_right(b):
             sig.append(x)
 
-        # Die Lösung von "P(sig) = msg" wird zurückgegeben
+        # Die Lösung von "Pr(sig) = msg" wird zurückgegeben
         return vector(F, sig)
diff --git a/classes/__init__.py b/classes/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/classes/helpers/AffineTransformation.py b/classes/helpers/AffineTransformation.py
index ca63c10..cbafeb0 100644
--- a/classes/helpers/AffineTransformation.py
+++ b/classes/helpers/AffineTransformation.py
@@ -1,3 +1,6 @@
+#!/usr/bin/sage
+# -*- coding: utf-8 -*-
+
 from __future__ import absolute_import, division, print_function
 from sage.all import *
 
@@ -16,20 +19,20 @@ class AffineTransformation():
         self.M = M  # invertierbare Matrix
         self.y = y  # Vektor
 
-    def __call__(self, vector):
+    def __call__(self, v):
         """Anwenden der Transformation auf den gegebenen Vektor"""
 
-        # Sollte `vector` eine Liste sein -> Typecast
+        # Sollte `v` eine Liste sein -> Typecast
         if not isinstance(vector, sage.structure.element.Vector):
-            vector = vector(vector)
+            v = vector(v)
 
-        return (self.M * vector) + self.y
+        return (self.M * v) + self.y
 
-    def inverse(self, vector):
+    def inverse(self, v):
         """Anwenden der inversen Transformation auf den gegebenen Vektor"""
 
-        # Sollte `vector` eine Liste sein -> Typecast
+        # Sollte `v` eine Liste sein -> Typecast
         if not isinstance(vector, sage.structure.element.Vector):
-            vector = vector(vector)
+            v = vector(v)
 
-        return self.M.inverse() * (vector - self.y)
+        return self.M.inverse() * (v - self.y)
diff --git a/classes/helpers/EncryptionScheme.py b/classes/helpers/EncryptionScheme.py
index a59d1dd..688512a 100644
--- a/classes/helpers/EncryptionScheme.py
+++ b/classes/helpers/EncryptionScheme.py
@@ -1,3 +1,5 @@
+#!/usr/bin/sage
+# -*- coding: utf-8 -*-
 from sage.all import *
 
 from .SignatureScheme import SignatureScheme
diff --git a/classes/helpers/PolynomialSystem.py b/classes/helpers/PolynomialSystem.py
new file mode 100644
index 0000000..d913c8c
--- /dev/null
+++ b/classes/helpers/PolynomialSystem.py
@@ -0,0 +1,20 @@
+#!/usr/bin/sage
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, print_function
+
+
+class PolynomialSystem(object):
+    def __init__(self, P):
+        self.P = P
+
+    def __repr__(self):
+        return self.P
+
+    def __call__(self, variables):
+
+        ret = []
+        for p in self.P:
+            ret.append(p(variables))
+
+        return ret
diff --git a/classes/helpers/PrivateKey.py b/classes/helpers/PrivateKey.py
index 6797c77..14c66a0 100644
--- a/classes/helpers/PrivateKey.py
+++ b/classes/helpers/PrivateKey.py
@@ -1,3 +1,6 @@
+#!/usr/bin/sage
+# -*- coding: utf-8 -*-
+
 from __future__ import absolute_import, division, print_function
 from sage.all import vector
 import cPickle as pickle
@@ -9,7 +12,7 @@ class PrivateKey(object):
     def __init__(self, S, Pr, T, path=None):
         # wird ein Schlüssel als Dateipfad übergeben, so wird dieser geladen
         if path is not None:
-            (self.S, self.P, self.T) = self.load(path)
+            (S, Pr, T) = self.load(path)
 
         self.S = S    # Affine Transformation
         self.Pr = Pr  # Polynomsystem
@@ -17,7 +20,7 @@ class PrivateKey(object):
 
     def generate_public_key(self):
         # in `x` sind die Variablen x1,...,xn
-        x = vector(self.P[0].parent().gens())
+        x = vector(self.Pr[0].parent().gens())
 
         # angewendet auf die Verschlüsselung ergibt
         # dies das öffentliche Polynom
@@ -29,15 +32,17 @@ class PrivateKey(object):
         # Die Verschlüsselung wurde angepasst um nicht von
         # dem PublicKey abzuhängen sondern von (S,Pr,T)
         sx = list(self.S(vector(message)))
-        spx = self.Pr(list(sx))
-        return self.T(spx)
+        spx = []
+        for p in self.Pr:
+            spx.append(p(sx))
+        return self.T(vector(spx))
 
     """ Es folgt eine sehr einfache Möglichkeit den Schlüssel zu
     speichern und entsprechend auch wieder zu laden """
 
-    def save(self, path="./keys/uov.priv"):
+    def save(self, path="./keys/key.priv"):
         with open(path, 'wb') as output:
-            pickle.dump((self.S, self.P, self.T),
+            pickle.dump((self.S, self.Pr, self.T),
                         output, pickle.HIGHEST_PROTOCOL)
 
     def load(self, path):
diff --git a/classes/helpers/PublicKey.py b/classes/helpers/PublicKey.py
index c6d75b2..8ffd221 100644
--- a/classes/helpers/PublicKey.py
+++ b/classes/helpers/PublicKey.py
@@ -1,4 +1,8 @@
+#!/usr/bin/sage
+# -*- coding: utf-8 -*-
+
 from __future__ import absolute_import, print_function
+from sage.all import vector
 import cPickle as pickle
 
 
@@ -20,16 +24,21 @@ class PublicKey(object):
     def encrypt(self, msg):
         # der Vektor `msg` muss als Liste an Sage übergeben werden
         # Sage kann dann eigenständig das Polynomsystem ausrechen
-        return self.P(list(msg))
+        msg = list(msg)
+        solution = []
+        for p in self.P:
+            solution.append(p(msg))
+
+        return vector(solution)
 
-    def verify(self, msg, signature):
+    def verify(self, msg, sig):
         # Vergleiche gegebene Singatur mit generierter Signatur
-        return signature == self.encrypt(msg)
+        return msg == self.encrypt(sig)
 
     """ Es folgt eine sehr einfache Möglichkeit den Schlüssel zu
     speichern und entsprechend auch wieder zu laden """
 
-    def save(self, path="./keys/uov.pub"):
+    def save(self, path="./keys/key.pub"):
         with open(path, 'wb') as output:
             pickle.dump(self.P, output, pickle.HIGHEST_PROTOCOL)
 
diff --git a/classes/helpers/SignatureScheme.py b/classes/helpers/SignatureScheme.py
index 63e8881..ab6b722 100644
--- a/classes/helpers/SignatureScheme.py
+++ b/classes/helpers/SignatureScheme.py
@@ -1,3 +1,6 @@
+#!/usr/bin/sage
+# -*- coding: utf-8 -*-
+
 from sage.all import *
 
 
@@ -22,7 +25,7 @@ class SignatureScheme(object):
         '''Platzhalter für alle Signatur- und Verschlüsselungsverfahren'''
         raise NotImplementedError
 
-    def verify(self, signature, msg):
+    def verify(self, msg, sig):
         # da SignatureScheme nicht direkt von PublicKey erbt wird
         # die Verifikation extra zur Verfügung gestellt
-        return self.public_key.verify(signature, msg)
+        return self.public_key.verify(msg, sig)
diff --git a/classes/helpers/sage_extensions.py b/classes/helpers/sage_extensions.py
index 6e87232..59f7a50 100644
--- a/classes/helpers/sage_extensions.py
+++ b/classes/helpers/sage_extensions.py
@@ -1,3 +1,6 @@
+#!/usr/bin/sage
+# -*- coding: utf-8 -*-
+
 from __future__ import absolute_import
 from sage.all import random_matrix, random_vector, random
 
diff --git a/keys/bsp_uov.priv b/keys/bsp_uov.priv
new file mode 100644
index 0000000000000000000000000000000000000000..b58b64b7dff26ab5dfef0d56e179a060c63bb4f9
GIT binary patch
literal 2023
zcmZo*(nwCuNh~f-E!N9O%_&GND%NvMOUukl4Jk^@D^ANV%1tcE%+KS(Dp<&vU&vHj
z$gB~{Seaa$n4YSao1apelUl4-mYQ6WUlgC4pOP1!lA2eX%2k?IkeQsFlNw)U$W_Rq
z0a0FDQdF8;Qd*R%mzD_9P|1~^nwMIXnH&%0$HTO76|&;glarsHU0M*Io|B)Hn8Q`b
z7Ru#Tl$z=bc1j_8YfvGFH@i2hH)DGtr$z>=Mh06bw_9djW=X1BW@=7KAy;cqA$JBR
z)cB&zy!2wd%)FA+^wc7*+{EnEco?UUCzR2&HK>p`l(C|<kk2oa1?0a%{!pgs+6>+d
zo=`@^)}TUxj*>#b+LA({ph979=1#woLXp~%LeZc?vDiX!6id>;j)+IG5fo%xzWFI!
zg%ThGja!2XB|!|3y;2#%?Lmdo8DJTZRWcb6Az6qJNU<DLNIun@*_*YaB&bj!l+hOw
z+PR4(MVS?P5Xt}^BV2`wP-j78pb9`Pfks|@T26jq370QeKc;x062yE&Y?kI_7M7;Q
z7o`>yr52~=l|a%^X<kukN@;Q`SD`XQ1FC(+1&PV2P)mZr>_Qcd3}J6(Z|2TW*0h|=
zyplrIlG^q{wV*=v&e}qaQ0A1>l0r>{=e3}o*Dm&E><Hy#WMN@qU}9usYWL<U2`bbn
zO^Pklg?bed=mq&Xm3jHOnTa`ixurQJnehmL_?*n7;>^7C(wxL1cu>Xr2EcWoC@9o}
z_=s|2gEI5dQH|Em5DsOkFeo$#WvVbNGz?{`Fe)@^FEqwsV@YaJZhU@GN@@{TNNQ28
zKbTc$qS;tzT3cwQ5y~46^HzLuNl~GBC{s#7p+zW1e0geSdPYfcp`~9adpsm+3a$J?
zS>y8(b5jegLpf7Y(~DBea#AY_Z9@6ta}$#jOLGz{jljm(hO)Z{rIz`mRutNWiXg1W
z%`Zw#%E?d8E-tk9W(Z}E&q>WoFUcr$@MaF>iqB0<&rJmDcMRoJf|{;W=oHExAD@z+
z93Nlk93sTXz`*4KvN~0vD77rLs5n(2C$%CoIX}H9u^=NeSwREtFii!J?-jtl*W=>y
zNi9)Gh)GFJ*Qkg~)KsulNQ^gB&{jx{H&W16h)KyWDF*ZM5_A+wGE(!n5-Q>n6>JnL
z;*t^+GSd_i^HLP@^KvRdY$RiB6re^XX(lM-7opmKB$b$#!c~%yT9m4gT9H{?Qml|*
zs1TErs*njL^AZ$_OOrDcN-`2l6cQ5S^Av0qlH&7pAnwvpNQ|$})HbXIi-K7op-crk
zg{1h*1U;@omr(Y2Xu!H^mL|0a6}r_Hy5maSpmd#*nOp)X&|E`G3vyDq3O#BIJ-r#c
z8H>G{+ky(cAQ{P|HK@=Vnvr}mJZiymz8N59p`SN{Hxop)KSU(Jn-Qiz5TYMc3I##+
z2WNQH7KV5;!IXq%fJMSIK(>N}OTngxXZV!11r<hQ=w-Oo7Dj4-bVY%bK&*;}7z`@$
zVxR`cf|SHTjA8U<gcuVKHXUqY0>pKR2=^v|B@2_i;qFa=7;DrTRG11iHVtHKI>=!V
zn=>GqG9eZ*!7R$kNCUYyJ5?itF~2aUwlEh|17@&*YZs0TPEe`E1S<LSYD)_9g9-~`
z3kx+Mwi&br6&68lD@F*FK!r+Ey_q1zc3CK+Z-$~qhEj%d2Dlhx@@DGH0GEH|L4_5a
hwS|=#(4r3%FjY_ks=-Ac3nK#qBc#-;DNSnE0|4RgtZ)DT

literal 0
HcmV?d00001

diff --git a/keys/bsp_uov2.priv b/keys/bsp_uov2.priv
new file mode 100644
index 0000000000000000000000000000000000000000..9888565e6ce5c97005eb2b57c3a08dfa7b77ac05
GIT binary patch
literal 2030
zcmZo*(nwCuNh~f-E!N9O%_&GND%NvMOUukl4Jk^@D^ANV%1tcE%+KS(Dp<&vU&vHj
z$gB~{Seaa$n4YSao1apelUl4-mYQ6WUlgC4pOP1!lA2eX%2k?IkeQsFlNw)U$W_Rq
z0a0FDQdF8;Qd*R%mzD_9P|1~^nwMIXnH&%0$HTO76|&;glarsHU0M*Io|B)Hn8Q`b
z7Ru#Tl$z=bc1j_8YfvGFH@i2hH)DGtr$z>=Mh06bw_9djW=X1BW@=7KAy;cqAva6~
z57d^T%)Insz0ACl)b!LMuH3}z)OZ-DkT;akv^A)ZFO;#OwUFO0lm+C?LV-}G>e>vx
z4Bk*i!`7fe!H$wbq1uu{;h;hhZ{|+Fl0wnil0vbdLh;x_2^34xz;200u@Mw<T)z1!
zT!oS#0}Wb(3Z*~{kiF6wBJDwiG8u3g*$jw~97M>ZHK<S?Dx{F=&FszEQ4&<B7|Q4i
z3H02=lA_ECJqTq0j~K2(C8)C?GEfB|mq6n%J}oCdv4qPPtRGXnP#I!AB2r89G7C#n
z<BL)Yic*VH^GYB|sWh)BHKjB;m8(z%q5;*u;)2BFRH!AvV0NLZMuvztvo~{RC~I0y
zW?o65T1jntp?XlEMrUoIW+-z?YDu9M#Pgt_*M@ptr`VgZBb1Yck&%UkftiV+-J7c<
zs8F{wDYj4#>QzXf7v$$u=H=&RCg$knmgbaX#v=scb25{PGxO3*a}tZ-K^5;C0M~({
zpim#;Bg%~p%FIhgHQFFUB$TPbpwKXsslu?(D3qzfsL;5*&;*B#C8<TZ@%cq5sYP5N
zsYSW|U{;~2W@DjQZK1hFC~rK>Tk*vuMTHijOeqD0mZ2Q+<*AwJ870MqR(_%E@sOw~
zwDt>Sjn7NWO)azu<xELUFG?-TNv$Zf4dsi^O-xQK%}J~@0vlr&%I+SNTIQ2lQD`43
zg0LbtzbG{+CqFs6xX{6yA(TBnCp9m<B%{#Ln>my#J~uHvHxaDgDU?$QYPwRPb0~X!
zd`f<De0-rxh!7(K1D6ZP>QsfI)Uwo~;#7s4)QZgH{Pd#4f{e^$1r4~vG!;O;R{;B7
zkBiGEwL~EyCM7jpqarR*Q^8gtG2T!?TOl#tNI_d6CMCb57|hE{&`~JKNX_F)sEA8c
zuu-UpOG;44OjAhAOHs(r%c%shk&LlXfEt;knV^tgglYqlRAOEVS4l={QK~{}MP_kH
zu|k5OLQGDoLME8ZOHe2-P0mm#$w(|wNJxy&Q?OM?iqF%5xJySNF}^xe+prca3TA<X
zG8OC;lHxNH^tcLLL)qh@0qdq&n$#Xt=w4gsfh%=`(sfE^atWkBa}6mi$VufY^sFuP
z@@DX6EcRw@3o7)6WF$~2;seb{z8RjiU^%}G5VO$Vo57n2qB;N~66nnc(;o!UZ`>MG
z7!1`PlHplf80yUgQxcW|775n?*$NUa1)Cm`;al1kR2Z3|pW$9x7^MNy6%A4Xu_^{)
zFerz|LJf`sDT#*|!|2TjF(v_QI@rWSi0hIN?o9?u7N#KFn+h@3s5PiC4QgyU$k+^!
z!yq<iLNsMTEMkILl%0_da&JzmMh0VkVQy_<9;hPBU;$S$92uOTQi};x^5@r<6cz*(
z7RDA9X&`JXhT2vF5dsBRDO9K|)td=YY?p^J`erC;WGH8-WPpo7CU2(B3~>2Z5mZ>&
hSzB0@0WJDK22?{0r~wy!EKH2d%#c#Awlt|-4*<zFuDbvL

literal 0
HcmV?d00001

diff --git a/test.py b/test.py
new file mode 100644
index 0000000..8d6db94
--- /dev/null
+++ b/test.py
@@ -0,0 +1,28 @@
+from __future__ import absolute_import, division, print_function
+from sys import exit
+from sage.all import *
+
+from classes.helpers.AffineTransformation import *
+
+k = GF(4, 'a')  # hat modulus x^2 + x + 1
+(a,) = k.gens()
+n = 3
+
+ring = PolynomialRing(k, 'x')
+(x,) = ring.gens()
+gx = x**3 + x + 1
+
+K = ring.quotient_ring(gx, 'X')
+
+q = len(k)
+
+thetas = []
+qn = q**n - 1
+print("qn =", qn)
+for theta in xrange(1, n):
+    qd = q**theta + 1
+    print("qd =", qd)
+    (common_divider, t, _) = xgcd(qd, qn)
+    if common_divider == 1:
+        thetas.append((theta, t))
+thetas
diff --git a/test_UOV.py b/test_UOV.py
new file mode 100644
index 0000000..30f7225
--- /dev/null
+++ b/test_UOV.py
@@ -0,0 +1,43 @@
+#!/usr/bin/sage
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, print_function
+from sys import exit
+from sage.all import *
+
+from classes.UnbalancedOilAndVinegar import UnbalancedOilAndVinegar
+
+# Variables that may be set by CLI
+q = 5  # Number of elements in F
+m = 4  # length of message
+n = 6  # length of signature
+
+# Computed Variables
+if n <= m:
+    exit(1)
+
+oil = n - m  # number of oil variables
+vinegar = m  # number of vinegar variables
+
+# Finite field with q elements
+finite_field = GF(q, 'a')
+
+# Multivariate Polynomial Ring over
+# `finite_field` with `n` variables
+ring = PolynomialRing(finite_field, 'x', n)
+
+"""TEST UOV"""
+
+# Initialize simple UOV
+UOV = UnbalancedOilAndVinegar(finite_field, n, m)
+
+# use a random vector
+msg = random_vector(finite_field, m)
+
+# generate Signature
+sig = UOV.sign(msg)
+
+# verify signature is valid
+print("msg =", msg)
+print("sig =", sig)
+print("UOV.verify(msg, sig):", UOV.verify(msg, sig))
-- 
GitLab