inst/tinytest/test_binfhe_eval_sign.R

## Functional bootstrapping: extract MSB (sign bit) of a large-Q LWE ciphertext.
## @openfhe-python: binfhe/eval-sign.py [FULL]
library(openfhe.R)

## One STD128 bootstrap-key generation plus eight functional bootstraps —
## skip on CRAN for time, 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)")

log_q <- 17L
ctx <- bin_fhe_context(
  paramset = BinFHEParamSet$STD128,
  method = BinFHEMethod$GINX,
  arb_func = FALSE,
  log_q = log_q,
  n = 0L,
  time_optimization = FALSE)

Q <- bitwShiftL(1L, log_q)             # 1 << 17 = 131072
q <- 4096
factor <- bitwShiftL(1L, log_q - as.integer(log2(q)))   # 1 << 5 = 32
p <- get_max_plaintext_space(ctx) * factor

sk <- bin_key_gen(ctx)
bin_bt_key_gen(ctx, sk)

# Mirror eval-sign.py: 8 inputs centered on p/2; expected sign is 1 iff i >= 3.
for (i in 0:7) {
  msg <- p %/% 2 + i - 3
  ct <- bin_encrypt(ctx, sk, msg,
                    output = BinFHEOutput$LARGE_DIM, p = p, mod = Q)
  ct_sign <- eval_sign(ctx, ct)
  result <- bin_decrypt(ctx, sk, ct_sign, p = 2L)
  expect_equal(result, as.integer(i >= 3),
    info = sprintf("i=%d msg=%g expected=%d", i, msg, as.integer(i >= 3)))
}

## Release the bootstrapping keys now: R's collector does not see the
## memory behind a context, so the keys would otherwise stay until a
## collection happens to run (notes/discoveries/D043).
bin_clear_bt_keys(ctx)

Try the openfhe.R package in your browser

Any scripts or data that you put into this service are public.

openfhe.R documentation built on Nov. 13, 2026, 5:07 p.m.