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