ChooserPoly ChooserEvaluator::exponentiate(const ChooserPoly &operand, uint64_t exponent)
    {
        if (operand.max_coeff_count_ <= 0 || operand.comp_ == nullptr)
        {
            throw invalid_argument("operand is not correctly initialized");
        }
        if (exponent == 0 && operand.max_abs_value_.is_zero())
        {
            throw invalid_argument("undefined operation");
        }
        if (exponent == 0)
        {
            return ChooserPoly(1, 1, new ExponentiateComputation(*operand.comp_, exponent));
        }
        if (operand.max_abs_value_.is_zero())
        {
            return ChooserPoly(1, 0, new ExponentiateComputation(*operand.comp_, exponent));
        }

        // There is no known closed formula for the growth factor, but we use the asymptotic approximation
        // k^n * sqrt[6/((k-1)*(k+1)*Pi*n)], where k = max_coeff_count_, n = exponent.
        uint64_t growth_factor = static_cast<uint64_t>(pow(operand.max_coeff_count_, exponent) * sqrt(6 / ((operand.max_coeff_count_ - 1) * (operand.max_coeff_count_ + 1) * 3.1415 * exponent)));

        int result_bit_count = static_cast<int>(exponent) * operand.max_abs_value_.significant_bit_count() + get_significant_bit_count(growth_factor) + 1;
        int result_uint64_count = divide_round_up(result_bit_count, bits_per_uint64);

        Pointer result_max_abs_value(allocate_uint(result_uint64_count, pool_));

        util::exponentiate_uint(operand.max_abs_value_.pointer(), operand.max_abs_value_.uint64_count(), &exponent, 1, result_uint64_count, result_max_abs_value.get(), pool_);

        ConstPointer temp_pointer(duplicate_uint_if_needed(result_max_abs_value.get(), result_uint64_count, result_uint64_count, true, pool_));
        multiply_uint_uint(&growth_factor, 1, temp_pointer.get(), result_uint64_count, result_uint64_count, result_max_abs_value.get());

        return ChooserPoly(static_cast<int>(exponent) * (operand.max_coeff_count_ - 1) + 1, BigUInt(result_bit_count, result_max_abs_value.get()), new ExponentiateComputation(*operand.comp_, exponent));
    }
    ChooserPoly ChooserEvaluator::multiply_plain(const ChooserPoly &operand, int plain_max_coeff_count, const BigUInt &plain_max_abs_value)
    {
        if (operand.max_coeff_count_ <= 0 || operand.comp_ == nullptr)
        {
            throw invalid_argument("operand is not correctly initialized");
        }
        if (plain_max_coeff_count <= 0)
        {
            throw invalid_argument("plain_max_coeff_count must be positive");
        }
        if (plain_max_abs_value.is_zero())
        {
            return ChooserPoly(1, 0, new MultiplyPlainComputation(*operand.comp_, plain_max_coeff_count, plain_max_abs_value));
        }
        if (operand.max_abs_value_.is_zero())
        {
            return ChooserPoly(1, 0, new MultiplyPlainComputation(*operand.comp_, plain_max_coeff_count, plain_max_abs_value));
        }

        uint64_t growth_factor = min(operand.max_coeff_count_, plain_max_coeff_count);
        int prod_bit_count = operand.max_abs_value_.significant_bit_count() + plain_max_abs_value.significant_bit_count() + get_significant_bit_count(growth_factor) + 1;
        int prod_uint64_count = divide_round_up(prod_bit_count, bits_per_uint64);

        Pointer prod_max_abs_value(allocate_zero_uint(prod_uint64_count, pool_));
        ConstPointer wide_operand_max_abs_value(duplicate_uint_if_needed(operand.max_abs_value_.pointer(), operand.max_abs_value_.uint64_count(), prod_uint64_count, false, pool_));

        multiply_uint_uint(&growth_factor, 1, plain_max_abs_value.pointer(), plain_max_abs_value.uint64_count(), prod_uint64_count, prod_max_abs_value.get());
        ConstPointer temp_pointer(duplicate_uint_if_needed(prod_max_abs_value.get(), prod_uint64_count, prod_uint64_count, true, pool_));
        multiply_uint_uint(wide_operand_max_abs_value.get(), prod_uint64_count, temp_pointer.get(), prod_uint64_count, prod_uint64_count, prod_max_abs_value.get());

        return ChooserPoly(operand.max_coeff_count_ + plain_max_coeff_count - 1, BigUInt(prod_bit_count, prod_max_abs_value.get()), new MultiplyPlainComputation(*operand.comp_, plain_max_coeff_count, plain_max_abs_value));
    }
示例#3
0
    ChooserPoly ChooserEvaluator::sub_plain(const ChooserPoly &operand, 
        int plain_max_coeff_count, uint64_t plain_max_abs_value)
    {
        if (operand.max_coeff_count_ <= 0 || operand.comp_ == nullptr)
        {
            throw invalid_argument("operand is not correctly initialized");
        }
        if (plain_max_coeff_count <= 0)
        {
            throw invalid_argument("plain_max_coeff_count must be positive");
        }
        if (plain_max_abs_value == 0)
        {
            return ChooserPoly(operand.max_coeff_count_, 
                operand.max_abs_value_, 
                new SubPlainComputation(*operand.comp_, 
                    plain_max_coeff_count, 
                    plain_max_abs_value));
        }
        if (operand.max_abs_value_ == 0)
        {
            return ChooserPoly(plain_max_coeff_count, 
                plain_max_abs_value, 
                new SubPlainComputation(*operand.comp_, 
                    plain_max_coeff_count, 
                    plain_max_abs_value));
        }

        return ChooserPoly(max(operand.max_coeff_count_, 
            plain_max_coeff_count), 
            operand.max_abs_value_ + plain_max_abs_value, 
            new SubPlainComputation(*operand.comp_, 
                plain_max_coeff_count, 
                plain_max_abs_value));
    }
示例#4
0
    ChooserPoly ChooserEvaluator::multiply(const ChooserPoly &operand1, 
        const ChooserPoly &operand2)
    {
        if (operand1.max_coeff_count_ <= 0 || operand1.comp_ == nullptr)
        {
            throw invalid_argument("operand1 is not correctly initialized");
        }
        if (operand2.max_coeff_count_ <= 0 || operand2.comp_ == nullptr)
        {
            throw invalid_argument("operand2 is not correctly initialized");
        }
        if (operand1.max_abs_value_ == 0 || operand2.max_abs_value_ == 0)
        {
            return ChooserPoly(1, 0, new MultiplyComputation(*operand1.comp_, *operand2.comp_));
        }

        uint64_t growth_factor = min(operand1.max_coeff_count_, operand2.max_coeff_count_);
        uint64_t prod_max_abs_value[2];
        multiply_uint64(growth_factor, operand1.max_abs_value_, prod_max_abs_value);
        if (prod_max_abs_value[1])
        {
            throw invalid_argument("polynomial coefficients too large");
        }
        multiply_uint64(prod_max_abs_value[0], operand2.max_abs_value_, prod_max_abs_value);
        if (prod_max_abs_value[1])
        {
            throw invalid_argument("polynomial coefficients too large");
        }

        return ChooserPoly(operand1.max_coeff_count_ + operand2.max_coeff_count_ - 1, 
            prod_max_abs_value[0], 
            new MultiplyComputation(*operand1.comp_, *operand2.comp_));
    }
示例#5
0
    ChooserPoly ChooserEvaluator::exponentiate(const ChooserPoly &operand, 
        uint64_t exponent, int decomposition_bit_count)
    {
        if (operand.max_coeff_count_ <= 0 || operand.comp_ == nullptr)
        {
            throw invalid_argument("operand is not correctly initialized");
        }
        if (exponent == 0)
        {
            throw invalid_argument("exponent cannot be 0");
        }

        // Check that decomposition_bit_count is in correct interval
        if (decomposition_bit_count < SEAL_DBC_MIN || 
            decomposition_bit_count > SEAL_DBC_MAX)
        {
            throw invalid_argument("decomposition_bit_count is not in the valid range");
        }

        if (operand.max_abs_value_ == 0)
        {
            return ChooserPoly(1, 0, 
                new ExponentiateComputation(*operand.comp_, 
                    exponent, 
                    decomposition_bit_count));
        }

        // There is no known closed formula for the growth factor, but we use the
        // asymptotic approximation k^n * sqrt[6/((k-1)*(k+1)*Pi*n)], where 
        // k = max_coeff_count_, n = exponent.
        uint64_t growth_factor = static_cast<uint64_t>(
            pow(operand.max_coeff_count_, exponent) * 
            sqrt(6 / ((operand.max_coeff_count_ - 1) * 
            (operand.max_coeff_count_ + 1) * 3.1415 * exponent)));

        uint64_t result_bit_count = 
            exponent * get_significant_bit_count(operand.max_abs_value_) + 
            get_significant_bit_count(growth_factor) + 1 + 
            get_significant_bit_count(growth_factor);
        if (result_bit_count > bits_per_uint64)
        {
            throw invalid_argument("polynomial coefficients too large");
        }
        uint64_t result_max_abs_value = exponentiate_uint64(
            operand.max_abs_value_, exponent) * growth_factor;

        uint64_t result_coeff_count = exponent * (operand.max_coeff_count_ - 1) + 1;
        if(result_coeff_count > numeric_limits<int>::max())
        {
            throw invalid_argument("polynomial is too long");
        }

        return ChooserPoly(static_cast<int>(result_coeff_count),
            result_max_abs_value, 
            new ExponentiateComputation(*operand.comp_, 
                exponent, 
                decomposition_bit_count));
    }
    ChooserPoly ChooserEvaluator::multiply_many(const vector<ChooserPoly> &operands)
    {
        if (operands.empty())
        {
            throw invalid_argument("operands vector can not be empty");
        }

        int prod_max_coeff_count = 1;
        uint64_t growth_factor = 1;
        int prod_max_abs_value_bit_count = 1;
        vector<Computation*> comps;
        for (vector<ChooserPoly>::size_type i = 0; i < operands.size(); ++i)
        {
            // Throw if any of the operands is not initialized correctly
            if (operands[i].max_coeff_count_ <= 0 || operands[i].comp_ == nullptr)
            {
                throw invalid_argument("input operand is not correctly initialized");
            }

            // Return early if the product is trivially zero
            if (operands[i].max_abs_value_.is_zero())
            {
                return ChooserPoly(1, 0, new MultiplyManyComputation(comps));
            }

            prod_max_coeff_count += operands[i].max_coeff_count_ - 1;
            prod_max_abs_value_bit_count += operands[i].max_abs_value().significant_bit_count();

            growth_factor *= (i == 0 ? 1 : min(operands[i].max_coeff_count_, prod_max_coeff_count));

            comps.push_back(operands[i].comp_);
        }

        prod_max_abs_value_bit_count += get_significant_bit_count(growth_factor);
        int prod_max_abs_value_uint64_count = divide_round_up(prod_max_abs_value_bit_count, bits_per_uint64);

        Pointer prod_max_abs_value(allocate_zero_uint(prod_max_abs_value_uint64_count, pool_));
        *prod_max_abs_value.get() = growth_factor;
        for (vector<ChooserPoly>::size_type i = 0; i < operands.size(); ++i)
        {
            ConstPointer temp_pointer(duplicate_uint_if_needed(prod_max_abs_value.get(), prod_max_abs_value_uint64_count, prod_max_abs_value_uint64_count, true, pool_));
            multiply_uint_uint(temp_pointer.get(), prod_max_abs_value_uint64_count, operands[i].max_abs_value_.pointer(), operands[i].max_abs_value_.uint64_count(), prod_max_abs_value_uint64_count, prod_max_abs_value.get());
        }

        return ChooserPoly(prod_max_coeff_count, BigUInt(prod_max_abs_value_bit_count, prod_max_abs_value.get()), new MultiplyManyComputation(comps));
    }
 ChooserPoly ChooserEvaluator::negate(const ChooserPoly &operand)
 {
     if (operand.max_coeff_count_ <= 0 || operand.comp_ == nullptr)
     {
         throw invalid_argument("operand is not correctly initialized");
     }
     return ChooserPoly(operand.max_coeff_count_, operand.max_abs_value_, new NegateComputation(*operand.comp_));
 }
示例#8
0
    ChooserPoly ChooserEvaluator::multiply_plain(const ChooserPoly &operand, 
        int plain_max_coeff_count, uint64_t plain_max_abs_value)
    {
        if (operand.max_coeff_count_ <= 0 || operand.comp_ == nullptr)
        {
            throw invalid_argument("operand is not correctly initialized");
        }
        if (plain_max_coeff_count <= 0)
        {
            throw invalid_argument("plain_max_coeff_count must be positive");
        }
        if (plain_max_abs_value == 0)
        {
            throw invalid_argument("plain_max_abs_value cannot be zero");
        }
        if (operand.max_abs_value_ == 0)
        {
            return ChooserPoly(1, 0, 
                new MultiplyPlainComputation(*operand.comp_, 
                    plain_max_coeff_count, 
                    plain_max_abs_value));
        }

        uint64_t growth_factor = min(operand.max_coeff_count_, plain_max_coeff_count);
        uint64_t prod_max_abs_value[2];
        multiply_uint64(growth_factor, operand.max_abs_value_, prod_max_abs_value);
        if (prod_max_abs_value[1])
        {
            throw invalid_argument("polynomial coefficients too large");
        }
        multiply_uint64(prod_max_abs_value[0], plain_max_abs_value, prod_max_abs_value);
        if (prod_max_abs_value[1])
        {
            throw invalid_argument("polynomial coefficients too large");
        }

        return ChooserPoly(operand.max_coeff_count_ + plain_max_coeff_count - 1, 
            prod_max_abs_value[0], 
            new MultiplyPlainComputation(*operand.comp_, 
                plain_max_coeff_count, plain_max_abs_value));
    }
    ChooserPoly ChooserEvaluator::add_plain(const ChooserPoly &operand, int plain_max_coeff_count, const BigUInt &plain_max_abs_value) const
    {
        if (operand.max_coeff_count_ <= 0 || operand.comp_ == nullptr)
        {
            throw invalid_argument("operand is not correctly initialized");
        }
        if (plain_max_coeff_count <= 0)
        {
            throw invalid_argument("plain_max_coeff_count must be positive");
        }
        if (plain_max_abs_value.is_zero())
        {
            return ChooserPoly(operand.max_coeff_count_, operand.max_abs_value_, new AddPlainComputation(*operand.comp_));
        }
        if (operand.max_abs_value_.is_zero())
        {
            return ChooserPoly(plain_max_coeff_count, plain_max_abs_value, new AddPlainComputation(*operand.comp_));
        }

        return ChooserPoly(max(operand.max_coeff_count_, plain_max_coeff_count), operand.max_abs_value_ + plain_max_abs_value, new AddPlainComputation(*operand.comp_));
    }
    ChooserPoly ChooserEvaluator::sub(const ChooserPoly &operand1, const ChooserPoly &operand2)
    {
        if (operand1.max_coeff_count_ <= 0 || operand1.comp_ == nullptr)
        {
            throw invalid_argument("operand1 is not correctly initialized");
        }
        if (operand2.max_coeff_count_ <= 0 || operand2.comp_ == nullptr)
        {
            throw invalid_argument("operand2 is not correctly initialized");
        }

        return ChooserPoly(max(operand1.max_coeff_count_, operand2.max_coeff_count_), operand1.max_abs_value_ + operand2.max_abs_value_, new SubComputation(*operand1.comp_, *operand2.comp_));
    }
示例#11
0
    ChooserPoly ChooserEvaluator::relinearize(const ChooserPoly &operand, 
        int decomposition_bit_count)
    {
        if (operand.max_coeff_count_ <= 0 || operand.comp_ == nullptr)
        {
            throw invalid_argument("operand is not correctly initialized");
        }

        // Check that decomposition_bit_count is in correct interval
        if (decomposition_bit_count < SEAL_DBC_MIN || decomposition_bit_count > SEAL_DBC_MAX)
        {
            throw invalid_argument("decomposition_bit_count is not in the valid range");
        }

        return ChooserPoly(operand.max_coeff_count_, 
            operand.max_abs_value_, 
            new RelinearizeComputation(*operand.comp_, decomposition_bit_count));
    }
    ChooserPoly ChooserEvaluator::add_many(const std::vector<ChooserPoly> &operands)
    {
        if (operands.empty())
        {
            throw invalid_argument("operands vector can not be empty");
        }

        int sum_max_coeff_count = operands[0].max_coeff_count_;
        vector<ChooserPoly>::size_type largest_abs_value_index = 0;
        for (vector<ChooserPoly>::size_type i = 0; i < operands.size(); ++i)
        {
            // Throw if any of the operands is not initialized correctly
            if (operands[i].max_coeff_count_ <= 0 || operands[i].comp_ == nullptr)
            {
                throw invalid_argument("input operand is not correctly initialized");
            }

            if (operands[i].max_coeff_count_ > sum_max_coeff_count)
            {
                sum_max_coeff_count = operands[i].max_coeff_count_;
            }
            if (compare_uint_uint(operands[i].max_abs_value_.pointer(), operands[i].max_abs_value_.uint64_count(), operands[largest_abs_value_index].max_abs_value_.pointer(), operands[largest_abs_value_index].max_abs_value_.uint64_count() > 0))
            {
                largest_abs_value_index = i;
            }
        }

        int sum_max_abs_value_bit_count = operands[largest_abs_value_index].max_abs_value_.significant_bit_count() + get_significant_bit_count(operands.size());
        int sum_max_abs_value_uint64_count = divide_round_up(sum_max_abs_value_bit_count, bits_per_uint64);
        Pointer sum_max_abs_value(allocate_zero_uint(sum_max_abs_value_uint64_count, pool_));

        vector<Computation*> comps;
        for (vector<ChooserPoly>::size_type i = 0; i < operands.size(); ++i)
        {
            add_uint_uint(operands[i].max_abs_value_.pointer(), operands[i].max_abs_value_.uint64_count(), sum_max_abs_value.get(), sum_max_abs_value_uint64_count, false, sum_max_abs_value_uint64_count, sum_max_abs_value.get());
            comps.push_back(operands[i].comp_);
        }

        return ChooserPoly(sum_max_coeff_count, BigUInt(sum_max_abs_value_bit_count, sum_max_abs_value.get()), new AddManyComputation(comps));
    }
示例#13
0
    ChooserPoly ChooserEvaluator::add_many(const std::vector<ChooserPoly> &operands)
    {
        if (operands.empty())
        {
            throw invalid_argument("operands vector can not be empty");
        }

        int sum_max_coeff_count = operands[0].max_coeff_count_;
        size_t largest_abs_value_index = 0;
        for (size_t i = 0; i < operands.size(); i++)
        {
            // Throw if any of the operands is not initialized correctly
            if (operands[i].max_coeff_count_ <= 0 || operands[i].comp_ == nullptr)
            {
                throw invalid_argument("input operand is not correctly initialized");
            }

            if (operands[i].max_coeff_count_ > sum_max_coeff_count)
            {
                sum_max_coeff_count = operands[i].max_coeff_count_;
            }
            if (operands[i].max_abs_value_ > operands[largest_abs_value_index].max_abs_value_)
            {
                largest_abs_value_index = i;
            }
        }

        uint64_t sum_max_abs_value = 0;
        vector<Computation*> comps;
        for (size_t i = 0; i < operands.size(); i++)
        {
            sum_max_abs_value += operands[i].max_abs_value_;
            comps.emplace_back(operands[i].comp_);
        }

        return ChooserPoly(sum_max_coeff_count, 
            sum_max_abs_value, 
            new AddManyComputation(comps));
    }
示例#14
0
    ChooserPoly ChooserEvaluator::multiply_many(
        const vector<ChooserPoly> &operands, int decomposition_bit_count)
    {
        if (operands.empty())
        {
            throw invalid_argument("operands vector can not be empty");
        }

        // Check that decomposition_bit_count is in correct interval
        if (decomposition_bit_count < SEAL_DBC_MIN || 
            decomposition_bit_count > SEAL_DBC_MAX)
        {
            throw invalid_argument("decomposition_bit_count is not in the valid range");
        }

        int prod_max_coeff_count = 1;
        uint64_t growth_factor = 1;
        int prod_max_abs_value_bit_count = 1;
        vector<Computation*> comps;
        for (size_t i = 0; i < operands.size(); i++)
        {
            // Throw if any of the operands is not initialized correctly
            if (operands[i].max_coeff_count_ <= 0 || operands[i].comp_ == nullptr)
            {
                throw invalid_argument("input operand is not correctly initialized");
            }

            // Return early if the product is trivially zero
            if (operands[i].max_abs_value_ == 0)
            {
                return ChooserPoly(1, 0, 
                    new MultiplyManyComputation(comps, 
                        decomposition_bit_count));
            }

            prod_max_coeff_count += operands[i].max_coeff_count_ - 1;
            prod_max_abs_value_bit_count += 
                get_significant_bit_count(operands[i].max_abs_value_);

            growth_factor *= (i == 0 ? 1 : 
                min(operands[i].max_coeff_count_, prod_max_coeff_count));

            comps.emplace_back(operands[i].comp_);
        }

        prod_max_abs_value_bit_count += get_significant_bit_count(growth_factor);
        if (prod_max_abs_value_bit_count >= bits_per_uint64)
        {
            throw invalid_argument("polynomial coefficients too large");
        }

        uint64_t prod_max_abs_value = growth_factor;
        for (size_t i = 0; i < operands.size(); i++)
        {
            prod_max_abs_value *= operands[i].max_abs_value_;
        }

        return ChooserPoly(prod_max_coeff_count, 
            prod_max_abs_value, 
            new MultiplyManyComputation(comps, 
                decomposition_bit_count));
    }