Building block: MPyC Secure matrix inverse

The code below is based on the demo ridgeregression.py from the MPyC library on Feb 26th, 2020, as implemented by Frank Blom. https://github.com/lschoe/mpyc/blob/2de1dd76db632bdc2a48acfbbaab841fa73cf8bd/demos/ridgeregression.py. The underlying theory is published in the paper ‘Efficient Secure Ridge Regression from Randomized Gaussian Elimination’ by Frank Blom, Niek J. Bouman, Berry Schoenmakers, and Niels de Vreede, presented at TPMPC 2019 by Frank Blom. See https://eprint.iacr.org/2019/773 (or https://ia.cr/2019/773).

Note: we added support for secure fixed points (SecFxp)

This building block is included in the TNO MPC Python Toolbox.

Install

Install the tno.mpc.mpyc.matrix_inverse package using one of the following options.

  • Personal access token

  • Deploy tokens

  • Cloning this repo (developer mode)

Personal access token

  1. Generate a personal access token with read_api scope. Instruction are found here.

  2. Install

    python -m pip install tno.mpc.mpyc.matrix_inverse --extra-index-url https://__token__:<personal_access_token>@ci.tno.nl/gitlab/api/v4/projects/5978/packages/pypi/simple
    

Deploy tokens

  1. Generate a deploy token with read_package_registry scope. Instruction are found here.

  2. Install

    python -m pip install tno.mpc.mpyc.matrix_inverse --extra-index-url https://<GITLAB_DEPLOY_TOKEN>:<GITLAB_DEPLOY_PASSWORD>@ci.tno.nl/gitlab/api/v4/projects/5978/packages/pypi/simple
    

Dockerfile

FROM python:3.8

ARG GITLAB_DEPLOY_TOKEN
ARG GITLAB_DEPLOY_PASSWORD

RUN python -m pip install tno.mpc.mpyc.matrix_inverse --extra-index-url https://$GITLAB_DEPLOY_TOKEN:$GITLAB_DEPLOY_PASSWORD@ci.tno.nl/gitlab/api/v4/projects/5978/packages/pypi/simple

Usage

example.py

import numpy as np
from mpyc.runtime import mpc
from tno.mpc.mpyc.matrix_inverse import matrix_inverse


async def main():
    X = (np.random.randint(low=-1000, high=1000, size=(5, 5)) / 10).tolist()
    Xinv = np.linalg.inv(X).tolist()
    await mpc.start()

    secfxp = mpc.SecFxp()
    X_mpc = [[secfxp(x) for x in row] for row in X]
    X_mpc = [mpc.input(row, 0) for row in X_mpc]

    inverse = matrix_inverse(X_mpc)
    Xinv_mpc = [await mpc.output(_) for _ in inverse]
    Xinv_mpc = [[float(xx) for xx in x] for x in Xinv_mpc]

    checker = mpc.matrix_prod(X_mpc, inverse)
    checker = [await mpc.output(_) for _ in checker]

    diff = np.array(Xinv) - np.array(Xinv_mpc)
    rel_diff = np.divide(
        diff, np.array(Xinv), out=np.zeros_like(diff), where=np.array(Xinv) != 0
    )

    await mpc.shutdown()

    print(f"X = \n{np.array(X)}\n")
    print(f"Xinv = \n{np.array(Xinv)}\n")
    print(f"Xinv_mpc = \n{np.array(Xinv_mpc)}\n")
    print(f"X * Xinv_mpc = \n{np.array(checker)}\n")
    print(f"max absolute diff = {np.abs(diff).max()}")
    print(f"max relative diff (nonzero entries) = {np.abs(rel_diff).max()}")


if __name__ == "__main__":
    mpc.run(main())

Indices and tables