mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-10 07:08:03 -05:00
chore(ci): add erc20 tests
This commit is contained in:
146
.github/workflows/gpu_integer_long_run_tests.yml
vendored
Normal file
146
.github/workflows/gpu_integer_long_run_tests.yml
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
name: AWS Long Run Tests on GPU
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
RUSTFLAGS: "-C target-cpu=native"
|
||||
RUST_BACKTRACE: "full"
|
||||
RUST_MIN_STACK: "8388608"
|
||||
SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
|
||||
SLACK_ICON: https://pbs.twimg.com/profile_images/1274014582265298945/OjBKP9kn_400x400.png
|
||||
SLACK_USERNAME: ${{ secrets.BOT_USERNAME }}
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
|
||||
|
||||
on:
|
||||
# Allows you to run this workflow manually from the Actions tab as an alternative.
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# Weekly tests will be triggered each Friday at 1a.m.
|
||||
- cron: '0 1 * * FRI'
|
||||
|
||||
jobs:
|
||||
setup-instance:
|
||||
name: Setup instance (gpu-tests)
|
||||
if: github.event_name != 'schedule' ||
|
||||
(github.event_name == 'schedule' && github.repository == 'zama-ai/tfhe-rs')
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
runner-name: ${{ steps.start-instance.outputs.label }}
|
||||
steps:
|
||||
- name: Start instance
|
||||
id: start-instance
|
||||
uses: zama-ai/slab-github-runner@801df0b8db5ea2b06128b7476c652f5ed5f193a8
|
||||
with:
|
||||
mode: start
|
||||
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
|
||||
slab-url: ${{ secrets.SLAB_BASE_URL }}
|
||||
job-secret: ${{ secrets.JOB_SECRET }}
|
||||
backend: hyperstack
|
||||
profile: single-h100
|
||||
|
||||
cuda-tests:
|
||||
name: Long run GPU H100 tests
|
||||
needs: [ setup-instance ]
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}_${{github.event_name}}_${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
runs-on: ${{ needs.setup-instance.outputs.runner-name }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# explicit include-based build matrix, of known valid options
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
cuda: "12.2"
|
||||
gcc: 11
|
||||
env:
|
||||
CUDA_PATH: /usr/local/cuda-${{ matrix.cuda }}
|
||||
CMAKE_VERSION: 3.29.6
|
||||
steps:
|
||||
# Mandatory on hyperstack since a bootable volume is not re-usable yet.
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y checkinstall zlib1g-dev libssl-dev libclang-dev
|
||||
wget https://github.com/Kitware/CMake/releases/download/v${{ env.CMAKE_VERSION }}/cmake-${{ env.CMAKE_VERSION }}.tar.gz
|
||||
tar -zxvf cmake-${{ env.CMAKE_VERSION }}.tar.gz
|
||||
cd cmake-${{ env.CMAKE_VERSION }}
|
||||
./bootstrap
|
||||
make -j"$(nproc)"
|
||||
sudo make install
|
||||
|
||||
- name: Checkout tfhe-rs
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
|
||||
- name: Set up home
|
||||
run: |
|
||||
echo "HOME=/home/ubuntu" >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Install latest stable
|
||||
uses: dtolnay/rust-toolchain@7b1c307e0dcbda6122208f10795a713336a9b35a
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Export CUDA variables
|
||||
if: ${{ !cancelled() }}
|
||||
run: |
|
||||
echo "CUDA_PATH=$CUDA_PATH" >> "${GITHUB_ENV}"
|
||||
echo "$CUDA_PATH/bin" >> "${GITHUB_PATH}"
|
||||
echo "LD_LIBRARY_PATH=$CUDA_PATH/lib:$LD_LIBRARY_PATH" >> "${GITHUB_ENV}"
|
||||
echo "CUDACXX=/usr/local/cuda-${{ matrix.cuda }}/bin/nvcc" >> "${GITHUB_ENV}"
|
||||
|
||||
# Specify the correct host compilers
|
||||
- name: Export gcc and g++ variables
|
||||
if: ${{ !cancelled() }}
|
||||
run: |
|
||||
{
|
||||
echo "CC=/usr/bin/gcc-${{ matrix.gcc }}";
|
||||
echo "CXX=/usr/bin/g++-${{ matrix.gcc }}";
|
||||
echo "CUDAHOSTCXX=/usr/bin/g++-${{ matrix.gcc }}";
|
||||
echo "HOME=/home/ubuntu";
|
||||
} >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Check device is detected
|
||||
if: ${{ !cancelled() }}
|
||||
run: nvidia-smi
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
make test_integer_long_run_gpu
|
||||
|
||||
slack-notify:
|
||||
name: Slack Notification
|
||||
needs: [ setup-instance, cuda-tests ]
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ always() && needs.cuda-tests.result != 'skipped' && failure() }}
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- name: Send message
|
||||
uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990
|
||||
env:
|
||||
SLACK_COLOR: ${{ needs.cuda-tests.result }}
|
||||
SLACK_MESSAGE: "Integer GPU H100 long run tests finished with status: ${{ needs.cuda-tests.result }}. (${{ env.ACTION_RUN_URL }})"
|
||||
|
||||
teardown-instance:
|
||||
name: Teardown instance (gpu-tests)
|
||||
if: ${{ always() && needs.setup-instance.result != 'skipped' }}
|
||||
needs: [ setup-instance, cuda-tests ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Stop instance
|
||||
id: stop-instance
|
||||
uses: zama-ai/slab-github-runner@801df0b8db5ea2b06128b7476c652f5ed5f193a8
|
||||
with:
|
||||
mode: stop
|
||||
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
|
||||
slab-url: ${{ secrets.SLAB_BASE_URL }}
|
||||
job-secret: ${{ secrets.JOB_SECRET }}
|
||||
label: ${{ needs.setup-instance.outputs.runner-name }}
|
||||
|
||||
- name: Slack Notification
|
||||
if: ${{ failure() }}
|
||||
continue-on-error: true
|
||||
uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990
|
||||
env:
|
||||
SLACK_COLOR: ${{ job.status }}
|
||||
SLACK_MESSAGE: "Instance teardown (gpu-long-run-tests) finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"
|
||||
94
.github/workflows/integer_long_run_tests.yml
vendored
Normal file
94
.github/workflows/integer_long_run_tests.yml
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
name: AWS Long Run Tests on CPU
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
RUSTFLAGS: "-C target-cpu=native"
|
||||
RUST_BACKTRACE: "full"
|
||||
RUST_MIN_STACK: "8388608"
|
||||
SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
|
||||
SLACK_ICON: https://pbs.twimg.com/profile_images/1274014582265298945/OjBKP9kn_400x400.png
|
||||
SLACK_USERNAME: ${{ secrets.BOT_USERNAME }}
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
|
||||
|
||||
on:
|
||||
# Allows you to run this workflow manually from the Actions tab as an alternative.
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# Weekly tests will be triggered each Friday at 1a.m.
|
||||
- cron: '0 1 * * FRI'
|
||||
|
||||
jobs:
|
||||
setup-instance:
|
||||
name: Setup instance (cpu-tests)
|
||||
if: github.event_name != 'schedule' ||
|
||||
(github.event_name == 'schedule' && github.repository == 'zama-ai/tfhe-rs')
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
runner-name: ${{ steps.start-instance.outputs.label }}
|
||||
steps:
|
||||
- name: Start instance
|
||||
id: start-instance
|
||||
uses: zama-ai/slab-github-runner@801df0b8db5ea2b06128b7476c652f5ed5f193a8
|
||||
with:
|
||||
mode: start
|
||||
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
|
||||
slab-url: ${{ secrets.SLAB_BASE_URL }}
|
||||
job-secret: ${{ secrets.JOB_SECRET }}
|
||||
backend: aws
|
||||
profile: cpu-big
|
||||
|
||||
cpu-tests:
|
||||
name: Long run CPU tests
|
||||
needs: [ setup-instance ]
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}_${{github.event_name}}_${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
runs-on: ${{ needs.setup-instance.outputs.runner-name }}
|
||||
steps:
|
||||
- name: Checkout tfhe-rs
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
with:
|
||||
persist-credentials: 'false'
|
||||
token: ${{ secrets.FHE_ACTIONS_TOKEN }}
|
||||
|
||||
- name: Install latest stable
|
||||
uses: dtolnay/rust-toolchain@7b1c307e0dcbda6122208f10795a713336a9b35a
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
make test_integer_long_run
|
||||
|
||||
- name: Slack Notification
|
||||
if: ${{ failure() }}
|
||||
continue-on-error: true
|
||||
uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990
|
||||
env:
|
||||
SLACK_COLOR: ${{ job.status }}
|
||||
SLACK_MESSAGE: "CPU long run tests finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"
|
||||
|
||||
teardown-instance:
|
||||
name: Teardown instance (cpu-tests)
|
||||
if: ${{ always() && needs.setup-instance.result != 'skipped' }}
|
||||
needs: [ setup-instance, cpu-tests ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Stop instance
|
||||
id: stop-instance
|
||||
uses: zama-ai/slab-github-runner@801df0b8db5ea2b06128b7476c652f5ed5f193a8
|
||||
with:
|
||||
mode: stop
|
||||
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
|
||||
slab-url: ${{ secrets.SLAB_BASE_URL }}
|
||||
job-secret: ${{ secrets.JOB_SECRET }}
|
||||
label: ${{ needs.setup-instance.outputs.runner-name }}
|
||||
|
||||
- name: Slack Notification
|
||||
if: ${{ failure() }}
|
||||
continue-on-error: true
|
||||
uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990
|
||||
env:
|
||||
SLACK_COLOR: ${{ job.status }}
|
||||
SLACK_MESSAGE: "Instance teardown (cpu-long-run-tests) finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"
|
||||
11
Makefile
11
Makefile
@@ -585,6 +585,11 @@ test_integer_gpu: install_rs_build_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --doc --profile $(CARGO_PROFILE) \
|
||||
--features=$(TARGET_ARCH_FEATURE),integer,gpu -p $(TFHE_SPEC) -- integer::gpu::server_key::
|
||||
|
||||
.PHONY: test_integer_long_run_gpu # Run the tests of the integer module including experimental on the gpu backend
|
||||
test_integer_long_run_gpu: install_rs_build_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||
--features=$(TARGET_ARCH_FEATURE),integer,gpu,__long_run_tests -p $(TFHE_SPEC) -- integer::gpu::server_key::radix::tests_long_run --test-threads=6
|
||||
|
||||
.PHONY: test_integer_compression
|
||||
test_integer_compression: install_rs_build_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||
@@ -765,6 +770,12 @@ test_signed_integer_multi_bit_ci: install_rs_check_toolchain install_cargo_nexte
|
||||
--cargo-profile "$(CARGO_PROFILE)" --multi-bit --avx512-support "$(AVX512_SUPPORT)" \
|
||||
--signed-only --tfhe-package "$(TFHE_SPEC)"
|
||||
|
||||
.PHONY: test_integer_long_run # Run the long run tests for integer
|
||||
test_integer_long_run: install_rs_build_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||
--features=$(TARGET_ARCH_FEATURE),integer,internal-keycache,__long_run_tests -p $(TFHE_SPEC) -- integer::server_key::radix_parallel::tests_long_run
|
||||
|
||||
|
||||
.PHONY: test_safe_serialization # Run the tests for safe serialization
|
||||
test_safe_serialization: install_rs_build_toolchain install_cargo_nextest
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||
|
||||
@@ -141,6 +141,7 @@ generator_aarch64_aes = ["tfhe-csprng/generator_aarch64_aes"]
|
||||
|
||||
# Private features
|
||||
__profiling = []
|
||||
__long_run_tests = []
|
||||
|
||||
seeder_unix = ["tfhe-csprng/seeder_unix"]
|
||||
seeder_x86_64_rdseed = ["tfhe-csprng/seeder_x86_64_rdseed"]
|
||||
|
||||
@@ -48,6 +48,8 @@ mod scalar_sub;
|
||||
mod shift;
|
||||
mod sub;
|
||||
|
||||
#[cfg(all(test, feature = "__long_run_tests"))]
|
||||
mod tests_long_run;
|
||||
#[cfg(test)]
|
||||
mod tests_signed;
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pub(crate) mod test_erc20;
|
||||
@@ -0,0 +1,65 @@
|
||||
use crate::integer::gpu::server_key::radix::tests_unsigned::{
|
||||
create_gpu_parametrized_test, GpuFunctionExecutor,
|
||||
};
|
||||
use crate::integer::gpu::CudaServerKey;
|
||||
use crate::integer::server_key::radix_parallel::tests_long_run::test_erc20::{
|
||||
no_cmux_erc20_test, safe_erc20_test, whitepaper_erc20_test,
|
||||
};
|
||||
use crate::shortint::parameters::*;
|
||||
|
||||
create_gpu_parametrized_test!(safe_erc20 {
|
||||
PARAM_GPU_MULTI_BIT_GROUP_3_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64
|
||||
});
|
||||
create_gpu_parametrized_test!(whitepaper_erc20 {
|
||||
PARAM_GPU_MULTI_BIT_GROUP_3_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64
|
||||
});
|
||||
create_gpu_parametrized_test!(no_cmux_erc20 {
|
||||
PARAM_GPU_MULTI_BIT_GROUP_3_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64
|
||||
});
|
||||
|
||||
fn safe_erc20<P>(param: P)
|
||||
where
|
||||
P: Into<PBSParameters>,
|
||||
{
|
||||
let overflowing_add_executor =
|
||||
GpuFunctionExecutor::new(&CudaServerKey::unsigned_overflowing_add);
|
||||
let overflowing_sub_executor =
|
||||
GpuFunctionExecutor::new(&CudaServerKey::unsigned_overflowing_sub);
|
||||
let if_then_else_executor = GpuFunctionExecutor::new(&CudaServerKey::if_then_else);
|
||||
let bitwise_or_executor = GpuFunctionExecutor::new(&CudaServerKey::bitor);
|
||||
safe_erc20_test(
|
||||
param,
|
||||
overflowing_add_executor,
|
||||
overflowing_sub_executor,
|
||||
if_then_else_executor,
|
||||
bitwise_or_executor,
|
||||
);
|
||||
}
|
||||
|
||||
fn whitepaper_erc20<P>(param: P)
|
||||
where
|
||||
P: Into<PBSParameters>,
|
||||
{
|
||||
let ge_executor = GpuFunctionExecutor::new(&CudaServerKey::ge);
|
||||
let add_executor = GpuFunctionExecutor::new(&CudaServerKey::add);
|
||||
let if_then_else_executor = GpuFunctionExecutor::new(&CudaServerKey::if_then_else);
|
||||
let sub_executor = GpuFunctionExecutor::new(&CudaServerKey::sub);
|
||||
whitepaper_erc20_test(
|
||||
param,
|
||||
ge_executor,
|
||||
add_executor,
|
||||
if_then_else_executor,
|
||||
sub_executor,
|
||||
);
|
||||
}
|
||||
|
||||
fn no_cmux_erc20<P>(param: P)
|
||||
where
|
||||
P: Into<PBSParameters>,
|
||||
{
|
||||
let ge_executor = GpuFunctionExecutor::new(&CudaServerKey::ge);
|
||||
let mul_executor = GpuFunctionExecutor::new(&CudaServerKey::mul);
|
||||
let add_executor = GpuFunctionExecutor::new(&CudaServerKey::add);
|
||||
let sub_executor = GpuFunctionExecutor::new(&CudaServerKey::sub);
|
||||
no_cmux_erc20_test(param, ge_executor, mul_executor, add_executor, sub_executor);
|
||||
}
|
||||
@@ -28,6 +28,8 @@ mod reverse_bits;
|
||||
mod slice;
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests_cases_unsigned;
|
||||
#[cfg(all(test, feature = "__long_run_tests"))]
|
||||
pub(crate) mod tests_long_run;
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests_signed;
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
pub(crate) mod test_erc20;
|
||||
pub(crate) const NB_CTXT_LONG_RUN: usize = 32;
|
||||
pub(crate) const NB_TESTS_LONG_RUN: usize = 1000;
|
||||
@@ -0,0 +1,528 @@
|
||||
use crate::integer::keycache::KEY_CACHE;
|
||||
use crate::integer::server_key::radix_parallel::tests_cases_unsigned::FunctionExecutor;
|
||||
use crate::integer::server_key::radix_parallel::tests_long_run::{
|
||||
NB_CTXT_LONG_RUN, NB_TESTS_LONG_RUN,
|
||||
};
|
||||
use crate::integer::server_key::radix_parallel::tests_unsigned::CpuFunctionExecutor;
|
||||
use crate::integer::tests::create_parametrized_test;
|
||||
use crate::integer::{
|
||||
BooleanBlock, IntegerCiphertext, IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey,
|
||||
};
|
||||
use crate::shortint::parameters::*;
|
||||
use rand::Rng;
|
||||
use std::sync::Arc;
|
||||
|
||||
create_parametrized_test!(safe_erc20 {
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64
|
||||
});
|
||||
create_parametrized_test!(whitepaper_erc20 {
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64
|
||||
});
|
||||
create_parametrized_test!(no_cmux_erc20 {
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64
|
||||
});
|
||||
create_parametrized_test!(overflow_erc20 {
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64
|
||||
});
|
||||
|
||||
fn safe_erc20<P>(param: P)
|
||||
where
|
||||
P: Into<PBSParameters>,
|
||||
{
|
||||
let overflowing_add_executor =
|
||||
CpuFunctionExecutor::new(&ServerKey::unsigned_overflowing_add_parallelized);
|
||||
let overflowing_sub_executor =
|
||||
CpuFunctionExecutor::new(&ServerKey::unsigned_overflowing_sub_parallelized);
|
||||
let if_then_else_executor = CpuFunctionExecutor::new(&ServerKey::cmux_parallelized);
|
||||
let bitwise_or_executor = CpuFunctionExecutor::new(&ServerKey::bitor_parallelized);
|
||||
safe_erc20_test(
|
||||
param,
|
||||
overflowing_add_executor,
|
||||
overflowing_sub_executor,
|
||||
if_then_else_executor,
|
||||
bitwise_or_executor,
|
||||
);
|
||||
}
|
||||
|
||||
fn whitepaper_erc20<P>(param: P)
|
||||
where
|
||||
P: Into<PBSParameters>,
|
||||
{
|
||||
let ge_executor = CpuFunctionExecutor::new(&ServerKey::ge_parallelized);
|
||||
let add_executor = CpuFunctionExecutor::new(&ServerKey::add_parallelized);
|
||||
let if_then_else_executor = CpuFunctionExecutor::new(&ServerKey::cmux_parallelized);
|
||||
let sub_executor = CpuFunctionExecutor::new(&ServerKey::sub_parallelized);
|
||||
whitepaper_erc20_test(
|
||||
param,
|
||||
ge_executor,
|
||||
add_executor,
|
||||
if_then_else_executor,
|
||||
sub_executor,
|
||||
);
|
||||
}
|
||||
|
||||
fn no_cmux_erc20<P>(param: P)
|
||||
where
|
||||
P: Into<PBSParameters>,
|
||||
{
|
||||
let ge_executor = CpuFunctionExecutor::new(&ServerKey::ge_parallelized);
|
||||
let mul_executor = CpuFunctionExecutor::new(&ServerKey::mul_parallelized);
|
||||
let add_executor = CpuFunctionExecutor::new(&ServerKey::add_parallelized);
|
||||
let sub_executor = CpuFunctionExecutor::new(&ServerKey::sub_parallelized);
|
||||
no_cmux_erc20_test(param, ge_executor, mul_executor, add_executor, sub_executor);
|
||||
}
|
||||
|
||||
fn overflow_erc20<P>(param: P)
|
||||
where
|
||||
P: Into<PBSParameters>,
|
||||
{
|
||||
let overflowing_sub_executor =
|
||||
CpuFunctionExecutor::new(&ServerKey::unsigned_overflowing_sub_parallelized);
|
||||
let if_then_else_executor = CpuFunctionExecutor::new(&ServerKey::cmux_parallelized);
|
||||
let not_executor = CpuFunctionExecutor::new(&ServerKey::boolean_bitnot);
|
||||
let mul_executor = CpuFunctionExecutor::new(&ServerKey::mul_parallelized);
|
||||
let add_executor = CpuFunctionExecutor::new(&ServerKey::add_parallelized);
|
||||
overflow_erc20_test(
|
||||
param,
|
||||
overflowing_sub_executor,
|
||||
if_then_else_executor,
|
||||
not_executor,
|
||||
mul_executor,
|
||||
add_executor,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn safe_erc20_test<P, T1, T2, T3, T4>(
|
||||
param: P,
|
||||
mut overflowing_add_executor: T1,
|
||||
mut overflowing_sub_executor: T2,
|
||||
mut if_then_else_executor: T3,
|
||||
mut bitor_executor: T4,
|
||||
) where
|
||||
P: Into<PBSParameters>,
|
||||
T1: for<'a> FunctionExecutor<
|
||||
(&'a RadixCiphertext, &'a RadixCiphertext),
|
||||
(RadixCiphertext, BooleanBlock),
|
||||
>,
|
||||
T2: for<'a> FunctionExecutor<
|
||||
(&'a RadixCiphertext, &'a RadixCiphertext),
|
||||
(RadixCiphertext, BooleanBlock),
|
||||
>,
|
||||
T3: for<'a> FunctionExecutor<
|
||||
(&'a BooleanBlock, &'a RadixCiphertext, &'a RadixCiphertext),
|
||||
RadixCiphertext,
|
||||
>,
|
||||
T4: for<'a> FunctionExecutor<(&'a RadixCiphertext, &'a RadixCiphertext), RadixCiphertext>,
|
||||
{
|
||||
let param = param.into();
|
||||
let (cks, mut sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
|
||||
|
||||
sks.set_deterministic_pbs_execution(true);
|
||||
let sks = Arc::new(sks);
|
||||
let cks = RadixClientKey::from((cks, NB_CTXT_LONG_RUN));
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
overflowing_add_executor.setup(&cks, sks.clone());
|
||||
overflowing_sub_executor.setup(&cks, sks.clone());
|
||||
if_then_else_executor.setup(&cks, sks.clone());
|
||||
bitor_executor.setup(&cks, sks);
|
||||
|
||||
for _ in 0..NB_TESTS_LONG_RUN {
|
||||
let clear_from_amount = rng.gen::<u64>();
|
||||
let clear_to_amount = rng.gen::<u64>();
|
||||
let clear_amount = rng.gen::<u64>();
|
||||
|
||||
let from_amount = cks.encrypt(clear_from_amount);
|
||||
let to_amount = cks.encrypt(clear_to_amount);
|
||||
let amount = cks.encrypt(clear_amount);
|
||||
|
||||
let (new_from, did_not_have_enough_funds) =
|
||||
overflowing_sub_executor.execute((&from_amount, &amount));
|
||||
let (new_to, did_not_have_enough_space) =
|
||||
overflowing_add_executor.execute((&to_amount, &amount));
|
||||
|
||||
let decrypted_did_not_have_enough_funds: bool =
|
||||
cks.decrypt_bool(&did_not_have_enough_funds);
|
||||
let decrypted_did_not_have_enough_space: bool =
|
||||
cks.decrypt_bool(&did_not_have_enough_space);
|
||||
|
||||
let did_not_have_enough_space_ct =
|
||||
RadixCiphertext::from_blocks(vec![did_not_have_enough_space.0]);
|
||||
let did_not_have_enough_funds_ct =
|
||||
RadixCiphertext::from_blocks(vec![did_not_have_enough_funds.0]);
|
||||
|
||||
let something_not_ok_ct =
|
||||
bitor_executor.execute((&did_not_have_enough_funds_ct, &did_not_have_enough_space_ct));
|
||||
let something_not_ok = BooleanBlock(something_not_ok_ct.blocks.first().unwrap().clone());
|
||||
|
||||
let new_from_amount =
|
||||
if_then_else_executor.execute((&something_not_ok, &from_amount, &new_from));
|
||||
let new_to_amount = if_then_else_executor.execute((&something_not_ok, &to_amount, &new_to));
|
||||
|
||||
let decrypted_new_from_amount: u64 = cks.decrypt(&new_from_amount);
|
||||
let decrypted_new_to_amount: u64 = cks.decrypt(&new_to_amount);
|
||||
let decrypted_something_not_ok: bool = cks.decrypt_bool(&something_not_ok);
|
||||
|
||||
let (expected_new_from, expected_did_not_have_enough_funds) =
|
||||
clear_from_amount.overflowing_sub(clear_amount);
|
||||
let (expected_new_to, expected_did_not_have_enough_space) =
|
||||
clear_to_amount.overflowing_add(clear_amount);
|
||||
|
||||
let expected_something_not_ok =
|
||||
expected_did_not_have_enough_funds | expected_did_not_have_enough_space;
|
||||
let expected_new_to_amount = if expected_something_not_ok {
|
||||
clear_to_amount
|
||||
} else {
|
||||
expected_new_to
|
||||
};
|
||||
let expected_new_from_amount = if expected_something_not_ok {
|
||||
clear_from_amount
|
||||
} else {
|
||||
expected_new_from
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
decrypted_did_not_have_enough_funds, expected_did_not_have_enough_funds,
|
||||
"Invalid erc20 result on enough funds: original from amount: {clear_from_amount}, amount: {clear_amount}, to amount: {clear_to_amount}."
|
||||
);
|
||||
assert_eq!(
|
||||
decrypted_did_not_have_enough_space, expected_did_not_have_enough_space,
|
||||
"Invalid erc20 result on enough space: amount: {clear_amount}, to amount: {clear_to_amount}."
|
||||
);
|
||||
assert_eq!(
|
||||
decrypted_something_not_ok, expected_something_not_ok,
|
||||
"Invalid erc20 result on something nok: original from amount: {clear_from_amount}, amount: {clear_amount}, to amount: {clear_to_amount}."
|
||||
);
|
||||
assert_eq!(
|
||||
decrypted_new_from_amount, expected_new_from_amount,
|
||||
"Invalid erc20 result on from amount: original from amount: {clear_from_amount}, amount: {clear_amount}, to amount: {clear_to_amount}, expected new from amount: {expected_new_from_amount}."
|
||||
);
|
||||
assert_eq!(
|
||||
decrypted_new_to_amount, expected_new_to_amount,
|
||||
"Invalid erc20 result on to amount."
|
||||
);
|
||||
|
||||
// Determinism check
|
||||
let (new_from_1, did_not_have_enough_funds_1) =
|
||||
overflowing_sub_executor.execute((&from_amount, &amount));
|
||||
let (new_to_1, did_not_have_enough_space_1) =
|
||||
overflowing_add_executor.execute((&to_amount, &amount));
|
||||
let did_not_have_enough_space_ct_1 =
|
||||
RadixCiphertext::from_blocks(vec![did_not_have_enough_space_1.0]);
|
||||
let did_not_have_enough_funds_ct_1 =
|
||||
RadixCiphertext::from_blocks(vec![did_not_have_enough_funds_1.0]);
|
||||
|
||||
let something_not_ok_ct_1 = bitor_executor.execute((
|
||||
&did_not_have_enough_funds_ct_1,
|
||||
&did_not_have_enough_space_ct_1,
|
||||
));
|
||||
let something_not_ok_1 =
|
||||
BooleanBlock(something_not_ok_ct_1.blocks.first().unwrap().clone());
|
||||
|
||||
let new_from_amount_1 =
|
||||
if_then_else_executor.execute((&something_not_ok_1, &from_amount, &new_from_1));
|
||||
let new_to_amount_1 =
|
||||
if_then_else_executor.execute((&something_not_ok_1, &to_amount, &new_to_1));
|
||||
assert_eq!(
|
||||
new_from_amount, new_from_amount_1,
|
||||
"Determinism check failed on erc20 from amount"
|
||||
);
|
||||
assert_eq!(
|
||||
new_to_amount, new_to_amount_1,
|
||||
"Determinism check failed on erc20 to amount"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn whitepaper_erc20_test<P, T1, T2, T3, T4>(
|
||||
param: P,
|
||||
mut ge_executor: T1,
|
||||
mut add_executor: T2,
|
||||
mut if_then_else_executor: T3,
|
||||
mut sub_executor: T4,
|
||||
) where
|
||||
P: Into<PBSParameters>,
|
||||
T1: for<'a> FunctionExecutor<(&'a RadixCiphertext, &'a RadixCiphertext), BooleanBlock>,
|
||||
T2: for<'a> FunctionExecutor<(&'a RadixCiphertext, &'a RadixCiphertext), RadixCiphertext>,
|
||||
T3: for<'a> FunctionExecutor<
|
||||
(&'a BooleanBlock, &'a RadixCiphertext, &'a RadixCiphertext),
|
||||
RadixCiphertext,
|
||||
>,
|
||||
T4: for<'a> FunctionExecutor<(&'a RadixCiphertext, &'a RadixCiphertext), RadixCiphertext>,
|
||||
{
|
||||
let param = param.into();
|
||||
let (cks, mut sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
|
||||
|
||||
sks.set_deterministic_pbs_execution(true);
|
||||
let sks = Arc::new(sks);
|
||||
let cks = RadixClientKey::from((cks, NB_CTXT_LONG_RUN));
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
ge_executor.setup(&cks, sks.clone());
|
||||
add_executor.setup(&cks, sks.clone());
|
||||
if_then_else_executor.setup(&cks, sks.clone());
|
||||
sub_executor.setup(&cks, sks);
|
||||
|
||||
for _ in 0..NB_TESTS_LONG_RUN {
|
||||
let clear_from_amount = rng.gen::<u64>();
|
||||
let clear_to_amount = rng.gen::<u64>();
|
||||
let clear_amount = rng.gen::<u64>();
|
||||
|
||||
let from_amount = cks.encrypt(clear_from_amount);
|
||||
let to_amount = cks.encrypt(clear_to_amount);
|
||||
let amount = cks.encrypt(clear_amount);
|
||||
|
||||
let has_enough_funds = ge_executor.execute((&from_amount, &amount));
|
||||
|
||||
let mut new_to_amount = add_executor.execute((&to_amount, &amount));
|
||||
new_to_amount =
|
||||
if_then_else_executor.execute((&has_enough_funds, &new_to_amount, &to_amount));
|
||||
|
||||
let mut new_from_amount = sub_executor.execute((&from_amount, &amount));
|
||||
new_from_amount =
|
||||
if_then_else_executor.execute((&has_enough_funds, &new_from_amount, &from_amount));
|
||||
|
||||
let decrypted_new_from_amount: u64 = cks.decrypt(&new_from_amount);
|
||||
let decrypted_new_to_amount: u64 = cks.decrypt(&new_to_amount);
|
||||
|
||||
let expected_new_from_amount = if clear_from_amount >= clear_amount {
|
||||
clear_from_amount - clear_amount
|
||||
} else {
|
||||
clear_from_amount
|
||||
};
|
||||
let expected_new_to_amount = if clear_from_amount >= clear_amount {
|
||||
clear_to_amount + clear_amount
|
||||
} else {
|
||||
clear_to_amount
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
decrypted_new_from_amount, expected_new_from_amount,
|
||||
"Invalid erc20 result on from amount: original from amount: {clear_from_amount}, amount: {clear_amount}, to amount: {clear_to_amount}, expected new from amount: {expected_new_from_amount}."
|
||||
);
|
||||
assert_eq!(
|
||||
decrypted_new_to_amount, expected_new_to_amount,
|
||||
"Invalid erc20 result on to amount."
|
||||
);
|
||||
|
||||
// Determinism check
|
||||
let has_enough_funds_1 = ge_executor.execute((&from_amount, &amount));
|
||||
|
||||
let mut new_to_amount_1 = add_executor.execute((&to_amount, &amount));
|
||||
new_to_amount_1 =
|
||||
if_then_else_executor.execute((&has_enough_funds_1, &new_to_amount_1, &to_amount));
|
||||
|
||||
let mut new_from_amount_1 = sub_executor.execute((&from_amount, &amount));
|
||||
new_from_amount_1 =
|
||||
if_then_else_executor.execute((&has_enough_funds_1, &new_from_amount_1, &from_amount));
|
||||
|
||||
assert_eq!(
|
||||
new_from_amount, new_from_amount_1,
|
||||
"Determinism check failed on erc20 from amount"
|
||||
);
|
||||
assert_eq!(
|
||||
new_to_amount, new_to_amount_1,
|
||||
"Determinism check failed on erc20 to amount"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn no_cmux_erc20_test<P, T1, T2, T3, T4>(
|
||||
param: P,
|
||||
mut ge_executor: T1,
|
||||
mut mul_executor: T2,
|
||||
mut add_executor: T3,
|
||||
mut sub_executor: T4,
|
||||
) where
|
||||
P: Into<PBSParameters>,
|
||||
T1: for<'a> FunctionExecutor<(&'a RadixCiphertext, &'a RadixCiphertext), BooleanBlock>,
|
||||
T2: for<'a> FunctionExecutor<(&'a RadixCiphertext, &'a RadixCiphertext), RadixCiphertext>,
|
||||
T3: for<'a> FunctionExecutor<(&'a RadixCiphertext, &'a RadixCiphertext), RadixCiphertext>,
|
||||
T4: for<'a> FunctionExecutor<(&'a RadixCiphertext, &'a RadixCiphertext), RadixCiphertext>,
|
||||
{
|
||||
let param = param.into();
|
||||
let (cks, mut sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
|
||||
|
||||
sks.set_deterministic_pbs_execution(true);
|
||||
let sks = Arc::new(sks);
|
||||
let cks = RadixClientKey::from((cks, NB_CTXT_LONG_RUN));
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
ge_executor.setup(&cks, sks.clone());
|
||||
mul_executor.setup(&cks, sks.clone());
|
||||
add_executor.setup(&cks, sks.clone());
|
||||
sub_executor.setup(&cks, sks);
|
||||
|
||||
for _ in 0..NB_TESTS_LONG_RUN {
|
||||
let clear_from_amount = rng.gen::<u64>();
|
||||
let clear_to_amount = rng.gen::<u64>();
|
||||
let clear_amount = rng.gen::<u64>();
|
||||
|
||||
let from_amount = cks.encrypt(clear_from_amount);
|
||||
let to_amount = cks.encrypt(clear_to_amount);
|
||||
let amount = cks.encrypt(clear_amount);
|
||||
|
||||
let has_enough_funds = ge_executor.execute((&from_amount, &amount));
|
||||
let has_enough_funds_ct = RadixCiphertext::from_blocks(vec![has_enough_funds.0]);
|
||||
let new_amount = mul_executor.execute((&amount, &has_enough_funds_ct));
|
||||
let new_to_amount = add_executor.execute((&to_amount, &new_amount));
|
||||
let new_from_amount = sub_executor.execute((&from_amount, &new_amount));
|
||||
|
||||
let decrypted_new_from_amount: u64 = cks.decrypt(&new_from_amount);
|
||||
let decrypted_new_to_amount: u64 = cks.decrypt(&new_to_amount);
|
||||
|
||||
let expected_new_from_amount = if clear_from_amount >= clear_amount {
|
||||
clear_from_amount - clear_amount
|
||||
} else {
|
||||
clear_from_amount
|
||||
};
|
||||
let expected_new_to_amount = if clear_from_amount >= clear_amount {
|
||||
clear_to_amount + clear_amount
|
||||
} else {
|
||||
clear_to_amount
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
decrypted_new_from_amount, expected_new_from_amount,
|
||||
"Invalid erc20 result on from amount: original from amount: {clear_from_amount}, amount: {clear_amount}, to amount: {clear_to_amount}, expected new from amount: {expected_new_from_amount}."
|
||||
);
|
||||
assert_eq!(
|
||||
decrypted_new_to_amount, expected_new_to_amount,
|
||||
"Invalid erc20 result on to amount."
|
||||
);
|
||||
|
||||
// Determinism check
|
||||
let has_enough_funds_1 = ge_executor.execute((&from_amount, &amount));
|
||||
let has_enough_funds_ct_1 = RadixCiphertext::from_blocks(vec![has_enough_funds_1.0]);
|
||||
let new_amount_1 = mul_executor.execute((&amount, &has_enough_funds_ct_1));
|
||||
let new_to_amount_1 = add_executor.execute((&to_amount, &new_amount_1));
|
||||
let new_from_amount_1 = sub_executor.execute((&from_amount, &new_amount_1));
|
||||
|
||||
assert_eq!(
|
||||
new_from_amount, new_from_amount_1,
|
||||
"Determinism check failed on no cmux erc20 from amount"
|
||||
);
|
||||
assert_eq!(
|
||||
new_to_amount, new_to_amount_1,
|
||||
"Determinism check failed on no cmux erc20 to amount"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn overflow_erc20_test<P, T1, T2, T3, T4, T5>(
|
||||
param: P,
|
||||
mut overflowing_sub_executor: T1,
|
||||
mut if_then_else_executor: T2,
|
||||
mut not_executor: T3,
|
||||
mut mul_executor: T4,
|
||||
mut add_executor: T5,
|
||||
) where
|
||||
P: Into<PBSParameters>,
|
||||
T1: for<'a> FunctionExecutor<
|
||||
(&'a RadixCiphertext, &'a RadixCiphertext),
|
||||
(RadixCiphertext, BooleanBlock),
|
||||
>,
|
||||
T2: for<'a> FunctionExecutor<
|
||||
(&'a BooleanBlock, &'a RadixCiphertext, &'a RadixCiphertext),
|
||||
RadixCiphertext,
|
||||
>,
|
||||
T3: for<'a> FunctionExecutor<&'a BooleanBlock, BooleanBlock>,
|
||||
T4: for<'a> FunctionExecutor<(&'a RadixCiphertext, &'a RadixCiphertext), RadixCiphertext>,
|
||||
T5: for<'a> FunctionExecutor<(&'a RadixCiphertext, &'a RadixCiphertext), RadixCiphertext>,
|
||||
{
|
||||
let param = param.into();
|
||||
let (cks, mut sks) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix);
|
||||
|
||||
sks.set_deterministic_pbs_execution(true);
|
||||
let sks = Arc::new(sks);
|
||||
let cks = RadixClientKey::from((cks, NB_CTXT_LONG_RUN));
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
overflowing_sub_executor.setup(&cks, sks.clone());
|
||||
if_then_else_executor.setup(&cks, sks.clone());
|
||||
not_executor.setup(&cks, sks.clone());
|
||||
mul_executor.setup(&cks, sks.clone());
|
||||
add_executor.setup(&cks, sks);
|
||||
|
||||
for _ in 0..NB_TESTS_LONG_RUN {
|
||||
let clear_from_amount = rng.gen::<u64>();
|
||||
let clear_to_amount = rng.gen::<u64>();
|
||||
let clear_amount = rng.gen::<u64>();
|
||||
|
||||
let from_amount = cks.encrypt(clear_from_amount);
|
||||
let to_amount = cks.encrypt(clear_to_amount);
|
||||
let amount = cks.encrypt(clear_amount);
|
||||
|
||||
let (new_from, did_not_have_enough_funds) =
|
||||
overflowing_sub_executor.execute((&from_amount, &amount));
|
||||
|
||||
let new_from_amount =
|
||||
if_then_else_executor.execute((&did_not_have_enough_funds, &from_amount, &new_from));
|
||||
|
||||
let had_enough_funds = not_executor.execute(&did_not_have_enough_funds);
|
||||
let had_enough_funds_ct = RadixCiphertext::from_blocks(vec![had_enough_funds.0]);
|
||||
let new_amount = mul_executor.execute((&amount, &had_enough_funds_ct));
|
||||
let new_to_amount = add_executor.execute((&to_amount, &new_amount));
|
||||
let decrypted_did_not_have_enough_funds: bool =
|
||||
cks.decrypt_bool(&did_not_have_enough_funds);
|
||||
|
||||
let decrypted_new_from_amount: u64 = cks.decrypt(&new_from_amount);
|
||||
let decrypted_new_to_amount: u64 = cks.decrypt(&new_to_amount);
|
||||
|
||||
let (expected_new_from, expected_did_not_have_enough_funds) =
|
||||
clear_from_amount.overflowing_sub(clear_amount);
|
||||
|
||||
let expected_new_from_amount = if expected_did_not_have_enough_funds {
|
||||
clear_from_amount
|
||||
} else {
|
||||
expected_new_from
|
||||
};
|
||||
let expected_had_enough_funds = !expected_did_not_have_enough_funds;
|
||||
let expected_new_amount = if expected_had_enough_funds {
|
||||
clear_amount
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let expected_new_to_amount = clear_to_amount + expected_new_amount;
|
||||
|
||||
assert_eq!(
|
||||
decrypted_did_not_have_enough_funds, expected_did_not_have_enough_funds,
|
||||
"Invalid erc20 result on enough funds: original from amount: {clear_from_amount}, amount: {clear_amount}, to amount: {clear_to_amount}."
|
||||
);
|
||||
assert_eq!(
|
||||
decrypted_new_from_amount, expected_new_from_amount,
|
||||
"Invalid erc20 result on from amount: original from amount: {clear_from_amount}, amount: {clear_amount}, to amount: {clear_to_amount}, expected new from amount: {expected_new_from_amount}."
|
||||
);
|
||||
assert_eq!(
|
||||
decrypted_new_to_amount, expected_new_to_amount,
|
||||
"Invalid erc20 result on to amount."
|
||||
);
|
||||
|
||||
// Determinism check
|
||||
let (new_from_1, did_not_have_enough_funds_1) =
|
||||
overflowing_sub_executor.execute((&from_amount, &amount));
|
||||
|
||||
let new_from_amount_1 = if_then_else_executor.execute((
|
||||
&did_not_have_enough_funds_1,
|
||||
&from_amount,
|
||||
&new_from_1,
|
||||
));
|
||||
|
||||
let had_enough_funds_1 = not_executor.execute(&did_not_have_enough_funds_1);
|
||||
let had_enough_funds_ct_1 = RadixCiphertext::from_blocks(vec![had_enough_funds_1.0]);
|
||||
let new_amount_1 = mul_executor.execute((&amount, &had_enough_funds_ct_1));
|
||||
let new_to_amount_1 = add_executor.execute((&to_amount, &new_amount_1));
|
||||
assert_eq!(
|
||||
new_from_amount, new_from_amount_1,
|
||||
"Determinism check failed on erc20 from amount"
|
||||
);
|
||||
assert_eq!(
|
||||
new_to_amount, new_to_amount_1,
|
||||
"Determinism check failed on erc20 to amount"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -654,6 +654,21 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// Bitnot
|
||||
impl<'a, F> FunctionExecutor<&'a BooleanBlock, BooleanBlock> for CpuFunctionExecutor<F>
|
||||
where
|
||||
F: Fn(&ServerKey, &BooleanBlock) -> BooleanBlock,
|
||||
{
|
||||
fn setup(&mut self, _cks: &RadixClientKey, sks: Arc<ServerKey>) {
|
||||
self.sks = Some(sks);
|
||||
}
|
||||
|
||||
fn execute(&mut self, input: &'a BooleanBlock) -> BooleanBlock {
|
||||
let sks = self.sks.as_ref().expect("setup was not properly called");
|
||||
(self.func)(sks, input)
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Unchecked Tests
|
||||
//=============================================================================
|
||||
|
||||
Reference in New Issue
Block a user