Nothing
## @openfhe-python: src/lib/bindings.cpp (IntBoot + IntMPBoot families) [PARTIAL]
## NONE for KeySwitchDown [R-ONLY]
##
## KeySwitchDown + IntBoot 4-function
## family + IntMPBoot 6-function family.
##
## Full end-to-end validation of the interactive bootstrap
## protocols, with numeric checks, is in
## test_example_interactive_bootstrapping.R and the two
## test_example_tckks_interactive_mp_bootstrapping*.R files. This file
## predates the `clone()` / `set_elements()` bindings those use, and
## verifies:
## - all 11 bindings dispatch cleanly and return the expected
## wrapper type;
## - the IntBoot single-party 4-method pipeline can be
## chained end-to-end without throwing (numeric fidelity
## of the refreshed ciphertext is checked in the example
## files named above);
## - `key_switch_down()` accepts an ext-rotated ciphertext
## (which lives in the P*Q basis) and returns a valid
## Ciphertext in the Q basis;
## - `int_mp_boot_random_element_gen()` dispatches on
## PublicKey vs Ciphertext correctly.
library(openfhe.R)
## Interactive (multi-party) bootstrapping — skip on CRAN for time/memory,
## but run everywhere else: on CI (GitHub Actions sets CI=true) and locally
## via tinytest::test_all() (sets TT_AT_HOME).
if (!at_home() && Sys.getenv("CI") != "true")
exit_file("skipped on CRAN: heavy bootstrapping (runs on CI and at_home)")
# ── CKKS setup with FHE + MULTIPARTY + ADVANCEDSHE ─────
cc <- fhe_context("CKKS",
multiplicative_depth = 6L,
scaling_mod_size = 50L,
first_mod_size = 60L,
ring_dim = 4096L,
security_level = SecurityLevel$HEStd_NotSet,
batch_size = 8L,
features = c(Feature$ADVANCEDSHE, Feature$FHE,
Feature$MULTIPARTY)
)
kp1 <- key_gen(cc, eval_mult = TRUE, rotations = c(1L, 2L))
kp2 <- multiparty_key_gen(cc, kp1@public)
x <- c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8)
pt <- make_ckks_packed_plaintext(cc, x)
## Encrypt under the joint (party 2) public key for the
## multi-party flow. Also encrypt a parallel copy under kp1's
## public key — kp1 has the rotation keys registered (via
## key_gen(cc, rotations = ...)) so the eval_fast_rotation_ext
## + key_switch_down sub-test can find an eval-key map for its
## key tag.
ct <- encrypt(kp2@public, pt, cc = cc)
ct_rot <- encrypt(kp1@public, pt, cc = cc)
# ── IntBoot single-party family: 4 bindings dispatch ────
## Each of the four IntBoot methods produces a new Ciphertext;
## chaining them mirrors the upstream
## UnitTestInteractiveBootstrap.cpp pipeline line 496-506.
ct_adjusted <- int_boot_adjust_scale(ct)
expect_true(S7::S7_inherits(ct_adjusted, Ciphertext))
ct_masked <- int_boot_decrypt(kp1@secret, ct_adjusted)
expect_true(S7::S7_inherits(ct_masked, Ciphertext))
ct_encrypted <- int_boot_encrypt(kp2@public, ct_masked)
expect_true(S7::S7_inherits(ct_encrypted, Ciphertext))
ct_added <- int_boot_add(ct_encrypted, ct_masked)
expect_true(S7::S7_inherits(ct_added, Ciphertext))
# ── KeySwitchDown on an ext-rotated ciphertext ──────────
## eval_fast_rotation_ext lands a ciphertext in the extended
## P*Q basis; key_switch_down brings it back to Q. The full
## numeric validation of the ext + key_switch_down pipeline
## is out of scope here — this test verifies the binding
## dispatches and returns a Ciphertext in the correct shape.
precomp <- eval_fast_rotation_precompute(ct_rot)
ct_ext <- eval_fast_rotation_ext(ct_rot, index = 1L, precomp = precomp,
add_first = TRUE)
expect_true(S7::S7_inherits(ct_ext, Ciphertext))
ct_down <- key_switch_down(ct_ext)
expect_true(S7::S7_inherits(ct_down, Ciphertext))
# ── IntMPBoot family: all 6 bindings dispatch ───────────
## int_mp_boot_adjust_scale: single arg, returns Ciphertext.
ct_mp_adjusted <- int_mp_boot_adjust_scale(ct)
expect_true(S7::S7_inherits(ct_mp_adjusted, Ciphertext))
## int_mp_boot_random_element_gen: PublicKey overload.
a_from_pk <- int_mp_boot_random_element_gen(cc, kp1@public)
expect_true(S7::S7_inherits(a_from_pk, Ciphertext))
## int_mp_boot_random_element_gen: Ciphertext overload.
a_from_ct <- int_mp_boot_random_element_gen(cc, ct)
expect_true(S7::S7_inherits(a_from_ct, Ciphertext))
## int_mp_boot_random_element_gen: type error on wrong source.
expect_error(int_mp_boot_random_element_gen(cc, "not a key"),
pattern = "PublicKey.*Ciphertext")
## int_mp_boot_decrypt: takes (sk, ct, a) and returns a list
## of two Ciphertexts (the shares pair).
shares1 <- int_mp_boot_decrypt(kp1@secret, ct_mp_adjusted, a_from_pk)
expect_true(is.list(shares1))
expect_equal(length(shares1), 2L)
for (s in shares1) expect_true(S7::S7_inherits(s, Ciphertext))
shares2 <- int_mp_boot_decrypt(kp2@secret, ct_mp_adjusted, a_from_pk)
expect_true(is.list(shares2))
expect_equal(length(shares2), 2L)
## int_mp_boot_add: aggregate the two parties' shares.
agg <- int_mp_boot_add(cc, list(shares1, shares2))
expect_true(is.list(agg))
for (a in agg) expect_true(S7::S7_inherits(a, Ciphertext))
## int_mp_boot_add: type error on non-list.
expect_error(int_mp_boot_add(cc, "not a list"),
pattern = "shares_pair_list.*list")
## int_mp_boot_encrypt: final step, returns the refreshed ct.
ct_refreshed <- int_mp_boot_encrypt(kp1@public, agg, a_from_pk,
ct_mp_adjusted)
expect_true(S7::S7_inherits(ct_refreshed, Ciphertext))
## int_mp_boot_encrypt: type error on non-list shares_pair.
expect_error(int_mp_boot_encrypt(kp1@public, "not a list",
a_from_pk, ct_mp_adjusted),
pattern = "shares_pair.*list")
# ── Formals shape assertions ────────────────────────────
expect_identical(names(formals(key_switch_down)), "ct")
expect_identical(names(formals(int_boot_decrypt)), c("sk", "ct"))
expect_identical(names(formals(int_boot_encrypt)), c("pk", "ct"))
expect_identical(names(formals(int_boot_add)), c("ct1", "ct2"))
expect_identical(names(formals(int_boot_adjust_scale)), "ct")
expect_identical(names(formals(int_mp_boot_adjust_scale)), "ct")
expect_identical(names(formals(int_mp_boot_random_element_gen)),
c("cc", "source"))
expect_identical(names(formals(int_mp_boot_decrypt)),
c("sk", "ct", "a"))
expect_identical(names(formals(int_mp_boot_add)),
c("cc", "shares_pair_list"))
expect_identical(names(formals(int_mp_boot_encrypt)),
c("pk", "shares_pair", "a", "ct"))
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.