Skip to main content

Secure Multi-Party Computation Protocol base on Partially Homomorphic Encryption for Python

Project description

安全多方计算协议


项目背景

安全多方计算(Secure Multi-Party Computation)的研究主要是针对无可信第三方的情况下,如何安全地计算一个约定函数的问题。安全多方计算是电子选举、门限签名以及电子拍卖等诸多应用得以实施的密码学基础。

一个安全多方计算协议,如果对于拥有无限计算能力攻击者而言是安全的,则称作是信息论安全的或无条件安全的;如果对于拥有多项式计算能力的攻击者是安全的,则称为是密码学安全的或条件安全的。

已有的结果证明了在无条件安全模型下,当且仅当恶意参与者的人数少于总人数的1/3时,安全的方案才存在。而在条件安全模型下,当且仅当恶意参与者的人数少于总人数的一半时,安全的方案才存在。

安全多方计算起源于1982年姚期智的百万富翁问题。后来Oded Goldreich有比较细致系统的论述。

基于phe库 (Paillier Homomorphic Encryption) 的安全多方计算协议实现,包含:

  • 安全乘法协议
  • 安全除法协议
  • 安全最大值计算协议
  • 安全最小值计算协议
  • 安全奇偶性判断协议
  • 安全二进制分解协议
  • 安全二进制与协议
  • 安全二进制或协议
  • 安全二进制非协议
  • 安全二进制异或协议
  • 安全相等协议
  • 安全不相等协议
  • 安全大于协议
  • 安全大于等于协议
  • 安全小于协议
  • 安全小于等于协议

项目环境

  • python3.8
  • gmpy2>=2.0.8
  • pandas>=1.2.4
  • phe>=1.4.0
  • tqdm>=4.59.0
  • numpy>=1.20.2

详见requirements.txt


项目示例

准备工作

安全依赖环境: pip install -r requirements.txt

安装smpcp库: pip install smpcp

引入phe库: import phe

引入smpcp库: from smpcp import CloudPlatform, CloudPlatformThird, SecureMultiPartyComputationProtocol

生成密钥

public_key, secret_key = phe.generate_paillier_keypair(n_length=2048)

其中n_length为密钥长度。

定义云服务器

cloud1 = CloudPlatform(public_key=public_key)
cloud2 = CloudPlatformThird(public_key=public_key, secret_key=secret_key)

定义安全多方计算协议

protocol = SecureMultiPartyComputationProtocol(c1=cloud1, c2=cloud2)

编码

n1 = protocol.encode(public_key.encrypt(6))
n2 = public_key.encrypt(3)
b1 = protocol.encode(public_key.encrypt(1))
b2 = public_key.encrypt(0)

解码

assert secret_key.decrypt(n1.decode()) == 6

安全多方计算协议实现

# TODO 安全乘法协议
assert secret_key.decrypt(n1 * n2) == 18
# TODO 安全除法协议
assert secret_key.decrypt(n1 / n2) == 2
# TODO 安全最大值协议
assert secret_key.decrypt(n1.optimum(n2, 'max')) == 6
# TODO 安全最小值协议
assert secret_key.decrypt(n1.optimum(n2, 'min')) == 3
# TODO 安全奇偶性判断协议
assert secret_key.decrypt(n1.parity()) == 0
assert secret_key.decrypt(protocol.encode(n2).parity()) == 1
# TODO 安全二进制分解协议
bit = []
for v in n1.bit_dec(3):
    bit.append(secret_key.decrypt(v))
assert bit == [1, 1, 0]
# TODO 安全二进制与协议
assert secret_key.decrypt(b1 | b2) == 1
# TODO 安全二进制或协议
assert secret_key.decrypt(b1 & b2) == 0
# TODO 安全二进制非协议
assert secret_key.decrypt(b1.bit_not()) == 0
# TODO 安全二进制异或协议
assert secret_key.decrypt(b1 ^ b2) == 1
# TODO 安全相等协议
assert secret_key.decrypt(n1 == n2) == 0
assert secret_key.decrypt(n1 == n2 * 2) == 1
# TODO 安全不相等协议
assert secret_key.decrypt(n1 != n2) == 1
assert secret_key.decrypt(n1 != n2 * 2) == 0
# TODO 安全大于协议
assert secret_key.decrypt(n1 > n2) == 1
assert secret_key.decrypt(n2 > n1) == 0
# TODO 安全大于等于协议
assert secret_key.decrypt(n1 >= n2) == 1
assert secret_key.decrypt(n2 >= n1) == 0
# TODO 安全小于协议
assert secret_key.decrypt(n1 < n2) == 0
assert secret_key.decrypt(n2 < n1) == 1
# TODO 安全小于等于协议
assert secret_key.decrypt(n1 <= n2) == 0
assert secret_key.decrypt(n2 <= n1) == 1

详见example.py


项目测试

经过Unit Test测试,测试结果如下:

key_length = 2048  # TODO 密钥长度

public_key, secret_key = phe.generate_paillier_keypair(n_length=key_length)  # 生成密钥对

cloud1 = CloudPlatform(public_key=public_key)  # 云服务器1
cloud2 = CloudPlatformThird(public_key=public_key, secret_key=secret_key)  # 云服务器2

protocol = SecureMultiPartyComputationProtocol(c1=cloud1, c2=cloud2)  # 安全多方计算协议类


class SMPCPTest(unittest.TestCase):
    """
    安全多方计算协议测试类
    """

    def setUp(self):
        """
        测试前
        """
        # 生成浮点数
        self.float1 = int(
            gmpy2.mpz_random(gmpy2.random_state(
                int(gmpy2.mpz_random(gmpy2.random_state(random.SystemRandom().randint(1, 0xffffffff)),
                                     key_length))), key_length)) * random.uniform(0.1, 1.0)
        self.float2 = int(
            gmpy2.mpz_random(gmpy2.random_state(
                int(gmpy2.mpz_random(gmpy2.random_state(random.SystemRandom().randint(1, 0xffffffff)), key_length))),
                key_length)) * random.uniform(0.1, 1.0)
        self.float_n1 = protocol.encode(public_key.encrypt(self.float1))
        self.float_n2 = public_key.encrypt(self.float2)
        # 生成整数
        self.int1 = int(gmpy2.mpz_random(gmpy2.random_state(
            int(gmpy2.mpz_random(gmpy2.random_state(random.SystemRandom().randint(1, 0xffffffff)), key_length))),
            key_length))
        self.int2 = int(gmpy2.mpz_random(gmpy2.random_state(
            int(gmpy2.mpz_random(gmpy2.random_state(random.SystemRandom().randint(1, 0xffffffff)), key_length))),
            key_length))
        self.int_n1 = protocol.encode(public_key.encrypt(self.int1))
        self.int_n2 = public_key.encrypt(self.int2)
        return super().setUp()

    def tearDown(self):
        """
        测试后
        """
        return super().tearDown()

    # TODO 安全乘法协议测试
    # @unittest.skip('跳过安全乘法协议')
    def test_mul(self):
        """
        安全乘法协议
        """
        # 浮点乘法测试:经过测试,最高支持8位浮点乘法
        self.assertEqual(round(self.float1 * self.float2, 8),
                         round(secret_key.decrypt(self.float_n1 * self.float_n2), 8))

        # 整数乘法测试:经过测试,无明显问题
        self.assertEqual(self.int1 * self.int2, secret_key.decrypt(self.int_n1 * self.int_n2))

    # TODO 安全除法协议测试
    # @unittest.skip('跳过安全除法协议')
    def test_div(self):
        """
        安全除法协议
        """
        # 浮点除法测试:经过测试,最高支持10位浮点除法
        self.assertEqual(round(self.float1 / self.float2, 10),
                         round(secret_key.decrypt(self.float_n1 / self.float_n2), 10))

        # 整数除法测试:经过测试,最高支持10位整数除法
        self.assertEqual(round(self.int1 / self.int2, 10), round(secret_key.decrypt(self.int_n1 / self.int_n2), 10))

    # TODO 安全最值计算协议测试
    # @unittest.skip('跳过安全最值计算协议')
    def test_optimum(self):
        """
        安全最值计算协议
        """
        mode = 'max' if random.random() > 0.5 else 'min'
        if mode == 'max':
            # 浮点最大值计算测试:经过测试,无明显问题
            self.assertEqual(max(self.float1, self.float2),
                             secret_key.decrypt(self.float_n1.optimum(self.float_n2, 'max')))

            # 整数最大值计算测试:经过测试,无明显问题
            self.assertEqual(max(self.int1, self.int2), secret_key.decrypt(self.int_n1.optimum(self.int_n2, 'max')))
        else:
            # 浮点最小值计算测试:经过测试,无明显问题
            self.assertEqual(min(self.float1, self.float2),
                             secret_key.decrypt(self.float_n1.optimum(self.float_n2, 'min')))

            # 整数最小值计算测试:经过测试,无明显问题
            self.assertEqual(min(self.int1, self.int2), secret_key.decrypt(self.int_n1.optimum(self.int_n2, 'min')))

    # TODO 安全奇偶性判断协议测试
    # @unittest.skip('跳过安全奇偶性判断协议')
    def test_parity(self):
        """
        安全奇偶性判断协议
        """
        # 整数奇偶性判断测试:经过测试,无明显问题
        self.assertEqual(self.int1 % 2, secret_key.decrypt(self.int_n1.parity()))

    # TODO 安全二进制分解协议测试
    # @unittest.skip('跳过安全二进制分解协议')
    def test_bit_dec(self):
        """
        安全二进制分解协议
        """
        # 整数二进制分解测试:经过测试,无明显问题
        bit = len(bin(self.int1).split('b')[1])
        result = ''.join([str(secret_key.decrypt(v)) for v in self.int_n1.bit_dec(bit)])
        self.assertEqual(bin(self.int1).split('b')[1], result)

    # TODO 安全二进制与协议测试
    # @unittest.skip('跳过安全二进制与协议')
    def test_and(self):
        """
        安全二进制与协议
        """
        bit1 = random.SystemRandom().randint(0, 1)
        bit2 = random.SystemRandom().randint(0, 1)
        bit_n1 = protocol.encode(public_key.encrypt(bit1))
        bit_n2 = public_key.encrypt(bit2)
        # 二进制或测试:经过测试,无明显问题
        self.assertEqual(bit1 & bit2, secret_key.decrypt(bit_n1 & bit_n2))

    # TODO 安全二进制或协议测试
    # @unittest.skip('跳过安全二进制或协议')
    def test_or(self):
        """
        安全二进制或协议
        """
        bit1 = random.SystemRandom().randint(0, 1)
        bit2 = random.SystemRandom().randint(0, 1)
        bit_n1 = protocol.encode(public_key.encrypt(bit1))
        bit_n2 = public_key.encrypt(bit2)
        # 二进制或测试:经过测试,无明显问题
        self.assertEqual(bit1 | bit2, secret_key.decrypt(bit_n1 | bit_n2))

    # TODO 安全二进制非协议测试
    # @unittest.skip('跳过安全二进制非协议')
    def test_bit_not(self):
        """
        安全二进制非协议
        """
        bit1 = random.SystemRandom().randint(0, 1)
        bit_n1 = protocol.encode(public_key.encrypt(bit1))
        # 二进制或测试:经过测试,无明显问题
        self.assertEqual(1 - bit1, secret_key.decrypt(bit_n1.bit_not()))

    # TODO 安全二进制异或协议测试
    # @unittest.skip('跳过安全二进制异或协议')
    def test_xor(self):
        """
        安全二进制异或协议
        """
        bit1 = random.SystemRandom().randint(0, 1)
        bit2 = random.SystemRandom().randint(0, 1)
        bit_n1 = protocol.encode(public_key.encrypt(bit1))
        bit_n2 = public_key.encrypt(bit2)
        # 二进制或测试:经过测试,无明显问题
        self.assertEqual(bit1 ^ bit2, secret_key.decrypt(bit_n1 ^ bit_n2))

    # TODO 安全相等协议测试
    # @unittest.skip('跳过安全相等协议')
    def test_eq(self):
        """
        安全相等协议
        """
        # 浮点数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.float1 == self.float1 else 0,
                         secret_key.decrypt(self.float_n1 == self.float_n1.decode()))

        # 整数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.int1 == self.int1 else 0, secret_key.decrypt(self.int_n1 == self.int_n1.decode()))

    # TODO 安全不相等协议测试
    # @unittest.skip('跳过安全不相等协议')
    def test_ne(self):
        """
        安全不相等协议
        """
        # 浮点数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.float1 != self.float2 else 0, secret_key.decrypt(self.float_n1 != self.float_n2))

        # 整数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.int1 != self.int2 else 0, secret_key.decrypt(self.int_n1 != self.int_n2))

    # TODO 安全大于协议测试
    # @unittest.skip('跳过安全大于协议')
    def test_gt(self):
        """
        安全大于协议
        """
        # 浮点数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.float1 > self.float2 else 0, secret_key.decrypt(self.float_n1 > self.float_n2))

        # 整数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.int1 > self.int2 else 0, secret_key.decrypt(self.int_n1 > self.int_n2))

    # TODO 安全大于等于协议测试
    # @unittest.skip('跳过安全大于等于协议')
    def test_ge(self):
        """
        安全大于等于协议
        """
        # 浮点数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.float1 >= self.float2 else 0, secret_key.decrypt(self.float_n1 >= self.float_n2))

        # 整数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.int1 >= self.int2 else 0, secret_key.decrypt(self.int_n1 >= self.int_n2))

    # TODO 安全小于协议测试
    # @unittest.skip('跳过安全小于协议')
    def test_lt(self):
        """
        安全小于协议
        """
        # 浮点数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.float1 < self.float2 else 0, secret_key.decrypt(self.float_n1 < self.float_n2))

        # 整数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.int1 < self.int2 else 0, secret_key.decrypt(self.int_n1 < self.int_n2))

    # TODO 安全小于等于协议测试
    # @unittest.skip('跳过安全小于等于协议')
    def test_le(self):
        """
        安全小于等于协议
        """
        # 浮点数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.float1 <= self.float2 else 0, secret_key.decrypt(self.float_n1 <= self.float_n2))

        # 整数相等测试:经过测试,极少数情况下,浮点数会影响结果
        self.assertEqual(1 if self.int1 <= self.int2 else 0, secret_key.decrypt(self.int_n1 <= self.int_n2))

详见test_case/test_smpcp.py, 项目报告依赖基于unittest项目test_case/BeautifulReport.py


联系方式

作者:沈阳航空航天大学 数据安全与隐私计算课题组 施展

Github: https://github.com/shine813/

邮箱:phe.zshi@gmail.com

如有问题,可及时联系作者

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

smpcp-2.0.2.tar.gz (11.1 kB view details)

Uploaded Source

Built Distribution

smpcp-2.0.2-py3-none-any.whl (8.5 kB view details)

Uploaded Python 3

File details

Details for the file smpcp-2.0.2.tar.gz.

File metadata

  • Download URL: smpcp-2.0.2.tar.gz
  • Upload date:
  • Size: 11.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.0 CPython/3.8.5

File hashes

Hashes for smpcp-2.0.2.tar.gz
Algorithm Hash digest
SHA256 19f89edb51c99066024056ca8831b35bdfe1a256493cd91726db02f35169c2e5
MD5 2e90fe5ed55c4b0dd0431ec99c20b0ac
BLAKE2b-256 13535285cee64e66a32789cd8c0cef69ecd655fb96a7f923aab12a43a43c7747

See more details on using hashes here.

File details

Details for the file smpcp-2.0.2-py3-none-any.whl.

File metadata

  • Download URL: smpcp-2.0.2-py3-none-any.whl
  • Upload date:
  • Size: 8.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.0 CPython/3.8.5

File hashes

Hashes for smpcp-2.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6676c4bd9c8f59b2d71ab82eb57ed180d5f14224156e766279d3dfa34b485efa
MD5 10fba74892c2583557a9dbba1076ed7a
BLAKE2b-256 5d0ed2aa01cae4b57bb6e3fd325aefc4d106fb1a739971ad2d52189b03e0d4d4

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page