use crate::{G, Point, Scalar, g, marker::*, s};
use alloc::vec::Vec;
use rand_core::RngCore;
pub mod scalar {
use super::*;
pub fn eval(
poly: &[Scalar<impl Secrecy, impl ZeroChoice>],
x: Scalar<impl Secrecy, impl ZeroChoice>,
) -> Scalar<Secret, Zero> {
s!(powers(x) .* poly)
}
pub fn to_point_poly<S: Secrecy, Z: ZeroChoice>(
scalar_poly: impl IntoIterator<Item = impl AsRef<Scalar<S, Z>>>,
) -> Vec<Point<Normal, Public, Z>> {
scalar_poly
.into_iter()
.map(|a| g!(a.as_ref() * G).normalize())
.collect()
}
pub fn generate(length: usize, rng: &mut impl RngCore) -> Vec<Scalar> {
(0..length).map(|_| Scalar::random(rng)).collect()
}
pub fn generate_shamir_sharing_poly<Z: ZeroChoice>(
secret: Scalar<Secret, Z>,
length: usize,
rng: &mut impl RngCore,
) -> Vec<Scalar<Secret, Z>> {
if length == 0 {
panic!("threshold cannot be 0");
}
core::iter::once(secret)
.chain((1..length).map(|_| Scalar::random(rng).mark_zero_choice()))
.collect()
}
pub fn trusted_dealer_shamir_sharing(
secret: Scalar<Secret, impl ZeroChoice>,
threshold: usize,
n_shares: usize,
rng: &mut impl RngCore,
) -> impl Iterator<Item = (Scalar<Public>, Scalar<Secret, NonZero>)> {
if n_shares < threshold {
panic!("n_shares must be >= threshold");
}
let poly = generate_shamir_sharing_poly(secret, threshold, rng);
(1..=n_shares).map(move |i| {
let i = Scalar::<Public, Zero>::from(i).non_zero().expect("> 0");
(
i,
eval(&poly, i)
.non_zero()
.expect("computationally unreachable if rng is really random"),
)
})
}
pub fn interpolate_and_eval_poly_at_0(
x_and_y: &[(Scalar<Public>, Scalar<impl Secrecy, impl ZeroChoice>)],
) -> Scalar<Secret, Zero> {
let indices = x_and_y.iter().map(|(index, _)| *index);
x_and_y
.iter()
.map(|(index, secret)| {
let lambda = eval_basis_poly_at_0(*index, indices.clone());
s!(secret * lambda)
})
.fold(s!(0), |interpolated_poly, scaled_basis_poly| {
s!(interpolated_poly + scaled_basis_poly)
})
}
pub fn interpolate<S: Secrecy>(
x_and_y: &[(Scalar<Public>, Scalar<S, impl ZeroChoice>)],
) -> Vec<Scalar<S, Zero>> {
let x_ms = x_and_y.iter().map(|(index, _)| *index);
let mut interpolating_polynomial: Vec<Scalar<S, Zero>> = vec![];
for (x_j, y_j) in x_and_y {
let basis_poly = super::lagrange_basis_poly(*x_j, x_ms.clone());
let scaled_basis_poly = basis_poly
.iter()
.map(|coeff| s!(coeff * y_j))
.collect::<Vec<_>>();
self::add_in_place(&mut interpolating_polynomial, scaled_basis_poly);
}
interpolating_polynomial
}
pub fn mul<S: Secrecy>(
a: &[Scalar<S, impl ZeroChoice>],
b: &[Scalar<S, impl ZeroChoice>],
) -> Vec<Scalar<S, Zero>> {
let mut result = vec![Scalar::zero(); a.len() + b.len() - 1];
for (i, &coeff_a) in a.iter().enumerate() {
for (j, &coeff_b) in b.iter().enumerate() {
result[i + j] = s!(result[i + j] + coeff_a.mark_zero() * coeff_b.mark_zero())
.set_secrecy::<S>();
}
}
result
}
pub fn add_in_place<SA: Secrecy>(
apoly: &mut Vec<Scalar<SA, Zero>>,
bpoly: impl IntoIterator<Item = Scalar<impl Secrecy, impl ZeroChoice>>,
) {
let b = bpoly.into_iter();
for (i, b) in b.enumerate() {
if i == apoly.len() {
apoly.push(b.set_secrecy::<SA>().mark_zero());
} else {
apoly[i] += b;
}
}
}
pub fn add(
apoly: impl IntoIterator<Item = Scalar<impl Secrecy, impl ZeroChoice>>,
bpoly: impl IntoIterator<Item = Scalar<impl Secrecy, impl ZeroChoice>>,
) -> impl Iterator<Item = Scalar<Secret, Zero>> {
let mut a = apoly.into_iter();
let mut b = bpoly.into_iter();
core::iter::from_fn(move || match (a.next(), b.next()) {
(Some(a), Some(b)) => Some(s!(a + b)),
(Some(a), None) => Some(a.mark_zero().secret()),
(None, Some(b)) => Some(b.mark_zero().secret()),
_ => None,
})
}
pub fn negate(poly: &mut [Scalar<impl Secrecy, impl ZeroChoice>]) {
for coeff in poly {
*coeff = -*coeff;
}
}
}
pub mod point {
use super::*;
pub fn eval<T: PointType>(
poly: &[Point<T, Public, impl ZeroChoice>],
x: Scalar<Public, impl ZeroChoice>,
) -> Point<NonNormal, Public, Zero> {
g!(powers(x) .* poly)
}
pub fn add_in_place<SA: Secrecy>(
apoly: &mut Vec<Point<NonNormal, SA, Zero>>,
bpoly: impl IntoIterator<Item = Point<impl PointType, impl Secrecy, impl ZeroChoice>>,
) {
let b = bpoly.into_iter();
for (i, b) in b.enumerate() {
if i == apoly.len() {
apoly.push(b.set_secrecy::<SA>().mark_zero().non_normal());
} else {
apoly[i] += b;
}
}
}
pub fn add(
poly1: impl IntoIterator<Item = Point<impl PointType, impl Secrecy, impl ZeroChoice>>,
poly2: impl IntoIterator<Item = Point<impl PointType, impl Secrecy, impl ZeroChoice>>,
) -> impl Iterator<Item = Point<NonNormal, Public, Zero>> {
let mut poly1 = poly1.into_iter();
let mut poly2 = poly2.into_iter();
core::iter::from_fn(move || match (poly1.next(), poly2.next()) {
(Some(a), Some(b)) => Some(g!(a + b)),
(Some(a), None) => Some(a.mark_zero().public().non_normal()),
(None, Some(b)) => Some(b.mark_zero().public().non_normal()),
_ => None,
})
}
#[allow(clippy::type_complexity)]
pub fn interpolate(
index_and_point: &[(
Scalar<Public, impl ZeroChoice>,
Point<impl PointType, impl Secrecy, impl ZeroChoice>,
)],
) -> Vec<Point<NonNormal, Public, Zero>> {
let x_ms = index_and_point.iter().map(|(index, _)| *index);
let mut interpolating_polynomial: Vec<Point<NonNormal, Public, Zero>> = vec![];
for (x_j, y_j) in index_and_point {
let basis_poly = super::lagrange_basis_poly(*x_j, x_ms.clone());
let point_scaled_basis_poly = basis_poly
.iter()
.map(|coeff| g!(coeff * y_j))
.collect::<Vec<_>>();
self::add_in_place(&mut interpolating_polynomial, point_scaled_basis_poly);
}
while interpolating_polynomial.len() > 1
&& interpolating_polynomial.last().unwrap().is_zero()
{
interpolating_polynomial.pop();
}
interpolating_polynomial
}
pub fn negate<T>(poly: &mut [Point<T, impl Secrecy, impl ZeroChoice>])
where
T: PointType<NegationType = T>,
{
for coeff in poly {
*coeff = -*coeff;
}
}
pub fn normalize<S, Z>(
poly: impl IntoIterator<Item = Point<impl PointType, S, Z>>,
) -> impl Iterator<Item = Point<Normal, S, Z>> {
poly.into_iter().map(|point| point.normalize())
}
}
fn powers<S: Secrecy, Z: ZeroChoice>(x: Scalar<S, Z>) -> impl Iterator<Item = Scalar<S, Z>> {
core::iter::successors(Some(Scalar::one().mark_zero_choice::<Z>()), move |xpow| {
Some(s!(xpow * x).set_secrecy())
})
}
pub fn eval_basis_poly_at_0(
x_j: Scalar<impl Secrecy>,
x_ms: impl IntoIterator<Item = Scalar<impl Secrecy>>,
) -> Scalar<Public> {
let (num, denom) = x_ms.into_iter().filter(|x_m| *x_m != x_j).fold(
(Scalar::<Public, _>::one(), Scalar::<Public, _>::one()),
|(mut numerator, mut denominator), x_m| {
numerator *= x_m;
denominator *= s!(x_m - x_j).non_zero().expect("x_m != x_j");
(numerator, denominator)
},
);
s!(num / denom).public()
}
pub fn lagrange_basis_poly(
x_j: Scalar<Public, impl ZeroChoice>,
x_ms: impl IntoIterator<Item = Scalar<Public, impl ZeroChoice>>,
) -> Vec<Scalar<Public, Zero>> {
let mut result = vec![s!(1).public().mark_zero()];
for x_m in x_ms.into_iter() {
if x_m == x_j {
continue;
}
let a_m = s!(x_j - x_m)
.non_zero()
.expect("x_m == x_j excluded")
.invert()
.mark_zero()
.public();
let b_m = s!(-x_m * a_m).mark_zero().public();
result = scalar::mul(&result[..], &[b_m, a_m]);
}
result
}