Commit c6c9d2f5 authored by Hoang Gia NGUYEN's avatar Hoang Gia NGUYEN
Browse files

first commit

parent fe2d6195
Pipeline #60 failed with stages
in 0 seconds
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT license. -->
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
</resources>
<!-- Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT license. -->
<resources>
<string name="app_name">SEAL</string>
</resources>
<!-- Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT license. -->
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT license.
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT license.
#Mon Apr 06 10:08:19 PDT 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
include ':app'
rootProject.name='SEAL'
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT license.
# Exports target SEAL::seal
#
# Creates variables:
# SEAL_FOUND : If a static Microsoft SEAL library was found
# SEAL_SHARED_FOUND : If a shared Microsoft SEAL library was found
# SEAL_C_FOUND : If a Microsoft SEAL C export library was found
# SEAL_VERSION : The full version number
# SEAL_VERSION_MAJOR : The major version number
# SEAL_VERSION_MINOR : The minor version number
# SEAL_VERSION_PATCH : The patch version number
# SEAL_DEBUG : Set to non-zero value if library is compiled with extra debugging code (very slow!)
# SEAL_USE_CXX17 : Set to non-zero value if library is compiled as C++17 instead of C++14
# SEAL_ENFORCE_HE_STD_SECURITY : Set to non-zero value if library is compiled to enforce at least
# a 128-bit security level based on HomomorphicEncryption.org security estimates
# SEAL_USE_MSGSL : Set to non-zero value if library is compiled with Microsoft GSL support
# SEAL_USE_ZLIB : Set to non-zero value if library is compiled with zlib support
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
macro(warning_when_not_quiet msg)
if(NOT SEAL_FIND_QUIETLY)
message(WARNING ${msg})
endif()
endmacro()
macro(status_when_not_quiet msg)
if(NOT SEAL_FIND_QUIETLY)
message(STATUS ${msg})
endif()
endmacro()
macro(find_seal_dependency dep)
find_dependency(${dep})
if(NOT ${dep}_FOUND)
warning_when_not_quiet("Could not find dependency `${dep}` required by this configuration")
set(SEAL_FOUND FALSE)
return()
endif()
endmacro()
set(SEAL_FOUND FALSE)
set(SEAL_SHARED_FOUND FALSE)
set(SEAL_C_FOUND FALSE)
set(SEAL_VERSION @SEAL_VERSION@)
set(SEAL_VERSION_MAJOR @SEAL_VERSION_MAJOR@)
set(SEAL_VERSION_MINOR @SEAL_VERSION_MINOR@)
set(SEAL_VERSION_PATCH @SEAL_VERSION_PATCH@)
set(SEAL_BUILD_TYPE @CMAKE_BUILD_TYPE@)
set(SEAL_DEBUG @SEAL_DEBUG@)
set(SEAL_USE_CXX17 @SEAL_USE_CXX17@)
set(SEAL_ENFORCE_HE_STD_SECURITY @SEAL_ENFORCE_HE_STD_SECURITY@)
set(SEAL_USE_MSGSL @SEAL_USE_MSGSL@)
set(SEAL_USE_ZLIB @SEAL_USE_ZLIB@)
# Add the current directory to the module search path
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_seal_dependency(Threads)
include(${CMAKE_CURRENT_LIST_DIR}/SEALTargets.cmake)
if(TARGET SEAL::seal)
set(SEAL_FOUND TRUE)
endif()
if(TARGET SEAL::seal_shared)
set(SEAL_SHARED_FOUND TRUE)
endif()
if(TARGET SEAL::sealc)
set(SEAL_C_FOUND TRUE)
endif()
if(SEAL_FOUND)
status_when_not_quiet("Microsoft SEAL -> Version ${SEAL_VERSION} detected")
if(SEAL_DEBUG)
status_when_not_quiet("Performance warning: Microsoft SEAL compiled in debug mode")
endif()
set(SEAL_TARGETS_AVAILABLE "Microsoft SEAL -> Targets available: SEAL::seal")
if(SEAL_SHARED_FOUND)
string(APPEND SEAL_TARGETS_AVAILABLE ", SEAL::seal_shared")
endif()
if(SEAL_C_FOUND)
string(APPEND SEAL_TARGETS_AVAILABLE ", SEAL::sealc")
endif()
status_when_not_quiet(${SEAL_TARGETS_AVAILABLE})
else()
warning_when_not_quiet("Microsoft SEAL -> NOT FOUND")
endif()
This diff is collapsed.
This diff is collapsed.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using Microsoft.Research.SEAL;
namespace SEALNetExamples
{
partial class Examples
{
private static void ExampleLevels()
{
Utilities.PrintExampleBanner("Example: Levels");
/*
In this examples we describe the concept of `levels' in BFV and CKKS and the
related objects that represent them in Microsoft SEAL.
In Microsoft SEAL a set of encryption parameters (excluding the random number
generator) is identified uniquely by a 256-bit hash of the parameters. This
hash is called the `ParmsId' and can be easily accessed and printed at any
time. The hash will change as soon as any of the parameters is changed.
When a SEALContext is created from a given EncryptionParameters instance,
Microsoft SEAL automatically creates a so-called `modulus switching chain',
which is a chain of other encryption parameters derived from the original set.
The parameters in the modulus switching chain are the same as the original
parameters with the exception that size of the coefficient modulus is
decreasing going down the chain. More precisely, each parameter set in the
chain attempts to remove the last coefficient modulus prime from the
previous set; this continues until the parameter set is no longer valid
(e.g., PlainModulus is larger than the remaining CoeffModulus). It is easy
to walk through the chain and access all the parameter sets. Additionally,
each parameter set in the chain has a `chain index' that indicates its
position in the chain so that the last set has index 0. We say that a set
of encryption parameters, or an object carrying those encryption parameters,
is at a higher level in the chain than another set of parameters if its the
chain index is bigger, i.e., it is earlier in the chain.
Each set of parameters in the chain involves unique pre-computations performed
when the SEALContext is created, and stored in a SEALContext.ContextData
object. The chain is basically a linked list of SEALContext.ContextData
objects, and can easily be accessed through the SEALContext at any time. Each
node can be identified by the ParmsId of its specific encryption parameters
(PolyModulusDegree remains the same but CoeffModulus varies).
*/
using EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV);
ulong polyModulusDegree = 8192;
parms.PolyModulusDegree = polyModulusDegree;
/*
In this example we use a custom CoeffModulus, consisting of 5 primes of
sizes 50, 30, 30, 50, and 50 bits. Note that this is still OK according to
the explanation in `1_BFV_Basics.cs'. Indeed,
CoeffModulus.MaxBitCount(polyModulusDegree)
returns 218 (greater than 50+30+30+50+50=210).
Due to the modulus switching chain, the order of the 5 primes is significant.
The last prime has a special meaning and we call it the `special prime'. Thus,
the first parameter set in the modulus switching chain is the only one that
involves the special prime. All key objects, such as SecretKey, are created
at this highest level. All data objects, such as Ciphertext, can be only at
lower levels. The special modulus should be as large as the largest of the
other primes in the CoeffModulus, although this is not a strict requirement.
special prime +---------+
|
v
CoeffModulus: { 50, 30, 30, 50, 50 } +---+ Level 4 (all keys; `key level')
|
|
CoeffModulus: { 50, 30, 30, 50 } +---+ Level 3 (highest `data level')
|
|
CoeffModulus: { 50, 30, 30 } +---+ Level 2
|
|
CoeffModulus: { 50, 30 } +---+ Level 1
|
|
CoeffModulus: { 50 } +---+ Level 0 (lowest level)
*/
parms.CoeffModulus = CoeffModulus.Create(
polyModulusDegree, new int[] { 50, 30, 30, 50, 50 });
/*
In this example the PlainModulus does not play much of a role; we choose
some reasonable value.
*/
parms.PlainModulus = PlainModulus.Batching(polyModulusDegree, 20);
using SEALContext context = new SEALContext(parms);
Utilities.PrintParameters(context);
/*
There are convenience method for accessing the SEALContext.ContextData for
some of the most important levels:
SEALContext.KeyContextData: access to key level ContextData
SEALContext.FirstContextData: access to highest data level ContextData
SEALContext.LastContextData: access to lowest level ContextData
We iterate over the chain and print the ParmsId for each set of parameters.
*/
Console.WriteLine();
Utilities.PrintLine();
Console.WriteLine("Print the modulus switching chain.");
/*
First print the key level parameter information.
*/
SEALContext.ContextData contextData = context.KeyContextData;
Console.WriteLine("----> Level (chain index): {0} ...... KeyContextData",
contextData.ChainIndex);
Console.WriteLine($" ParmsId: {contextData.ParmsId}");
Console.Write(" CoeffModulus primes: ");
foreach (Modulus prime in contextData.Parms.CoeffModulus)
{
Console.Write($"{Utilities.ULongToString(prime.Value)} ");
}
Console.WriteLine();
Console.WriteLine("\\");
Console.Write(" \\--> ");
/*
Next iterate over the remaining (data) levels.
*/
contextData = context.FirstContextData;
while (null != contextData)
{
Console.Write($"Level (chain index): {contextData.ChainIndex}");
if (contextData.ParmsId.Equals(context.FirstParmsId))
{
Console.WriteLine(" ...... FirstContextData");
}
else if (contextData.ParmsId.Equals(context.LastParmsId))
{
Console.WriteLine(" ...... LastContextData");
}
else
{
Console.WriteLine();
}
Console.WriteLine($" ParmsId: {contextData.ParmsId}");
Console.Write(" CoeffModulus primes: ");
foreach (Modulus prime in contextData.Parms.CoeffModulus)
{
Console.Write($"{Utilities.ULongToString(prime.Value)} ");
}
Console.WriteLine();
Console.WriteLine("\\");
Console.Write(" \\--> ");
/*
Step forward in the chain.
*/
contextData = contextData.NextContextData;
}
Console.WriteLine("End of chain reached");
Console.WriteLine();
/*
We create some keys and check that indeed they appear at the highest level.
*/
using KeyGenerator keygen = new KeyGenerator(context);
using PublicKey publicKey = keygen.PublicKey;
using SecretKey secretKey = keygen.SecretKey;
using RelinKeys relinKeys = keygen.RelinKeysLocal();
/*
In this example we create a local version of the GaloisKeys object using
KeyGenerator.GaloisKeysLocal(). In a production setting where the Galois
keys would need to be communicated to a server, it would be much better to
use KeyGenerator.GaloisKeys(), which outputs a Serializable<GaloisKeys>
object for compressed serialization.
*/
using GaloisKeys galoisKeys = keygen.GaloisKeysLocal();
Utilities.PrintLine();
Console.WriteLine("Print the parameter IDs of generated elements.");
Console.WriteLine($" + publicKey: {publicKey.ParmsId}");
Console.WriteLine($" + secretKey: {secretKey.ParmsId}");
Console.WriteLine($" + relinKeys: {relinKeys.ParmsId}");
Console.WriteLine($" + galoisKeys: {galoisKeys.ParmsId}");
using Encryptor encryptor = new Encryptor(context, publicKey);
using Evaluator evaluator = new Evaluator(context);
using Decryptor decryptor = new Decryptor(context, secretKey);
/*
In the BFV scheme plaintexts do not carry a ParmsId, but ciphertexts do. Note
how the freshly encrypted ciphertext is at the highest data level.
*/
using Plaintext plain = new Plaintext("1x^3 + 2x^2 + 3x^1 + 4");
using Ciphertext encrypted = new Ciphertext();
encryptor.Encrypt(plain, encrypted);
Console.WriteLine($" + plain: {plain.ParmsId} (not set in BFV)");
Console.WriteLine($" + encrypted: {encrypted.ParmsId}");
Console.WriteLine();
/*
`Modulus switching' is a technique of changing the ciphertext parameters down
in the chain. The function Evaluator.ModSwitchToNext always switches to the
next level down the chain, whereas Evaluator.ModSwitchTo switches to a parameter
set down the chain corresponding to a given ParmsId. However, it is impossible
to switch up in the chain.
*/
Utilities.PrintLine();
Console.WriteLine("Perform modulus switching on encrypted and print.");
contextData = context.FirstContextData;
Console.Write("----> ");
while (null != contextData.NextContextData)
{
Console.WriteLine($"Level (chain index): {contextData.ChainIndex}");
Console.WriteLine($" ParmsId of encrypted: {contextData.ParmsId}");
Console.WriteLine(" Noise budget at this level: {0} bits",
decryptor.InvariantNoiseBudget(encrypted));
Console.WriteLine("\\");
Console.Write(" \\--> ");
evaluator.ModSwitchToNextInplace(encrypted);
contextData = contextData.NextContextData;
}
Console.WriteLine($"Level (chain index): {contextData.ChainIndex}");
Console.WriteLine($" ParmsId of encrypted: {contextData.ParmsId}");
Console.WriteLine(" Noise budget at this level: {0} bits",
decryptor.InvariantNoiseBudget(encrypted));
Console.WriteLine("\\");
Console.Write(" \\--> ");
Console.WriteLine("End of chain reached");
Console.WriteLine();
/*
At this point it is hard to see any benefit in doing this: we lost a huge
amount of noise budget (i.e., computational power) at each switch and seemed
to get nothing in return. Decryption still works.
*/
Utilities.PrintLine();
Console.WriteLine("Decrypt still works after modulus switching.");
decryptor.Decrypt(encrypted, plain);
Console.WriteLine($" + Decryption of encrypted: {plain} ...... Correct.");
Console.WriteLine();
/*
However, there is a hidden benefit: the size of the ciphertext depends
linearly on the number of primes in the coefficient modulus. Thus, if there
is no need or intention to perform any further computations on a given
ciphertext, we might as well switch it down to the smallest (last) set of
parameters in the chain before sending it back to the secret key holder for
decryption.
Also the lost noise budget is actually not an issue at all, if we do things
right, as we will see below.
First we recreate the original ciphertext and perform some computations.
*/
Console.WriteLine("Computation is more efficient with modulus switching.");
Utilities.PrintLine();
Console.WriteLine("Compute the eight power.");
encryptor.Encrypt(plain, encrypted);
Console.WriteLine(" + Noise budget fresh: {0} bits",
decryptor.InvariantNoiseBudget(encrypted));
evaluator.SquareInplace(encrypted);
evaluator.RelinearizeInplace(encrypted, relinKeys);
Console.WriteLine(" + Noise budget of the 2nd power: {0} bits",
decryptor.InvariantNoiseBudget(encrypted));
evaluator.SquareInplace(encrypted);
evaluator.RelinearizeInplace(encrypted, relinKeys);
Console.WriteLine(" + Noise budget of the 4th power: {0} bits",
decryptor.InvariantNoiseBudget(encrypted));
/*
Surprisingly, in this case modulus switching has no effect at all on the
noise budget.
*/
evaluator.ModSwitchToNextInplace(encrypted);
Console.WriteLine(" + Noise budget after modulus switching: {0} bits",
decryptor.InvariantNoiseBudget(encrypted));
/*
This means that there is no harm at all in dropping some of the coefficient
modulus after doing enough computations. In some cases one might want to
switch to a lower level slightly earlier, actually sacrificing some of the
noise budget in the process, to gain computational performance from having
smaller parameters. We see from the print-out that the next modulus switch
should be done ideally when the noise budget is down to around 25 bits.
*/
evaluator.SquareInplace(encrypted);
evaluator.RelinearizeInplace(encrypted, relinKeys);
Console.WriteLine(" + Noise budget of the 8th power: {0} bits",
decryptor.InvariantNoiseBudget(encrypted));
evaluator.ModSwitchToNextInplace(encrypted);
Console.WriteLine(" + Noise budget after modulus switching: {0} bits",
decryptor.InvariantNoiseBudget(encrypted));
/*
At this point the ciphertext still decrypts correctly, has very small size,
and the computation was as efficient as possible. Note that the decryptor
can be used to decrypt a ciphertext at any level in the modulus switching
chain.
*/
decryptor.Decrypt(encrypted, plain);
Console.WriteLine(" + Decryption of the 8th power (hexadecimal) ...... Correct.");
Console.WriteLine($" {plain}");
Console.WriteLine();
/*
In BFV modulus switching is not necessary and in some cases the user might
not want to create the modulus switching chain, except for the highest two
levels. This can be done by passing a bool `false' to SEALContext constructor.
*/
using SEALContext context2 = new SEALContext(parms, expandModChain: false);
/*
We can check that indeed the modulus switching chain has been created only
for the highest two levels (key level and highest data level). The following
loop should execute only once.
*/
Console.WriteLine("Optionally disable modulus switching chain expansion.");
Utilities.PrintLine();
Console.WriteLine("Print the modulus switching chain.");
Console.Write("----> ");
for (contextData = context2.KeyContextData; null != contextData;
contextData = contextData.NextContextData)
{
Console.WriteLine($"Level (chain index): {contextData.ChainIndex}");
Console.WriteLine($" ParmsId of encrypted: {contextData.ParmsId}");
Console.Write(" CoeffModulus primes: ");
foreach (Modulus prime in contextData.Parms.CoeffModulus)
{
Console.Write($"{Utilities.ULongToString(prime.Value)} ");
}
Console.WriteLine();
Console.WriteLine("\\");
Console.Write(" \\--> ");
}
Console.WriteLine("End of chain reached");
Console.WriteLine();
/*
It is very important to understand how this example works since in the CKKS
scheme modulus switching has a much more fundamental purpose and the next
examples will be difficult to understand unless these basic properties are
totally clear.
*/
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using System.Collections.Generic;
using Microsoft.Research.SEAL;
namespace SEALNetExamples
{
partial class Examples
{
private static void ExampleCKKSBasics()
{
Utilities.PrintExampleBanner("Example: CKKS Basics");
/*
In this example we demonstrate evaluating a polynomial function
PI*x^3 + 0.4*x + 1
on encrypted floating-point input data x for a set of 4096 equidistant points
in the interval [0, 1]. This example demonstrates many of the main features
of the CKKS scheme, but also the challenges in using it.
We start by setting up the CKKS scheme.
*/
using EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);
/*
We saw in `2_Encoders.cs' that multiplication in CKKS causes scales in
ciphertexts to grow. The scale of any ciphertext must not get too close to
the total size of CoeffModulus, or else the ciphertext simply runs out of
room to store the scaled-up plaintext. The CKKS scheme provides a `rescale'
functionality that can reduce the scale, and stabilize the scale expansion.
Rescaling is a kind of modulus switch operation (recall `3_Levels.cs').
As modulus switching, it removes the last of the primes from CoeffModulus,
but as a side-effect it scales down the ciphertext by the removed prime.
Usually we want to have perfect control over how the scales are changed,
which is why for the CKKS scheme it is more common to use carefully selected
primes for the CoeffModulus.
More precisely, suppose that the scale in a CKKS ciphertext is S, and the
last prime in the current CoeffModulus (for the ciphertext) is P. Rescaling
to the next level changes the scale to S/P, and removes the prime P from the
CoeffModulus, as usual in modulus switching. The number of primes limits
how many rescalings can be done, and thus limits the multiplicative depth of
the computation.
It is possible to choose the initial scale freely. One good strategy can be
to is to set the initial scale S and primes P_i in the CoeffModulus to be
very close to each other. If ciphertexts have scale S before multiplication,
they have scale S^2 after multiplication, and S^2/P_i after rescaling. If all
P_i are close to S, then S^2/P_i is close to S again. This way we stabilize the
scales to be close to S throughout the computation. Generally, for a circuit
of depth D, we need to rescale D times, i.e., we need to be able to remove D
primes from the coefficient modulus. Once we have only one prime left in the
coeff_modulus, the remaining prime must be larger than S by a few bits to
preserve the pre-decimal-point value of the plaintext.
Therefore, a generally good strategy is to choose parameters for the CKKS
scheme as follows:
(1) Choose a 60-bit prime as the first prime in CoeffModulus. This will
give the highest precision when decrypting;
(2) Choose another 60-bit prime as the last element of CoeffModulus, as
this will be used as the special prime and should be as large as the
largest of the other primes;
(3) Choose the intermediate primes to be close to each other.
We use CoeffModulus.Create to generate primes of the appropriate size. Note
that our CoeffModulus is 200 bits total, which is below the bound for our
PolyModulusDegree: CoeffModulus.MaxBitCount(8192) returns 218.
*/
ulong polyModulusDegree = 8192;
parms.PolyModulusDegree = polyModulusDegree;
parms.CoeffModulus = CoeffModulus.Create(
polyModulusDegree, new int[]{ 60, 40, 40, 60 });
/*
We choose the initial scale to be 2^40. At the last level, this leaves us
60-40=20 bits of precision before the decimal point, and enough (roughly
10-20 bits) of precision after the decimal point. Since our intermediate
primes are 40 bits (in fact, they are very close to 2^40), we can achieve
scale stabilization as described above.
*/
double scale = Math.Pow(2.0, 40);
using SEALContext context = new SEALContext(parms);
Utilities.PrintParameters(context);
Console.WriteLine();
using KeyGenerator keygen = new KeyGenerator(context);
using PublicKey publicKey = keygen.PublicKey;
using SecretKey secretKey = keygen.SecretKey;
using RelinKeys relinKeys = keygen.RelinKeysLocal();
using Encryptor encryptor = new Encryptor(context, publicKey);
using Evaluator evaluator = new Evaluator(context);
using Decryptor decryptor = new Decryptor(context, secretKey);
using CKKSEncoder encoder = new CKKSEncoder(context);
ulong slotCount = encoder.SlotCount;
Console.WriteLine($"Number of slots: {slotCount}");
List<double> input = new List<double>((int)slotCount);
double currPoint = 0, stepSize = 1.0 / (slotCount - 1);
for (ulong i = 0; i < slotCount; i++, currPoint += stepSize)
{
input.Add(currPoint);
}
Console.WriteLine("Input vector:");
Utilities.PrintVector(input, 3, 7);
Console.WriteLine("Evaluating polynomial PI*x^3 + 0.4x + 1 ...");
/*
We create plaintexts for PI, 0.4, and 1 using an overload of CKKSEncoder.Encode
that encodes the given floating-point value to every slot in the vector.
*/
using Plaintext plainCoeff3 = new Plaintext(),
plainCoeff1 = new Plaintext(),
plainCoeff0 = new Plaintext();
encoder.Encode(3.14159265, scale, plainCoeff3);
encoder.Encode(0.4, scale, plainCoeff1);
encoder.Encode(1.0, scale, plainCoeff0);
using Plaintext xPlain = new Plaintext();
Utilities.PrintLine();
Console.WriteLine("Encode input vectors.");
encoder.Encode(input, scale, xPlain);
using Ciphertext x1Encrypted = new Ciphertext();
encryptor.Encrypt(xPlain, x1Encrypted);
/*
To compute x^3 we first compute x^2 and relinearize. However, the scale has
now grown to 2^80.
*/
using Ciphertext x3Encrypted = new Ciphertext();
Utilities.PrintLine();
Console.WriteLine("Compute x^2 and relinearize:");
evaluator.Square(x1Encrypted, x3Encrypted);
evaluator.RelinearizeInplace(x3Encrypted, relinKeys);
Console.WriteLine(" + Scale of x^2 before rescale: {0} bits",
Math.Log(x3Encrypted.Scale, newBase: 2));
/*
Now rescale; in addition to a modulus switch, the scale is reduced down by
a factor equal to the prime that was switched away (40-bit prime). Hence, the
new scale should be close to 2^40. Note, however, that the scale is not equal
to 2^40: this is because the 40-bit prime is only close to 2^40.
*/
Utilities.PrintLine();
Console.WriteLine("Rescale x^2.");
evaluator.RescaleToNextInplace(x3Encrypted);
Console.WriteLine(" + Scale of x^2 after rescale: {0} bits",
Math.Log(x3Encrypted.Scale, newBase: 2));
/*
Now x3Encrypted is at a different level than x1Encrypted, which prevents us
from multiplying them to compute x^3. We could simply switch x1Encrypted to
the next parameters in the modulus switching chain. However, since we still
need to multiply the x^3 term with PI (plainCoeff3), we instead compute PI*x
first and multiply that with x^2 to obtain PI*x^3. To this end, we compute
PI*x and rescale it back from scale 2^80 to something close to 2^40.
*/
Utilities.PrintLine();
Console.WriteLine("Compute and rescale PI*x.");
using Ciphertext x1EncryptedCoeff3 = new Ciphertext();
evaluator.MultiplyPlain(x1Encrypted, plainCoeff3, x1EncryptedCoeff3);
Console.WriteLine(" + Scale of PI*x before rescale: {0} bits",
Math.Log(x1EncryptedCoeff3.Scale, newBase: 2));
evaluator.RescaleToNextInplace(x1EncryptedCoeff3);
Console.WriteLine(" + Scale of PI*x after rescale: {0} bits",
Math.Log(x1EncryptedCoeff3.Scale, newBase: 2));
/*
Since x3Encrypted and x1EncryptedCoeff3 have the same exact scale and use
the same encryption parameters, we can multiply them together. We write the
result to x3Encrypted, relinearize, and rescale. Note that again the scale
is something close to 2^40, but not exactly 2^40 due to yet another scaling
by a prime. We are down to the last level in the modulus switching chain.
*/
Utilities.PrintLine();
Console.WriteLine("Compute, relinearize, and rescale (PI*x)*x^2.");
evaluator.MultiplyInplace(x3Encrypted, x1EncryptedCoeff3);
evaluator.RelinearizeInplace(x3Encrypted, relinKeys);
Console.WriteLine(" + Scale of PI*x^3 before rescale: {0} bits",
Math.Log(x3Encrypted.Scale, newBase: 2));
evaluator.RescaleToNextInplace(x3Encrypted);
Console.WriteLine(" + Scale of PI*x^3 after rescale: {0} bits",
Math.Log(x3Encrypted.Scale, newBase: 2));
/*
Next we compute the degree one term. All this requires is one MultiplyPlain
with plainCoeff1. We overwrite x1Encrypted with the result.
*/
Utilities.PrintLine();
Console.WriteLine("Compute and rescale 0.4*x.");
evaluator.MultiplyPlainInplace(x1Encrypted, plainCoeff1);
Console.WriteLine(" + Scale of 0.4*x before rescale: {0} bits",
Math.Log(x1Encrypted.Scale, newBase: 2));
evaluator.RescaleToNextInplace(x1Encrypted);
Console.WriteLine(" + Scale of 0.4*x after rescale: {0} bits",
Math.Log(x1Encrypted.Scale, newBase: 2));
/*
Now we would hope to compute the sum of all three terms. However, there is
a serious problem: the encryption parameters used by all three terms are
different due to modulus switching from rescaling.
Encrypted addition and subtraction require that the scales of the inputs are
the same, and also that the encryption parameters (ParmsId) match. If there
is a mismatch, Evaluator will throw an exception.
*/
Console.WriteLine();
Utilities.PrintLine();
Console.WriteLine("Parameters used by all three terms are different:");
Console.WriteLine(" + Modulus chain index for x3Encrypted: {0}",
context.GetContextData(x3Encrypted.ParmsId).ChainIndex);
Console.WriteLine(" + Modulus chain index for x1Encrypted: {0}",
context.GetContextData(x1Encrypted.ParmsId).ChainIndex);
Console.WriteLine(" + Modulus chain index for plainCoeff0: {0}",
context.GetContextData(plainCoeff0.ParmsId).ChainIndex);
Console.WriteLine();
/*
Let us carefully consider what the scales are at this point. We denote the
primes in coeff_modulus as P_0, P_1, P_2, P_3, in this order. P_3 is used as
the special modulus and is not involved in rescalings. After the computations
above the scales in ciphertexts are:
- Product x^2 has scale 2^80 and is at level 2;
- Product PI*x has scale 2^80 and is at level 2;
- We rescaled both down to scale 2^80/P2 and level 1;
- Product PI*x^3 has scale (2^80/P_2)^2;
- We rescaled it down to scale (2^80/P_2)^2/P_1 and level 0;
- Product 0.4*x has scale 2^80;
- We rescaled it down to scale 2^80/P_2 and level 1;
- The contant term 1 has scale 2^40 and is at level 2.
Although the scales of all three terms are approximately 2^40, their exact
values are different, hence they cannot be added together.
*/
Utilities.PrintLine();
Console.WriteLine("The exact scales of all three terms are different:");
Console.WriteLine(" + Exact scale in PI*x^3: {0:0.0000000000}", x3Encrypted.Scale);
Console.WriteLine(" + Exact scale in 0.4*x: {0:0.0000000000}", x1Encrypted.Scale);
Console.WriteLine(" + Exact scale in 1: {0:0.0000000000}", plainCoeff0.Scale);
Console.WriteLine();
/*
There are many ways to fix this problem. Since P_2 and P_1 are really close
to 2^40, we can simply "lie" to Microsoft SEAL and set the scales to be the
same. For example, changing the scale of PI*x^3 to 2^40 simply means that we
scale the value of PI*x^3 by 2^120/(P_2^2*P_1), which is very close to 1.
This should not result in any noticeable error.
Another option would be to encode 1 with scale 2^80/P_2, do a MultiplyPlain
with 0.4*x, and finally rescale. In this case we would need to additionally
make sure to encode 1 with appropriate encryption parameters (ParmsId).
In this example we will use the first (simplest) approach and simply change
the scale of PI*x^3 and 0.4*x to 2^40.
*/
Utilities.PrintLine();
Console.WriteLine("Normalize scales to 2^40.");
x3Encrypted.Scale = Math.Pow(2.0, 40);
x1Encrypted.Scale = Math.Pow(2.0, 40);
/*
We still have a problem with mismatching encryption parameters. This is easy
to fix by using traditional modulus switching (no rescaling). CKKS supports
modulus switching just like the BFV scheme, allowing us to switch away parts
of the coefficient modulus when it is simply not needed.
*/
Utilities.PrintLine();
Console.WriteLine("Normalize encryption parameters to the lowest level.");
ParmsId lastParmsId = x3Encrypted.ParmsId;
evaluator.ModSwitchToInplace(x1Encrypted, lastParmsId);
evaluator.ModSwitchToInplace(plainCoeff0, lastParmsId);
/*
All three ciphertexts are now compatible and can be added.
*/
Utilities.PrintLine();
Console.WriteLine("Compute PI*x^3 + 0.4*x + 1.");
using Ciphertext encryptedResult = new Ciphertext();
evaluator.Add(x3Encrypted, x1Encrypted, encryptedResult);
evaluator.AddPlainInplace(encryptedResult, plainCoeff0);
/*
First print the true result.
*/
using Plaintext plainResult = new Plaintext();
Utilities.PrintLine();
Console.WriteLine("Decrypt and decode PI * x ^ 3 + 0.4x + 1.");
Console.WriteLine(" + Expected result:");
List<double> trueResult = new List<double>(input.Count);
foreach (double x in input)
{
trueResult.Add((3.14159265 * x * x + 0.4) * x + 1);
}
Utilities.PrintVector(trueResult, 3, 7);
/*
We decrypt, decode, and print the result.
*/
decryptor.Decrypt(encryptedResult, plainResult);
List<double> result = new List<double>();
encoder.Decode(plainResult, result);
Console.WriteLine(" + Computed result ...... Correct.");
Utilities.PrintVector(result, 3, 7);
/*
While we did not show any computations on complex numbers in these examples,
the CKKSEncoder would allow us to have done that just as easily. Additions
and multiplications of complex numbers behave just as one would expect.
*/
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using Microsoft.Research.SEAL;
using System.Collections.Generic;
namespace SEALNetExamples
{
partial class Examples
{
/*
Both the BFV scheme (with BatchEncoder) as well as the CKKS scheme support native
vectorized computations on encrypted numbers. In addition to computing slot-wise,
it is possible to rotate the encrypted vectors cyclically.
*/
private static void ExampleRotationBFV()
{
Utilities.PrintExampleBanner("Example: Rotation / Rotation in BFV");
using EncryptionParameters parms = new EncryptionParameters(SchemeType.BFV);
ulong polyModulusDegree = 8192;
parms.PolyModulusDegree = polyModulusDegree;
parms.CoeffModulus = CoeffModulus.BFVDefault(polyModulusDegree);
parms.PlainModulus = PlainModulus.Batching(polyModulusDegree, 20);
using SEALContext context = new SEALContext(parms);
Utilities.PrintParameters(context);
Console.WriteLine();
using KeyGenerator keygen = new KeyGenerator(context);
using PublicKey publicKey = keygen.PublicKey;
using SecretKey secretKey = keygen.SecretKey;
using RelinKeys relinKeys = keygen.RelinKeysLocal();
using Encryptor encryptor = new Encryptor(context, publicKey);
using Evaluator evaluator = new Evaluator(context);
using Decryptor decryptor = new Decryptor(context, secretKey);
using BatchEncoder batchEncoder = new BatchEncoder(context);
ulong slotCount = batchEncoder.SlotCount;
ulong rowSize = slotCount / 2;
Console.WriteLine($"Plaintext matrix row size: {rowSize}");
ulong[] podMatrix = new ulong[slotCount];
podMatrix[0] = 0;
podMatrix[1] = 1;
podMatrix[2] = 2;
podMatrix[3] = 3;
podMatrix[rowSize] = 4;
podMatrix[rowSize + 1] = 5;
podMatrix[rowSize + 2] = 6;
podMatrix[rowSize + 3] = 7;
Console.WriteLine("Input plaintext matrix:");
Utilities.PrintMatrix(podMatrix, (int)rowSize);
Console.WriteLine();
/*
First we use BatchEncoder to encode the matrix into a plaintext. We encrypt
the plaintext as usual.
*/
Utilities.PrintLine();
using Plaintext plainMatrix = new Plaintext();
Console.WriteLine("Encode and encrypt.");
batchEncoder.Encode(podMatrix, plainMatrix);
using Ciphertext encryptedMatrix = new Ciphertext();
encryptor.Encrypt(plainMatrix, encryptedMatrix);
Console.WriteLine(" + Noise budget in fresh encryption: {0} bits",
decryptor.InvariantNoiseBudget(encryptedMatrix));
Console.WriteLine();
/*
Rotations require yet another type of special key called `Galois keys'. These
are easily obtained from the KeyGenerator.
*/
using GaloisKeys galKeys = keygen.GaloisKeysLocal();
/*
Now rotate both matrix rows 3 steps to the left, decrypt, decode, and print.
*/
Utilities.PrintLine();
Console.WriteLine("Rotate rows 3 steps left.");
evaluator.RotateRowsInplace(encryptedMatrix, 3, galKeys);
using Plaintext plainResult = new Plaintext();
Console.WriteLine(" + Noise budget after rotation: {0} bits",
decryptor.InvariantNoiseBudget(encryptedMatrix));
Console.WriteLine(" + Decrypt and decode ...... Correct.");
decryptor.Decrypt(encryptedMatrix, plainResult);
List<ulong> podResult = new List<ulong>();
batchEncoder.Decode(plainResult, podResult);
Utilities.PrintMatrix(podResult, (int)rowSize);
/*
We can also rotate the columns, i.e., swap the rows.
*/
Utilities.PrintLine();
Console.WriteLine("Rotate columns.");
evaluator.RotateColumnsInplace(encryptedMatrix, galKeys);
Console.WriteLine(" + Noise budget after rotation: {0} bits",
decryptor.InvariantNoiseBudget(encryptedMatrix));
Console.WriteLine(" + Decrypt and decode ...... Correct.");
decryptor.Decrypt(encryptedMatrix, plainResult);
batchEncoder.Decode(plainResult, podResult);
Utilities.PrintMatrix(podResult, (int)rowSize);
/*
Finally, we rotate the rows 4 steps to the right, decrypt, decode, and print.
*/
Utilities.PrintLine();
Console.WriteLine("Rotate rows 4 steps right.");
evaluator.RotateRowsInplace(encryptedMatrix, -4, galKeys);
Console.WriteLine(" + Noise budget after rotation: {0} bits",
decryptor.InvariantNoiseBudget(encryptedMatrix));
Console.WriteLine(" + Decrypt and decode ...... Correct.");
decryptor.Decrypt(encryptedMatrix, plainResult);
batchEncoder.Decode(plainResult, podResult);
Utilities.PrintMatrix(podResult, (int)rowSize);
/*
Note that rotations do not consume any noise budget. However, this is only
the case when the special prime is at least as large as the other primes. The
same holds for relinearization. Microsoft SEAL does not require that the
special prime is of any particular size, so ensuring this is the case is left
for the user to do.
*/
}
private static void ExampleRotationCKKS()
{
Utilities.PrintExampleBanner("Example: Rotation / Rotation in CKKS");
using EncryptionParameters parms = new EncryptionParameters(SchemeType.CKKS);
ulong polyModulusDegree = 8192;
parms.PolyModulusDegree = polyModulusDegree;
parms.CoeffModulus = CoeffModulus.Create(
polyModulusDegree, new int[] { 40, 40, 40, 40, 40 });
using SEALContext context = new SEALContext(parms);
Utilities.PrintParameters(context);
Console.WriteLine();
using KeyGenerator keygen = new KeyGenerator(context);
using PublicKey publicKey = keygen.PublicKey;
using SecretKey secretKey = keygen.SecretKey;
using RelinKeys relinKeys = keygen.RelinKeysLocal();
using GaloisKeys galKeys = keygen.GaloisKeysLocal();
using Encryptor encryptor = new Encryptor(context, publicKey);
using Evaluator evaluator = new Evaluator(context);
using Decryptor decryptor = new Decryptor(context, secretKey);
using CKKSEncoder ckksEncoder = new CKKSEncoder(context);
ulong slotCount = ckksEncoder.SlotCount;
Console.WriteLine($"Number of slots: {slotCount}");
List<double> input = new List<double>((int)slotCount);
double currPoint = 0, stepSize = 1.0 / (slotCount - 1);
for (ulong i = 0; i < slotCount; i++, currPoint += stepSize)
{
input.Add(currPoint);
}
Console.WriteLine("Input vector:");
Utilities.PrintVector(input, 3, 7);
double scale = Math.Pow(2.0, 50);
Utilities.PrintLine();
Console.WriteLine("Encode and encrypt.");
using Plaintext plain = new Plaintext();
ckksEncoder.Encode(input, scale, plain);
using Ciphertext encrypted = new Ciphertext();
encryptor.Encrypt(plain, encrypted);
using Ciphertext rotated = new Ciphertext();
Utilities.PrintLine();
Console.WriteLine("Rotate 2 steps left.");
evaluator.RotateVector(encrypted, 2, galKeys, rotated);
Console.WriteLine(" + Decrypt and decode ...... Correct.");
decryptor.Decrypt(encrypted, plain);
List<double> result = new List<double>();
ckksEncoder.Decode(plain, result);
Utilities.PrintVector(result, 3, 7);
/*
With the CKKS scheme it is also possible to evaluate a complex conjugation on
a vector of encrypted complex numbers, using Evaluator.ComplexConjugate. This
is in fact a kind of rotation, and requires also Galois keys.
*/
}
private static void ExampleRotation()
{
Utilities.PrintExampleBanner("Example: Rotation");
/*
Run all rotation examples.
*/
ExampleRotationBFV();
ExampleRotationCKKS();
}
}
}
This diff is collapsed.
This diff is collapsed.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Research.SEAL;
using System;
namespace SEALNetExamples
{
partial class Examples
{
static void Main(string[] args)
{
Console.WriteLine("Microsoft SEAL version: " + SEALVersion.Version);
while (true)
{
Console.WriteLine("+---------------------------------------------------------+");
Console.WriteLine("| The following examples should be executed while reading |");
Console.WriteLine("| comments in associated files in dotnet/examples/. |");
Console.WriteLine("+---------------------------------------------------------+");
Console.WriteLine("| Examples | Source Files |");
Console.WriteLine("+----------------------------+----------------------------+");
Console.WriteLine("| 1. BFV Basics | 1_BFV_Basics.cs |");
Console.WriteLine("| 2. Encoders | 2_Encoders.cs |");
Console.WriteLine("| 3. Levels | 3_Levels.cs |");
Console.WriteLine("| 4. CKKS Basics | 4_CKKS_Basics.cs |");
Console.WriteLine("| 5. Rotation | 5_Rotation.cs |");
Console.WriteLine("| 6. Serialization | 6_Serialization.cs |");
Console.WriteLine("| 7. Performance Test | 7_Performance.cs |");
Console.WriteLine("+----------------------------+----------------------------+");
/*
Print how much memory we have allocated from the current memory pool.
By default the memory pool will be a static global pool and the
MemoryManager class can be used to change it. Most users should have
little or no reason to touch the memory allocation system.
*/
ulong megabytes = MemoryManager.GetPool().AllocByteCount >> 20;
Console.WriteLine("[{0,7} MB] Total allocation from the memory pool", megabytes);
ConsoleKeyInfo key;
do
{
Console.WriteLine();
Console.Write("> Run example (1 ~ 7) or exit (0): ");
key = Console.ReadKey();
Console.WriteLine();
} while (key.KeyChar < '0' || key.KeyChar > '7');
switch (key.Key)
{
case ConsoleKey.D1:
ExampleBFVBasics();
break;
case ConsoleKey.D2:
ExampleEncoders();
break;
case ConsoleKey.D3:
ExampleLevels();
break;
case ConsoleKey.D4:
ExampleCKKSBasics();
break;
case ConsoleKey.D5:
ExampleRotation();
break;
case ConsoleKey.D6:
ExampleSerialization();
break;
case ConsoleKey.D7:
ExamplePerformanceTest();
break;
case ConsoleKey.D0:
return;
default:
Console.WriteLine(" [Beep~~] Invalid option: type 0 ~ 7");
break;
}
/*
We may want to force a garbage collection after each example to accurately show memory pool use.
*/
GC.Collect();
}
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Authors>Microsoft Research</Authors>
<Company>Microsoft Corporation</Company>
<Description>.NET wrapper examples for Microsoft SEAL</Description>
<Copyright>Microsoft Corporation 2020</Copyright>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='AnyCPU'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>$(ProjectDir)../../bin/dotnet/$(Configuration)</OutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="$(ProjectDir)../src/SEALNet.csproj" />
</ItemGroup>
<ItemGroup>
<SEALCBinaryFiles Condition="$([MSBuild]::IsOsPlatform(Windows))" Include="$(ProjectDir)..\..\lib\x64\$(Configuration)\sealc.dll" />
<SEALCBinaryFiles Condition="$([MSBuild]::IsOsPlatform(Linux))" Include="$(ProjectDir)../../lib/libsealc.so.*" />
<SEALCBinaryFiles Condition="$([MSBuild]::IsOsPlatform(OSX))" Include="$(ProjectDir)../../lib/libsealc*.dylib" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Copy SourceFiles="@(SEALCBinaryFiles)" DestinationFolder="$(TargetDir)" />
</Target>
</Project>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment