|
@@ -0,0 +1,1484 @@
|
|
|
+#include <iostream>
|
|
|
+#include <map>
|
|
|
+#include "openfhe.h"
|
|
|
+#include "key/key-ser.h"
|
|
|
+#include "bindings.hpp"
|
|
|
+#include "pke/cryptocontext_wrapper.hpp"
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#include "pke/scheme/bfvrns/gen-cryptocontext-bfvrns-params.h"
|
|
|
+#include "pke/serialization.hpp"
|
|
|
+#include "constants.h"
|
|
|
+
|
|
|
+using namespace lbcrypto;
|
|
|
+
|
|
|
+namespace {
|
|
|
+ struct ParamsHolder{
|
|
|
+ std::shared_ptr<Params> ptr;
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+FFIParams::FFIParams(){
|
|
|
+ params_ptr = reinterpret_cast<void*>(
|
|
|
+ new ParamsHolder{std::make_shared<Params>()});
|
|
|
+}
|
|
|
+
|
|
|
+FFIParams::FFIParams(FFISCHEME scheme){
|
|
|
+ params_ptr = reinterpret_cast<void*>(
|
|
|
+ new ParamsHolder{std::make_shared<Params>(lbcrypto:SCHEME(scheme))});
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+FFIPlaintextModulus FFIParams::GetPlaintextModulus() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFISCHEME(cc_params->GetPlaintextModulus());
|
|
|
+}
|
|
|
+
|
|
|
+FFISCHEME FFIParams::GetScheme() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFISCHEME(cc_params->GetScheme());
|
|
|
+}
|
|
|
+
|
|
|
+usint FFIParams::GetDigitSize() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetDigitSize();
|
|
|
+}
|
|
|
+
|
|
|
+float FFIParams::GetStandardDeviation() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetStandardDeviation();
|
|
|
+}
|
|
|
+
|
|
|
+FFISecretKeyDist FFIParams::GetSecretKeyDist() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFISecretKeyDist(cc_params->GetSecretKeyDist());
|
|
|
+}
|
|
|
+
|
|
|
+usint FFIParams::GetMaxRelinSkDeg() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetMaxRelinSkDeg();
|
|
|
+}
|
|
|
+
|
|
|
+FFIProxyReEncryptionMode FFIParams::GetPREMode() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFIProxyReEncryptionMode(cc_params->GetPREMode());
|
|
|
+}
|
|
|
+
|
|
|
+FFIMultipartyMode FFIParams::GetMultipartyMode() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFIMultipartyMode(cc_params->GetMultipartyMode());
|
|
|
+}
|
|
|
+
|
|
|
+FFIExecutionMode FFIParams::GetExecutionMode() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFIExecutionMode(cc_params->GetExecutionMode());
|
|
|
+}
|
|
|
+
|
|
|
+FFIDecryptionNoiseMode FFIParams::GetDecryptionNoiseMode() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFIDecryptionNoiseMode(cc_params->GetDecryptionNoiseMode());
|
|
|
+}
|
|
|
+
|
|
|
+double FFIParams::GetNoiseEstimate() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetNoiseEstimate();
|
|
|
+}
|
|
|
+
|
|
|
+double FFIParams::GetDesiredPrecision() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetDesiredPrecision();
|
|
|
+}
|
|
|
+
|
|
|
+double FFIParams::GetStatisticalSecurity() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetStatisticalSecurity();
|
|
|
+}
|
|
|
+
|
|
|
+double FFIParams::GetNumAdversarialQueries() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetNumAdversarialQueries();
|
|
|
+}
|
|
|
+
|
|
|
+usint FFIParams::GetThresholdNumOfParties() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetThresholdNumOfParties();
|
|
|
+}
|
|
|
+
|
|
|
+FFIKeySwitchTechnique FFIParams::GetKeySwitchTechnique() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFIKeySwitchTechnique(cc_params->GetKeySwitchTechnique());
|
|
|
+}
|
|
|
+
|
|
|
+FFIScalingTechnique FFIParams::GetScalingTechnique() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFIScalingTechnique(cc_params->GetScalingTechnique());
|
|
|
+}
|
|
|
+
|
|
|
+usint FFIParams::GetBatchSize() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetBatchSize();
|
|
|
+}
|
|
|
+
|
|
|
+usint FFIParams::GetFirstModSize() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetFirstModSize();
|
|
|
+}
|
|
|
+
|
|
|
+uint32_t FFIParams::GetNumLargeDigits() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return static_cast<uint32_t>(cc_params->GetNumLargeDigits());
|
|
|
+}
|
|
|
+
|
|
|
+usint FFIParams::GetMultiplicativeDepth() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return static_cast<usint>(cc_params->GetMultiplicativeDepth());
|
|
|
+}
|
|
|
+
|
|
|
+usint FFIParams::GetScalingModSize() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return static_cast<usint>(cc_params->GetScalingModSize());
|
|
|
+}
|
|
|
+
|
|
|
+FFISecurityLevel FFIParams::GetSecurityLevel() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFISecurityLevel(cc_params->GetSecurityLevel());
|
|
|
+}
|
|
|
+
|
|
|
+usint FFIParams::GetRingDim() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetRingDim();
|
|
|
+}
|
|
|
+
|
|
|
+usint FFIParams::GetEvalAddCount() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetEvalAddCount();
|
|
|
+}
|
|
|
+
|
|
|
+usint FFIParams::GetKeySwitchCount() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetKeySwitchCount();
|
|
|
+}
|
|
|
+
|
|
|
+FFIEncryptionTechnique FFIParams::GetEncryptionTechnique() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFIEncryptionTechnique(cc_params->GetEncryptionTechnique());
|
|
|
+}
|
|
|
+
|
|
|
+FFIMultiplicationTechnique FFIParams::GetMultiplicationTechnique() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFIMultiplicationTechnique(cc_params->GetMultiplicationTechnique());
|
|
|
+}
|
|
|
+
|
|
|
+usint FFIParams::GetMultiHopModSize() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return cc_params->GetMultiHopModSize();
|
|
|
+}
|
|
|
+
|
|
|
+FFICOMPRESSION_LEVEL FFIParams::GetInteractiveBootCompressionLevel() const{
|
|
|
+ std::shared_ptr<const Params> cc_params =
|
|
|
+ reinterpret_cast<const ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ return FFICOMPRESSION_LEVEL(cc_params->GetInteractiveBootCompressionLevel());
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void FFIParams::SetPlaintextModulus(FFIPlaintextModulus ptModulus){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetPlaintextModulus(ptModulus);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetDigitSize(usint digitSize){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetDigitSize(digitSize);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetStandardDeviation(float standardDeviation){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetStandardDeviation(standardDeviation);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetSecretKeyDist(FFISecretKeyDist secretKeyDist){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetSecretKeyDist(lbcrypto::SecretKeyDist(secretKeyDist));
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetMaxRelinSkDeg(usint maxRelinSkDeg){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetMaxRelinSkDeg(maxRelinSkDeg);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetPREMode(FFIProxyReEncryptionMode preMode){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetPREMode(lbcrypto::ProxyReEncryptionMode(preMode));
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetMultipartyMode(FFIMultipartyMode multipartyMode){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetMultipartyMode(lbcrypto::MultipartyMode(multipartyMode));
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetExecutionMode(FFIExecutionMode executionMode){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetExecutionMode(lbcrypto::ExecutionMode(executionMode));
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetDecryptionNoiseMode(FFIDecryptionNoiseMode decryptionNoiseMode){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetDecryptionNoiseMode(lbcrypto::DecryptionNoiseMode(decryptionNoiseMode));
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetNoiseEstimate(double noiseEstimate){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetNoiseEstimate(noiseEstimate);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetDesiredPrecision(double desiredPrecision){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetDesiredPrecision(desiredPrecision);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetStatisticalSecurity(uint32_t statisticalSecurity){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetStatisticalSecurity(statisticalSecurity);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetNumAdversarialQueries(uint32_t numAdversarialQueries){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetNumAdversarialQueries(numAdversarialQueries);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetThresholdNumOfParties(uint32_t thresholdNumOfParties){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetThresholdNumOfParties(thresholdNumOfParties);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetKeySwitchTechnique(FFIKeySwitchTechnique keySwitchTechnique){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetKeySwitchTechnique(lbcrypto::KeySwitchTechnique(keySwitchTechnique));
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetScalingTechnique(FFIScalingTechnique scalingTechnique){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetScalingTechnique(lbcrypto::ScalingTechnique(scalingTechnique));
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetBatchSize(usint batchSize){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetBatchSize(batchSize);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetFirstModSize(usint firstModSize){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetFirstModSize(firstModSize);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetNumLargeDigits(usint numLargeDigits){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetNumLargeDigits(numLargeDigits);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetMultiplicativeDepth(usint multiplicativeDepth){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetMultiplicativeDepth(multiplicativeDepth);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetScalingModSize(usint scalingModSize){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetScalingModSize(scalingModSize);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetSecurityLevel(FFISecurityLevel securityLevel){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetSecurityLevel(lbcrypto::SecurityLevel(securityLevel));
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetRingDim(usint ringDim){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetRingDim(ringDim);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetEvalAddCount(usint evalAddCount){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetEvalAddCount(evalAddCount);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetKeySwitchCount(usint keySwitchCount){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetKeySwitchCount(keySwitchCount);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetEncryptionTechnique(FFIEncryptionTechnique encryptionTechnique){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetEncryptionTechnique(lbcrypto::EncryptionTechnique(encryptionTechnique));
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetMultiplicationTechnique(FFIMultiplicationTechnique multiplicationTechnique){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetMultiplicationTechnique(lbcrypto::MultiplicationTechnique(multiplicationTechnique));
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetMultiHopModSize(usint multiHopModSize){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetMultiHopModSize(multiHopModSize);
|
|
|
+}
|
|
|
+
|
|
|
+void FFIParams::SetInteractiveBootCompressionLevel(FFICOMPRESSION_LEVEL interactiveBootCompressionLevel){
|
|
|
+ std::shared_ptr<Params> cc_params =
|
|
|
+ reinterpret_cast<ParamsHolder*>(params_ptr)->ptr;
|
|
|
+ cc_params->SetInteractiveBootCompressionLevel(lbcrypto::COMPRESSION_LEVEL(interactiveBootCompressionLevel));
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|