安全多方计算(MPC)的SPDZ库快速入门教程

  • Post author:
  • Post category:其他


原作:

​​​​​​data61/MP-SPDZ:用于多方计算的多功能框架 (github.com)

写在前面

该软件用于对各种安全多方计算(MPC)协议进行基准测试,例如SPDZ,SPDZ2k,MASCOT,Overdrive,BMR乱码电路,Yao的乱码电路,以及基于三方复制秘密共享以及Shamir秘密共享(诚实多数)的计算。

常见问题




该文档

包含有关许多常见问题的部分,以及有关如何解决常见问题的信息(附链接:



Welcome to MP-SPDZ’s documentation! — MP-SPDZ documentation



)。




TL;DR (Linux 上的二进制发行版或 macOS 上的源代码发行版)




这需要最初发布于2014年或之后的Linux发行版(glibc 2.17)或macOS High Sierra或更高版本,以及Python 3和基本的命令行实用程序。



下载并解压缩

分发包

,然后从顶部文件夹执行以下操作(附链接:



https://github.com/data61/MP-SPDZ/releases



):

Scripts/tldr.sh
./compile.py tutorial
echo 1 2 3 4 > Player-Data/Input-P0-0
echo 1 2 3 4 > Player-Data/Input-P1-0
Scripts/mascot.sh tutorial

这将运行具有双方和恶意安全性

的教程

(附链接:

https://github.com/data61/MP-SPDZ/blob/master/Programs/Source/tutorial.mpc

)。




TL;DR (源代码分发)




在Linux上,这需要一个工作工具链和

所有要求(附链接:)




https://github.com/data61/MP-SPDZ#requirements




所有要求(附链接:)

。在 Ubuntu 上,以下内容可能就足够了:

apt-get install automake build-essential git libboost-dev libboost-thread-dev libntl-dev libsodium-dev libssl-dev libtool m4 python3 texinfo yasm

在 MacOS 上,这需要安装

brew

(附链接:

The Missing Package Manager for macOS (or Linux) — Homebrew

),这将用于所有依赖项。它将使用双方和恶意安全性执行

教程

(附链接:

https://github.com/data61/MP-SPDZ/blob/master/Programs/Source/tutorial.mpc

)。

请注意,这仅适用于 git 克隆,而不适用于二进制版本。

make -j 8 tldr
./compile.py tutorial
echo 1 2 3 4 > Player-Data/Input-P0-0
echo 1 2 3 4 > Player-Data/Input-P1-0
Scripts/mascot.sh tutorial

前言

该软件的主要目的是在各种协议中运行相同的计算,以比较性能。以下列表中的所有协议均已完全实现。此外,还有更多的协议仅部分实现,最值得注意的是Overdrive协议。默认情况下,它们处于停用状态,以避免在安全性方面出现混淆。请参阅有关如何激活它们的

编译部分

(附链接:

GitHub – data61/MP-SPDZ: Versatile framework for multi-party computation

)。

协议

下表列出了完全支持的所有协议。

PS:malicious 恶意的        covert 隐蔽的      semi-honest  半诚实的

模素数和模数 2^k 是允许类整数计算的两个设置。对于 k = 64,后者对应于广泛使用的 64 位处理器上可用的计算。GF(2^n) 表示阶数为 2^n 的伽罗瓦扩展场,它与计算模数 2^n 不同。特别是,每个元素都有一个逆元,而不是模2^n的情况。有关介绍,请参阅

此文章



https://en.wikipedia.org/wiki/Finite_field

)。模素数和GF(2^n)被混为一谈,因为由于数学性质,协议非常相似。

Bin.SS代表二进制秘密共享,即秘密共享模二。在某些设置中,这需要特定的协议,因为某些协议要求域大小大于两个。在其他设置中,协议在数学上是相同的,但特定的实现允许进行优化,例如对机器字使用按位操作的固有并行性。

安全模型指定有多少方被”允许”在什么意义上行为不端。恶意意味着不遵循协议至少会被检测到,而半诚实意味着即使是腐败的一方也会被假定遵循协议。有关各种安全模型的解释和对多方计算的高级介绍,请参阅本文(

Cryptology ePrint Archive: Report 2020/300 – Secure Multiparty Computation (MPC)

)。



寻找最有效的协议




较低的安全要求通常允许更有效的协议。在同一安全模型(上表中的行)中,需要考虑以下几点:

  • 计算域:算术协议(模素数或二的幂)对于许多应用更可取,因为它们以低成本提供整数加法和乘法。但是,如果整数计算非常少,二进制电路可能是更好的选择。

    请参阅下文



    https://github.com/data61/MP-SPDZ#finding-the-most-efficient-variant

    ),找到最有效的混合电路变体。此外,本地计算模数为2的幂更便宜,但MP-SPDZ不提供具有同态加密的域。

  • 秘密共享与乱码电路:使用秘密共享的计算需要许多通信轮次,这些轮次根据计算而增长,而乱码电路则不是这种情况。然而,作为二进制电路的整数计算的成本通常会抵消这一点。MP-SPDZ仅提供具有二进制计算的乱码电路。

  • 不诚实多数的底层技术:虽然秘密共享本身足以满足诚实多数的计算,但不诚实的多数需要同态加密(HE)或遗忘转移(OT)。这两个选项提供了计算通信权衡:虽然OT更容易计算,但HE需要的通信更少。此外,后者需要一定的批处理才能有效,这使得OT更适合较小的任务。

  • 恶意的、诚实的多数三方计算:许多协议可用于此设置,但 SY/SPDZ-wise 是最有效的协议,原因有很多:它需要最低的通信,并且是唯一提供恒定通信点产品的协议。

  • 定点乘法:三方和四方复制的秘密共享以及半诚实的全阈值协议允许特殊的概率截断协议(参见

    Dalskov等人



    Dalskov等人

    )。您可以通过在高级程序的开头添加来激活它。

    program.use_trunc_pr = True

  • 次要变体:某些命令行选项会更改协议的各个方面,例如:


    • --bucket-size

      :在某些恶意二进制计算和恶意 edaBit 生成中,较小的存储桶大小允许以更高的渐近开销进行较小的批处理。


    • --batch-size

      :小批量预处理可避免产生过多的批次,但较大的批次可节省通信轮次。


    • --direct

      :在不诚实的多数协议中,直接通信而不是星形通信以牺牲二次量为代价来节省通信回合。这可能对少数当事方有利。


    • --bits-from-squares

      在一些计算模素数的协议(Shamir,Rep3,SPDZ-wise)中,这从通过各方输入的异或生成到使用随机平方根生成。



概述




对于实际计算,软件实现了一个虚拟机,该虚拟机在特定字节码中执行程序。此类代码可以使用编译器从高级Python代码生成,该编译器优化计算,特别侧重于最小化通信轮次数(对于基于秘密共享的协议)或AES-NI流水线(用于乱码电路)。



该软件使用两个不同的字节码集,一个用于算术电路,一个用于布尔电路。高级代码在两种变体之间略有不同,但我们的目标是将这些差异保持在最低限度。



在计算部分,我们将解释如何为各种计算域编译高级程序,然后如何使用不同的协议运行它。



有关脱机阶段的部分将说明如何对 SPDZ 协议所需的脱机阶段进行基准测试。运行在线相位输出所需的离线材料量,这允许计算特定计算的预处理时间。



要求


  • GCC 5 或更高版本(最多 11 个测试)或 LLVM/clang 5 或更高版本(最多 12 个测试)。我们建议使用 clang,因为它的性能更好。
  • MPIR 库,使用C++支持编译(运行配置时使用标志)。您可以使用它在本地安装。

    --enable-cxx


    make -j8 tldr
  • libsodium 库,针对 1.0.18 进行测试
  • OpenSSL,针对 1.1.1 进行测试
  • Boost.Asio 支持 SSL(在 Ubuntu 上),针对 1.71 进行了测试

    libboost-dev
  • Boost.Thread for BMR(在 Ubuntu 上),针对 1.71 进行了测试

    libboost-thread-dev
  • x86 或 ARM 64 位 CPU(后者使用 AWS Gravitron 和 Apple Silicon 进行测试)
  • Python 3.5 或更高版本
  • 用于同态加密的 NTL 库(可选;使用 NTL 10.5 进行测试)
  • 如果使用 macOS、Sierra 或更高版本

编译

  1. 编辑或满足您的需求:

    CONFIG


    CONFIG.mine
  • 在 x86 上,二进制文件针对要编译的 CPU 进行了优化。对于 x86 上的所有优化,需要支持 AES-NI、PCLMUL、AVX2、BMI2、ADX 的 CPU。这包括 2014 年或之后发布的主流处理器。如果打算在与编译不同的 CPU 上运行,则可能需要将 中的变量更改为 。有关可能的选项,请参阅

    GCC 文档

    。要在没有 AVX 的情况下在 x86 上运行基于 OT 的协议,请添加。

    ARCH


    CONFIG


    CONFIG.mine


    -march=<cpu>


    AVX_OT = 0
  • 为了在 ARM 上的 Linux 上获得最佳结果,请添加到 。这将启用对 AES 的硬件支持。有关可用选项,请参阅

    GCC 文档



    ARCH = -march=-march=armv8.2-a+crypto


    CONFIG.mine
  • 要对仅联机协议或 Overdrive 脱机阶段进行基准测试,请在顶部添加以下行:

    MY_CFLAGS = -DINSECURE

  • PREP_DIR

    应指向本地的未版本化目录以存储预处理数据(默认位于当前目录中)。

    Player-Data

2.对于使用 GF(2^40) 的同态加密,请设置 。

USE_NTL = 1

运行以编译所有软件(使用该标志使用多个线程更快地编译)。请参阅下文,了解如何仅编译特定部分。请记住在更改 或 后先运行。

make


-j


make clean


CONFIG


CONFIG.mine

GCC文档:

x86 Options (Using the GNU Compiler Collection (GCC))

运行计算

请参见下列有关MPC程序的一些实例。此外,

“阅读文档”

还提供了从目录中的 Python 代码中提取的高级功能的更详细参考,以及相关编译器选项的摘要。

Programs/Source/


tutorial.mpc


Compiler

“阅读文档”链接:

Welcome to MP-SPDZ’s documentation! — MP-SPDZ documentation



编译高级程序




有三个计算域,必须相应地编译高级程序。



算术模 a 素数





./compile.py [-F <integer bit length>] [-P <prime>] <program>




整数位长度默认为 64,素数默认为 none 给定。如果给定一个素数,它必须比整数长度长至少两位。



请注意,在此上下文中,整数不会根据位整数位长度换行,而是将长度用于非线性计算,例如比较。如果没有给出具体的素数,则秘密整数的溢出可能会产生安全隐患。



与计算一起给出的参数要求对素模量进行一些限制,可以是精确值还是最小长度。后者大致是整数长度加 40(默认安全参数)。这些限制将传达给虚拟机,如果已相应地编译了这些限制,则虚拟机将使用适当的质数。默认情况下,它们被编译为最大 256 的质数位长度。对于较大的素数,您必须编译肢体的数量是素数长度除以64四舍五入。

MOD = -DGFP_MOD_SZ=<number of limbs>


CONFIG.mine




定点和浮点计算的精度不受整数位长度的影响,但可以直接在代码中设置。对于定点计算,这是通过 完成的。

sfix.set_precision()




算术模数 2^k





./compile.py -R <integer bit length> <program>




长度将传达给虚拟机,并在支持时自动使用。默认情况下,它们支持位长度 64、72 和 128。如果需要其他长度,请在 中使用。

MOD = -DRING_SIZE=<bit length>


CONFIG.mine




二进制电路





./compile.py -B <integer bit length> <program>




整数长度可以是任何数字,最大值取决于协议。所有协议都支持至少 64 位整数。



在二进制电路中,定点数 () 默认始终使用 16/16 位精度。这可以通过 更改。请参阅

教程



sfix


sfix.set_precision




如果要使用各种精度的整数,可以使用它来获取 -bit 算术的类型。

sbitint.get_type(n)


n




混合电路




MP-SPDZ 允许在同一安全模型中混合计算算术和二进制机密共享。在编译器中,这用于从算术计算切换到二进制计算,用于某些非线性函数,例如比较,位分解,截断和二的模幂,用于定点和浮点运算。有几种方法可以实现此目的,如下所述。



经典达比特




您可以通过在编译算术电路时添加来激活它,即计算模数为素数,计算模数为2^ k。

-X


./compile.py -X [-F <integer bit length>] <program>


./compile.py -X -R <integer bit length> <program>




在内部,这使用了

Rotaru和Wood

描述的daBits,这是在不同域中共享的秘密随机位。一些安全模型允许将随机位从算术直接转换为二进制,而其他安全模型则需要来自多方的输入,然后计算异或并检查恶意安全性,如Rotaru和Wood在第4.1节中所述。



扩展的达比特




扩展的daBits是由

Escuedro等人引入的

。您可以使用 而不是 激活它们。请注意,这也会在有用时激活经典 daBits。

-Y


-X




本地共享转换





Mohassel和Rindal

以及

Araki等人

已经使用了这种技术,并且

Demmler等人

已经使用了两方。它涉及在本地将算术共享转换为一组二进制共享,从中可以使用二进制加法器重建与算术共享等效的二进制共享。这需要在没有任何 MAC 的情况下通过环进行附加机密共享。您可以通过使用编译器来激活它,其中是标准变体的参与方数,Mohassel和Rindal的特殊变体的2方数(仅在Rep3中可用)。

-Z <n>


n




寻找最有效的变体




在可能的情况下,本地份额转换可能是最有效的变体。否则,edaBits可能会提供渐近的好处。将 edaBits 与恶意协议结合使用时,需要在单项目成本和批大小之间进行权衡。每个项目的最低成本需要大批量的edaBits(一次超过一百万),这对于相应的大型计算才有价值。可以通过使用 运行虚拟机来选择此设置。对于较小的计算,请尝试 or ,它将批大小分别设置为 ~10,000 和 ~1,000,渐近开销较高。 是默认值。

-B 3


-B 4


-B 5


-B 4




布里斯托尔时尚电路




布里斯托尔时尚是

SCALE-MAMBA

使用的二进制电路描述格式的名称。您可以从高级语言访问此类线路(如果它们存在于 中)。要运行 SCALE-MAMBA 随附的 AES-128 电路,可以运行以下命令:

Programs/Circuits


make Programs/Circuits
./compile.py aes_circuit
Scripts/semi.sh aes_circuit



这会下载电路,将其编译为MP-SPDZ字节码,并将其作为半诚实的双方计算并行运行1000次。然后,它应该输出 AES 测试向量 。您也可以使用任何其他协议运行它。

0x3ad77bb40d7a3660a89ecaf32466ef97




有关更多示例,请参阅

文档





从外部目录编译和运行程序




程序也可以从具有上述基本结构的任何目录进行编辑,编译和运行。因此,对于 中的源文件,所有 SPDZ 脚本都必须从 中运行。还必须从 中运行脚本以创建相关数据。例如:

./Programs/Source/


./


setup-online.sh


./


spdz$ cd ../
$ mkdir myprogs
$ cd myprogs
$ mkdir -p Programs/Source
$ vi Programs/Source/test.mpc
$ ../spdz/compile.py test.mpc
$ ls Programs/
Bytecode  Public-Input  Schedules  Source
$ ../spdz/Scripts/setup-online.sh
$ ls
Player-Data Programs
$ ../spdz/Scripts/run-online.sh test

TensorFlow


推理(不知道翻译的对不对)


MP-SPDZ 支持使用选定的 TensorFlow 图进行推理,尤其是

CrypTFlow

中使用的 DenseNet、ResNet 和 SqueezeNet。例如,您可以为 ImageNet 运行 SqueezeNet 推理,如下所示:

git clone https://github.com/mkskeller/EzPC
cd EzPC/Athos/Networks/SqueezeNetImgNet
axel -a -n 5 -c --output ./PreTrainedModel https://github.com/avoroshilov/tf-squeezenet/raw/master/sqz_full.mat
pip3 install scipy==1.1.0
python3 squeezenet_main.py --in ./SampleImages/n02109961_36.JPEG --saveTFMetadata True
python3 squeezenet_main.py --in ./SampleImages/n02109961_36.JPEG --scalingFac 12 --saveImgAndWtData True
cd ../../../..
Scripts/fixed-rep-to-float.py EzPC/Athos/Networks/SqueezeNetImgNet/SqNetImgNet_img_input.inp
./compile.py -R 64 tf EzPC/Athos/Networks/SqueezeNetImgNet/graphDef.bin 1 trunc_pr split
Scripts/ring.sh tf-EzPC_Athos_Networks_SqueezeNetImgNet_graphDef.bin-1-trunc_pr-split



这需要安装TensorFlow和axel命令行实用程序。它通过三方半诚实计算进行推理,类似于CrypTFlow的Porthos。将 1 替换为最后两行中所需的线程数。如果使用任何其他协议运行,则需要删除 和 。另请注意,您需要使用包含修补程序的 CrypTFlow 存储库

,该存储库 https://github.com/mkskeller/EzPC/commit/2021be90d21dc26894be98f33cd10dd26769f479



trunc_pr


split





该参考

包含有关可用图层的更多文档。



仿真




对于算术电路,模二次幂电路和二进制电路,可以模拟计算如下:




./emulate.x <program>




这将在明文计算中运行已编译的字节码。



Dishonest majority


一些完整的实现需要遗忘传输,这是作为基于

https://github.com/mkskeller/SimpleOT

或OpenSSL的OT扩展实现的(使用in或激活后者)。

AVX_OT = 0


CONFIG


CONFIG.mine



秘密共享


下表显示了使用机密共享进行不诚实多数计算的所有程序:



Mama 表示 MASCOT,其中包含多个 MAC,以将安全参数增加到素数长度的倍数。MAC 的数量缺省为 3,它由编译时参数控制(添加到 )。

N_MAMA_MACS


MY_CFLAGS += -DN_MAMA_MACS=<number of MACs>


CONFIG.mine




Semi和Semi2k表示剥离MASCOT / SPDZ2k恶意安全所需的所有步骤的结果,即放大,牺牲,MAC生成和OT关联检查。剩下的是使用OT生成加法共享的海狸三元组。



类似地,SemiBin表示使用OT生成按位乘法三元组的协议,没有任何恶意安全元素。



Tiny 表示 SPDZ2k 对二进制设置的适应。特别是,SPDZ2k牺牲对位不起作用,因此我们根据

Furukawa等人

将其替换为cut-and-choose。



LowGear和HighGear的虚拟机运行类似于

Rotaru等人

的密钥生成。主要区别在于使用 daBits 生成 maBits。CowGear和ChaiGear表示LowGear和HighGear的秘密安全版本。在所有相关程序中,选项在两者中激活

TopGear

零知识证明。

-T




Hemi和Soho分别表示LowGear和HighGear的剥离版本,用于类似于Semi的半诚实安全性,即使用半同态加密生成加法共享的Beaver三元组。Temi反过来又表示

Cramer等人

对基于LWE的半同态加密的适应性。Hemi和Temi都使用

Halevi和Shoup

的对角线填料进行矩阵乘法。



我们将使用MASCOT来演示使用,但其他协议的工作方式类似。



首先编译虚拟机:




make -j8 mascot-party.x




和一个高级程序,例如教程(用于SPDZ2k和Semi2k以及SemiBin):

-R 64


-B <precision>





./compile.py -F 64 tutorial




要在一台计算机上使用两方运行本教程,请运行:




./mascot-party.x -N 2 -I -p 0 tutorial





./mascot-party.x -N 2 -I -p 1 tutorial

(在单独的终端中)



使用激活交互模式,这意味着从标准输入中请求输入,并将输出提供给任何一方。省略会导致以文本格式读取输入。

-I


-I


Player-Data/Input-P<party number>-0




或者,您可以使用脚本在非交互模式下自动运行两个参与方:




Scripts/mascot.sh tutorial




要在两台不同的机器上运行程序,需要传递第一方正在运行的计算机,例如,如果这台机器是本地网络上的名称:

mascot-party.x


diffie





./mascot-party.x -N 2 -h diffie 0 tutorial





./mascot-party.x -N 2 -h diffie 1 tutorial




默认情况下,该软件使用大约5000的TCP端口,请使用参数来更改它。

-pn




姚氏乱码电路





编译虚拟机:




make -j 8 yao




和高级计划:




./compile.py -B <integer bit length> <program>




然后按如下方式运行:

  • 乱码:

    ./yao-party.x [-I] -p 0 <program>
  • 计算器:

    ./yao-party.x [-I] -p 1 -h <garbler host> <program>



在本地运行时,可以省略 host 参数。如上所述,激活交互式输入,否则将从 中读取输入。

-I


Player-Data/Input-P<playerno>-0




默认情况下,电路在块中出现乱码,每当收到时都会进行评估。您可以通过添加到两侧的命令行来一次激活所有乱码。

-O




Honest majority


下表显示了用于诚实多数计算的所有程序:



我们使用

Lindell和Nof

描述的”生成随机三重乐观/牺牲/海狸”方法来实现恶意安全,除了”PS”(牺牲后)协议,其中实际的乘法被乐观地执行,并在稍后进行检查,正如Lindell和Nof所描述的那样。、 、 和 分别对应于

Eerikson 等人

称为 DOS18 预处理(单个)、ABF+17 预处理、CDE+18 预处理和后处理的协议。我们使用

Cramer等人

的重新共享来共享Shamir的秘密共享,并使用

Araki等人

的优化方法来复制秘密共享。CCD协议以Chaum,Crépeau和Damgård

的历史论文

命名,该论文引入了使用Shamir秘密共享在特征二的扩展场上的二进制计算。SY/SPDZ-wise是指

由Chida等人

开始的计算模a素数的工作线,并由

Abspuel等人

进一步推动计算模数a的幂。它涉及共享类似于SPDZ的秘密值和信息理论标签,但不涉及附加秘密共享,因此得名。Rep4指的是

Dalskov等人

的四方协议。 基于

Furukawa等人

的cut-and-choose三代,但使用海狸乘法而不是他们的牺牲后方法。 基于

Araki 等人

的牺牲后方法,但没有使用他们的缓存优化。

brain-party.x


malicious-rep-ring-party.x -S


malicious-rep-ring-party.x


ps-rep-ring-party.x


malicious-rep-bin-party.x


ps-rep-bin-party.x




本节中的所有协议都需要加密通道,因为诚实的多数人收到的信息足以重建所有机密。因此,网络上的窃听者可以学习所有信息。



MP-SPDZ 使用 OpenSSL 实现安全通道。您可以按如下方式生成必要的证书和密钥:




Scripts/setup-ssl.sh [<number of parties>]




程序要求密钥和证书分别位于 和 中,并且证书具有播放器的公用名。此外,相关的根证书必须位于 OpenSSL 可以找到它们(运行)中。上面的脚本通过生成自签名证书来处理所有这些问题。因此,如果您在不同的主机上运行程序,则需要复制证书文件。

Player-Data/P<i>.key


Player-Data/P<i>.pem


P<i>


<i>


Player-Data


c_rehash Player-Data




在下文中,我们将演练与三方一起运行教程模 2^k。其他程序的工作方式类似。



首先,编译虚拟机:




make -j 8 replicated-ring-party.x




为了编译高级程序,请使用:

./compile.py -R 64





./compile.py -R 64 tutorial




如果使用其他计算域,请使用或

如上文相关部分

所述。

-F


-B




最后,按如下方式运行三方:




./replicated-ring-party.x -I 0 tutorial





./replicated-ring-party.x -I 1 tutorial

(在单独的终端中)




./replicated-ring-party.x -I 2 tutorial

(在单独的终端中)








Scripts/ring.sh tutorial




该参数启用交互式输入,并且在教程中,将要求参与方 0 和 1 提供三个数字。否则,在使用脚本时,将从 中读取输入。

-I


Player-Data/Input-P<playerno>-0




使用基于 Shamir 的秘密共享的程序时,可以指定 具有 的参与方数和 与 的最大损坏方数。后者最多只能是当事方数量的一半。

-N


-T




BMR


BMR(Bellare-Micali-Rogaway)是一种使用另一种安全计算协议生成乱码电路的方法。我们基于所有使用 GF(2^128) 的可用实现实现了 BMR,因为该字段的性质特别适合乱码电路的自由异或优化。我们的实施基于

SPDZ-BMR-ORAM建设

。下表列出了可用的方案。



在下文中,我们将演练一下基于 MASCOT 和双方的 BMR 教程。其他程序的工作方式类似。



首先,编译虚拟机。为了与三个以上的政党一起竞选,请相应地更改 in 的定义。

MAX_N_PARTIES


BMR/config.h





make -j 8 real-bmr-party.x




为了编译高级程序,请使用:

./compile.py -B





./compile.py -B 32 tutorial




最后,按如下方式运行两个方:




./real-bmr-party.x -I 0 tutorial





./real-bmr-party.x -I 1 tutorial

(在单独的终端中)








Scripts/real-bmr.sh tutorial




启用交互式输入,并在教程中将要求方 0 和 1 提供三个数字。否则,在使用脚本时,将从 中读取输入。

-I


Player