Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
MatsumotoImaiAExample.py 2.59 KiB
#!/usr/bin/sage
# -*- coding: utf-8 -*-

from __future__ import absolute_import, print_function
from sage.all import *
import copy as cp

from .helpers.sage_extensions import random_value, random_invertible_matrix

from .helpers.AffineTransformation import AffineTransformation
from .helpers.PrivateKey import PrivateKey
from .helpers.PrivateKey import PublicKey
from .helpers.EncryptionScheme import EncryptionScheme


class MatsumotoImaiAExample(EncryptionScheme):
    """Matsumoto Imai Scheme A implementation"""

    def phi(self, polynomail_a):
        return polynomail_a.list()

    def phi_inv(self, vector_a):  # -> b::Polynomial
        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()
            self.generate_example_keys()

    def generate_example_keys(self):
        k = self.finite_field
        (a,) = k.gens()
        n = 3

        ring = PolynomialRing(k, 'x')
        (x,) = ring.gens()
        gx = x**3 + x + 1

        (self.theta, self.theta_invers) = (2, 26)

        ML1 = matrix(k, [[a**2, a, a], [a, 1, 0], [1, 0, 1]])
        yL1 = vector(k, [0, 1, a])
        T = AffineTransformation(ML1, yL1)

        ML2 = matrix(k, [[1, 0, a], [0, 1, a], [1, a, 0]])
        yL2 = vector(k, [a, a**2, a**2])
        S = AffineTransformation(ML2, yL2)

        multivariate_ring = PolynomialRing(k, 'x1, x2, x3', 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_inv(Sx)  # <- phi_invers

        # Now the MAGIC happens
        # post_F = self.F(pre_F)

        post_F = extension_field("1 + (a + 1)*x1 + (a)*x2 + x3 + x1*x2 + (a)*x1*x3 + (a + 1)*x2*x3 + ((a) + (a)*x1 + x2 + (a + 1)*x3 + x1^2 + (a + 1)*x1*x2 + x2^2 + x2*x3)*T + ((a + 1) + (a + 1)*x1 + (a)*x2 + (a)*x3 + x1^2 + x1*x2 + (a)*x1*x3 + (a + 1)*x2^2 + (a)*x2*x3 + (a + 1)*x3^2)*T^2")

        SPTx = T(vector(post_F.list()))

        Pr = T.inverse(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))
        return vector(self.phi(X**self.theta_invers))