use std::{
iter::Sum,
mem::size_of,
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use ark_ec::{
hashing::{
curve_maps::swu::{SWUConfig, SWUMap},
map_to_curve_hasher::MapToCurve,
HashToCurveError,
},
short_weierstrass::Projective,
AffineRepr, CurveGroup,
};
use ark_ff::PrimeField;
use ark_serialize::SerializationError;
use itertools::Itertools;
use serde::{de::Error as DeError, Deserialize, Serialize};
use crate::{
algebra::{
authenticated_curve::AUTHENTICATED_POINT_RESULT_LEN,
authenticated_scalar::AUTHENTICATED_SCALAR_RESULT_LEN,
},
fabric::{ResultHandle, ResultValue},
};
use super::{
authenticated_curve::AuthenticatedPointResult,
authenticated_scalar::AuthenticatedScalarResult,
macros::{impl_borrow_variants, impl_commutative},
mpc_curve::MpcPointResult,
mpc_scalar::MpcScalarResult,
scalar::{n_bytes_field, Scalar, ScalarResult},
};
const MSM_CHUNK_SIZE: usize = 1 << 16;
const MSM_SIZE_THRESHOLD: usize = 10;
pub const HASH_TO_CURVE_SECURITY: usize = 16; #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CurvePoint<C: CurveGroup>(pub(crate) C);
impl<C: CurveGroup> Unpin for CurvePoint<C> {}
impl<C: CurveGroup> Serialize for CurvePoint<C> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let bytes = self.to_bytes();
bytes.serialize(serializer)
}
}
impl<'de, C: CurveGroup> Deserialize<'de> for CurvePoint<C> {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let bytes = <Vec<u8>>::deserialize(deserializer)?;
CurvePoint::from_bytes(&bytes)
.map_err(|err| DeError::custom(format!("Failed to deserialize point: {err:?}")))
}
}
impl<C: CurveGroup> CurvePoint<C> {
pub type BaseField = C::BaseField;
pub type ScalarField = C::ScalarField;
pub fn identity() -> CurvePoint<C> {
CurvePoint(C::zero())
}
pub fn is_identity(&self) -> bool {
self == &CurvePoint::identity()
}
pub fn to_affine(&self) -> C::Affine {
self.0.into_affine()
}
pub fn generator() -> CurvePoint<C> {
CurvePoint(C::generator())
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut out: Vec<u8> = Vec::with_capacity(size_of::<CurvePoint<C>>());
self.0
.serialize_compressed(&mut out)
.expect("Failed to serialize point");
out
}
pub fn from_bytes(bytes: &[u8]) -> Result<CurvePoint<C>, SerializationError> {
let point = C::deserialize_compressed(bytes)?;
Ok(CurvePoint(point))
}
}
impl<C: CurveGroup> CurvePoint<C>
where
C::BaseField: PrimeField,
{
pub fn n_bytes() -> usize {
n_bytes_field::<C::BaseField>()
}
}
impl<C: CurveGroup> CurvePoint<C>
where
C::Config: SWUConfig,
C::BaseField: PrimeField,
{
pub fn from_uniform_bytes(
buf: Vec<u8>,
) -> Result<CurvePoint<Projective<C::Config>>, HashToCurveError> {
let n_bytes = Self::n_bytes();
assert_eq!(
buf.len(),
2 * n_bytes,
"Invalid buffer length, must represent two curve points"
);
let f1 = Self::hash_to_field(&buf[..n_bytes / 2]);
let f2 = Self::hash_to_field(&buf[n_bytes / 2..]);
let mapper = SWUMap::<C::Config>::new()?;
let p1 = mapper.map_to_curve(f1)?;
let p2 = mapper.map_to_curve(f2)?;
let p1_clear = p1.clear_cofactor();
let p2_clear = p2.clear_cofactor();
Ok(CurvePoint(p1_clear + p2_clear))
}
fn hash_to_field(buf: &[u8]) -> C::BaseField {
Self::BaseField::from_be_bytes_mod_order(buf)
}
}
impl<C: CurveGroup> From<C> for CurvePoint<C> {
fn from(p: C) -> Self {
CurvePoint(p)
}
}
impl<C: CurveGroup> Add<&C> for &CurvePoint<C> {
type Output = CurvePoint<C>;
fn add(self, rhs: &C) -> Self::Output {
CurvePoint(self.0 + rhs)
}
}
impl_borrow_variants!(CurvePoint<C>, Add, add, +, C, C: CurveGroup);
impl<C: CurveGroup> Add<&CurvePoint<C>> for &CurvePoint<C> {
type Output = CurvePoint<C>;
fn add(self, rhs: &CurvePoint<C>) -> Self::Output {
CurvePoint(self.0 + rhs.0)
}
}
impl_borrow_variants!(CurvePoint<C>, Add, add, +, CurvePoint<C>, C: CurveGroup);
pub type CurvePointResult<C> = ResultHandle<C, CurvePoint<C>>;
pub type BatchCurvePointResult<C> = ResultHandle<C, Vec<CurvePoint<C>>>;
impl<C: CurveGroup> Add<&CurvePointResult<C>> for &CurvePointResult<C> {
type Output = CurvePointResult<C>;
fn add(self, rhs: &CurvePointResult<C>) -> Self::Output {
self.fabric.new_gate_op(vec![self.id, rhs.id], |args| {
let lhs: CurvePoint<C> = args[0].to_owned().into();
let rhs: CurvePoint<C> = args[1].to_owned().into();
ResultValue::Point(CurvePoint(lhs.0 + rhs.0))
})
}
}
impl_borrow_variants!(CurvePointResult<C>, Add, add, +, CurvePointResult<C>, C: CurveGroup);
impl<C: CurveGroup> Add<&CurvePoint<C>> for &CurvePointResult<C> {
type Output = CurvePointResult<C>;
fn add(self, rhs: &CurvePoint<C>) -> Self::Output {
let rhs = *rhs;
self.fabric.new_gate_op(vec![self.id], move |args| {
let lhs: CurvePoint<C> = args[0].to_owned().into();
ResultValue::Point(CurvePoint(lhs.0 + rhs.0))
})
}
}
impl_borrow_variants!(CurvePointResult<C>, Add, add, +, CurvePoint<C>, C: CurveGroup);
impl_commutative!(CurvePointResult<C>, Add, add, +, CurvePoint<C>, C: CurveGroup);
impl<C: CurveGroup> CurvePointResult<C> {
pub fn batch_add(
a: &[CurvePointResult<C>],
b: &[CurvePointResult<C>],
) -> Vec<CurvePointResult<C>> {
assert_eq!(
a.len(),
b.len(),
"batch_add cannot compute on vectors of unequal length"
);
let n = a.len();
let fabric = a[0].fabric();
let all_ids = a.iter().chain(b.iter()).map(|r| r.id).collect_vec();
fabric.new_batch_gate_op(all_ids, n , move |mut args| {
let a = args.drain(..n).map(CurvePoint::from).collect_vec();
let b = args.into_iter().map(CurvePoint::from).collect_vec();
a.into_iter()
.zip(b.into_iter())
.map(|(a, b)| a + b)
.map(ResultValue::Point)
.collect_vec()
})
}
}
impl<C: CurveGroup> AddAssign for CurvePoint<C> {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl<C: CurveGroup> Sub<&CurvePoint<C>> for &CurvePoint<C> {
type Output = CurvePoint<C>;
fn sub(self, rhs: &CurvePoint<C>) -> Self::Output {
CurvePoint(self.0 - rhs.0)
}
}
impl_borrow_variants!(CurvePoint<C>, Sub, sub, -, CurvePoint<C>, C: CurveGroup);
impl<C: CurveGroup> Sub<&CurvePointResult<C>> for &CurvePointResult<C> {
type Output = CurvePointResult<C>;
fn sub(self, rhs: &CurvePointResult<C>) -> Self::Output {
self.fabric.new_gate_op(vec![self.id, rhs.id], |args| {
let lhs: CurvePoint<C> = args[0].to_owned().into();
let rhs: CurvePoint<C> = args[1].to_owned().into();
ResultValue::Point(CurvePoint(lhs.0 - rhs.0))
})
}
}
impl_borrow_variants!(CurvePointResult<C>, Sub, sub, -, CurvePointResult<C>, C: CurveGroup);
impl<C: CurveGroup> Sub<&CurvePoint<C>> for &CurvePointResult<C> {
type Output = CurvePointResult<C>;
fn sub(self, rhs: &CurvePoint<C>) -> Self::Output {
let rhs = *rhs;
self.fabric.new_gate_op(vec![self.id], move |args| {
let lhs: CurvePoint<C> = args[0].to_owned().into();
ResultValue::Point(CurvePoint(lhs.0 - rhs.0))
})
}
}
impl_borrow_variants!(CurvePointResult<C>, Sub, sub, -, CurvePoint<C>, C: CurveGroup);
impl<C: CurveGroup> Sub<&CurvePointResult<C>> for &CurvePoint<C> {
type Output = CurvePointResult<C>;
fn sub(self, rhs: &CurvePointResult<C>) -> Self::Output {
let self_owned = *self;
rhs.fabric.new_gate_op(vec![rhs.id], move |args| {
let rhs: CurvePoint<C> = args[0].to_owned().into();
ResultValue::Point(CurvePoint(self_owned.0 - rhs.0))
})
}
}
impl<C: CurveGroup> CurvePointResult<C> {
pub fn batch_sub(
a: &[CurvePointResult<C>],
b: &[CurvePointResult<C>],
) -> Vec<CurvePointResult<C>> {
assert_eq!(
a.len(),
b.len(),
"batch_sub cannot compute on vectors of unequal length"
);
let n = a.len();
let fabric = a[0].fabric();
let all_ids = a.iter().chain(b.iter()).map(|r| r.id).collect_vec();
fabric.new_batch_gate_op(all_ids, n , move |mut args| {
let a = args.drain(..n).map(CurvePoint::from).collect_vec();
let b = args.into_iter().map(CurvePoint::from).collect_vec();
a.into_iter()
.zip(b.into_iter())
.map(|(a, b)| a - b)
.map(ResultValue::Point)
.collect_vec()
})
}
}
impl<C: CurveGroup> SubAssign for CurvePoint<C> {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl<C: CurveGroup> Neg for &CurvePoint<C> {
type Output = CurvePoint<C>;
fn neg(self) -> Self::Output {
CurvePoint(-self.0)
}
}
impl_borrow_variants!(CurvePoint<C>, Neg, neg, -, C: CurveGroup);
impl<C: CurveGroup> Neg for &CurvePointResult<C> {
type Output = CurvePointResult<C>;
fn neg(self) -> Self::Output {
self.fabric.new_gate_op(vec![self.id], |args| {
let lhs: CurvePoint<C> = args[0].to_owned().into();
ResultValue::Point(CurvePoint(-lhs.0))
})
}
}
impl_borrow_variants!(CurvePointResult<C>, Neg, neg, -, C:CurveGroup);
impl<C: CurveGroup> CurvePointResult<C> {
pub fn batch_neg(a: &[CurvePointResult<C>]) -> Vec<CurvePointResult<C>> {
let n = a.len();
let fabric = a[0].fabric();
let all_ids = a.iter().map(|r| r.id).collect_vec();
fabric.new_batch_gate_op(all_ids, n , |args| {
args.into_iter()
.map(CurvePoint::from)
.map(CurvePoint::neg)
.map(ResultValue::Point)
.collect_vec()
})
}
}
impl<C: CurveGroup> Mul<&Scalar<C>> for &CurvePoint<C> {
type Output = CurvePoint<C>;
fn mul(self, rhs: &Scalar<C>) -> Self::Output {
CurvePoint(self.0 * rhs.0)
}
}
impl_borrow_variants!(CurvePoint<C>, Mul, mul, *, Scalar<C>, C: CurveGroup);
impl_commutative!(CurvePoint<C>, Mul, mul, *, Scalar<C>, C: CurveGroup);
impl<C: CurveGroup> Mul<&Scalar<C>> for &CurvePointResult<C> {
type Output = CurvePointResult<C>;
fn mul(self, rhs: &Scalar<C>) -> Self::Output {
let rhs = *rhs;
self.fabric.new_gate_op(vec![self.id], move |args| {
let lhs: CurvePoint<C> = args[0].to_owned().into();
ResultValue::Point(CurvePoint(lhs.0 * rhs.0))
})
}
}
impl_borrow_variants!(CurvePointResult<C>, Mul, mul, *, Scalar<C>, C: CurveGroup);
impl_commutative!(CurvePointResult<C>, Mul, mul, *, Scalar<C>, C: CurveGroup);
impl<C: CurveGroup> Mul<&ScalarResult<C>> for &CurvePoint<C> {
type Output = CurvePointResult<C>;
fn mul(self, rhs: &ScalarResult<C>) -> Self::Output {
let self_owned = *self;
rhs.fabric.new_gate_op(vec![rhs.id], move |args| {
let rhs: Scalar<C> = args[0].to_owned().into();
ResultValue::Point(CurvePoint(self_owned.0 * rhs.0))
})
}
}
impl_borrow_variants!(CurvePoint<C>, Mul, mul, *, ScalarResult<C>, Output=CurvePointResult<C>, C: CurveGroup);
impl_commutative!(CurvePoint<C>, Mul, mul, *, ScalarResult<C>, Output=CurvePointResult<C>, C: CurveGroup);
impl<C: CurveGroup> Mul<&ScalarResult<C>> for &CurvePointResult<C> {
type Output = CurvePointResult<C>;
fn mul(self, rhs: &ScalarResult<C>) -> Self::Output {
self.fabric.new_gate_op(vec![self.id, rhs.id], |mut args| {
let lhs: CurvePoint<C> = args.remove(0).into();
let rhs: Scalar<C> = args.remove(0).into();
ResultValue::Point(CurvePoint(lhs.0 * rhs.0))
})
}
}
impl_borrow_variants!(CurvePointResult<C>, Mul, mul, *, ScalarResult<C>, C: CurveGroup);
impl_commutative!(CurvePointResult<C>, Mul, mul, *, ScalarResult<C>, C: CurveGroup);
impl<C: CurveGroup> CurvePointResult<C> {
pub fn batch_mul(a: &[ScalarResult<C>], b: &[CurvePointResult<C>]) -> Vec<CurvePointResult<C>> {
assert_eq!(
a.len(),
b.len(),
"batch_mul cannot compute on vectors of unequal length"
);
let n = a.len();
let fabric = a[0].fabric();
let all_ids = a
.iter()
.map(|a| a.id())
.chain(b.iter().map(|b| b.id()))
.collect_vec();
fabric.new_batch_gate_op(all_ids, n , move |mut args| {
let a = args.drain(..n).map(Scalar::from).collect_vec();
let b = args.into_iter().map(CurvePoint::from).collect_vec();
a.into_iter()
.zip(b.into_iter())
.map(|(a, b)| a * b)
.map(ResultValue::Point)
.collect_vec()
})
}
pub fn batch_mul_shared(
a: &[MpcScalarResult<C>],
b: &[CurvePointResult<C>],
) -> Vec<MpcPointResult<C>> {
assert_eq!(
a.len(),
b.len(),
"batch_mul_shared cannot compute on vectors of unequal length"
);
let n = a.len();
let fabric = a[0].fabric();
let all_ids = a
.iter()
.map(|a| a.id())
.chain(b.iter().map(|b| b.id()))
.collect_vec();
fabric
.new_batch_gate_op(all_ids, n , move |mut args| {
let a = args.drain(..n).map(Scalar::from).collect_vec();
let b = args.into_iter().map(CurvePoint::from).collect_vec();
a.into_iter()
.zip(b.into_iter())
.map(|(a, b)| a * b)
.map(ResultValue::Point)
.collect_vec()
})
.into_iter()
.map(MpcPointResult::from)
.collect_vec()
}
pub fn batch_mul_authenticated(
a: &[AuthenticatedScalarResult<C>],
b: &[CurvePointResult<C>],
) -> Vec<AuthenticatedPointResult<C>> {
assert_eq!(
a.len(),
b.len(),
"batch_mul_authenticated cannot compute on vectors of unequal length"
);
let n = a.len();
let fabric = a[0].fabric();
let all_ids = b
.iter()
.map(|b| b.id())
.chain(a.iter().flat_map(|a| a.ids()))
.collect_vec();
let results = fabric.new_batch_gate_op(
all_ids,
AUTHENTICATED_POINT_RESULT_LEN * n, move |mut args| {
let points: Vec<CurvePoint<C>> =
args.drain(..n).map(CurvePoint::from).collect_vec();
let mut results = Vec::with_capacity(AUTHENTICATED_POINT_RESULT_LEN * n);
for (scalars, point) in args
.chunks_exact(AUTHENTICATED_SCALAR_RESULT_LEN)
.zip(points.into_iter())
{
let share = Scalar::from(&scalars[0]);
let mac = Scalar::from(&scalars[1]);
let public_modifier = Scalar::from(&scalars[2]);
results.push(ResultValue::Point(point * share));
results.push(ResultValue::Point(point * mac));
results.push(ResultValue::Point(point * public_modifier));
}
results
},
);
AuthenticatedPointResult::from_flattened_iterator(results.into_iter())
}
}
impl<C: CurveGroup> MulAssign<&Scalar<C>> for CurvePoint<C> {
fn mul_assign(&mut self, rhs: &Scalar<C>) {
self.0 *= rhs.0;
}
}
impl<C: CurveGroup> Sum for CurvePoint<C> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(CurvePoint::identity(), |acc, x| acc + x)
}
}
impl<C: CurveGroup> Sum for CurvePointResult<C> {
fn sum<I: Iterator<Item = Self>>(mut iter: I) -> Self {
let first = iter.next().expect("empty iterator");
iter.fold(first, |acc, x| acc + x)
}
}
impl<C: CurveGroup> CurvePoint<C> {
pub fn msm(scalars: &[Scalar<C>], points: &[CurvePoint<C>]) -> CurvePoint<C> {
assert_eq!(
scalars.len(),
points.len(),
"msm cannot compute on vectors of unequal length"
);
let n = scalars.len();
if n < MSM_SIZE_THRESHOLD {
return scalars.iter().zip(points.iter()).map(|(s, p)| s * p).sum();
}
let affine_points = points.iter().map(|p| p.0.into_affine()).collect_vec();
let stripped_scalars = scalars.iter().map(|s| s.0).collect_vec();
C::msm(&affine_points, &stripped_scalars)
.map(CurvePoint)
.unwrap()
}
pub fn msm_iter<I, J>(scalars: I, points: J) -> CurvePoint<C>
where
I: IntoIterator<Item = Scalar<C>>,
J: IntoIterator<Item = CurvePoint<C>>,
{
let mut res = CurvePoint::identity();
for (scalar_chunk, point_chunk) in scalars
.into_iter()
.chunks(MSM_CHUNK_SIZE)
.into_iter()
.zip(points.into_iter().chunks(MSM_CHUNK_SIZE).into_iter())
{
let scalars: Vec<Scalar<C>> = scalar_chunk.collect();
let points: Vec<CurvePoint<C>> = point_chunk.collect();
let chunk_res = CurvePoint::msm(&scalars, &points);
res += chunk_res;
}
res
}
pub fn msm_results(
scalars: &[ScalarResult<C>],
points: &[CurvePoint<C>],
) -> CurvePointResult<C> {
assert_eq!(
scalars.len(),
points.len(),
"msm cannot compute on vectors of unequal length"
);
let fabric = scalars[0].fabric();
let scalar_ids = scalars.iter().map(|s| s.id()).collect_vec();
let points = points.to_vec();
fabric.new_gate_op(scalar_ids, move |args| {
let scalars = args.into_iter().map(Scalar::from).collect_vec();
ResultValue::Point(CurvePoint::msm(&scalars, &points))
})
}
pub fn msm_results_iter<I, J>(scalars: I, points: J) -> CurvePointResult<C>
where
I: IntoIterator<Item = ScalarResult<C>>,
J: IntoIterator<Item = CurvePoint<C>>,
{
Self::msm_results(
&scalars.into_iter().collect_vec(),
&points.into_iter().collect_vec(),
)
}
pub fn msm_authenticated(
scalars: &[AuthenticatedScalarResult<C>],
points: &[CurvePoint<C>],
) -> AuthenticatedPointResult<C> {
assert_eq!(
scalars.len(),
points.len(),
"msm cannot compute on vectors of unequal length"
);
let n = scalars.len();
let fabric = scalars[0].fabric();
let scalar_ids = scalars.iter().flat_map(|s| s.ids()).collect_vec();
let points = points.to_vec();
let res: Vec<CurvePointResult<C>> = fabric.new_batch_gate_op(
scalar_ids,
AUTHENTICATED_SCALAR_RESULT_LEN, move |args| {
let mut shares = Vec::with_capacity(n);
let mut macs = Vec::with_capacity(n);
let mut modifiers = Vec::with_capacity(n);
for chunk in args.chunks_exact(AUTHENTICATED_SCALAR_RESULT_LEN) {
shares.push(Scalar::from(chunk[0].to_owned()));
macs.push(Scalar::from(chunk[1].to_owned()));
modifiers.push(Scalar::from(chunk[2].to_owned()));
}
vec![
CurvePoint::msm(&shares, &points),
CurvePoint::msm(&macs, &points),
CurvePoint::msm(&modifiers, &points),
]
.into_iter()
.map(ResultValue::Point)
.collect_vec()
},
);
AuthenticatedPointResult {
share: res[0].to_owned().into(),
mac: res[1].to_owned().into(),
public_modifier: res[2].to_owned(),
}
}
pub fn msm_authenticated_iter<I, J>(scalars: I, points: J) -> AuthenticatedPointResult<C>
where
I: IntoIterator<Item = AuthenticatedScalarResult<C>>,
J: IntoIterator<Item = CurvePoint<C>>,
{
let scalars: Vec<AuthenticatedScalarResult<C>> = scalars.into_iter().collect();
let points: Vec<CurvePoint<C>> = points.into_iter().collect();
Self::msm_authenticated(&scalars, &points)
}
}
impl<C: CurveGroup> CurvePointResult<C> {
pub fn msm_results(
scalars: &[ScalarResult<C>],
points: &[CurvePointResult<C>],
) -> CurvePointResult<C> {
assert!(!scalars.is_empty(), "msm cannot compute on an empty vector");
assert_eq!(
scalars.len(),
points.len(),
"msm cannot compute on vectors of unequal length"
);
let n = scalars.len();
let fabric = scalars[0].fabric();
let all_ids = scalars
.iter()
.map(|s| s.id())
.chain(points.iter().map(|p| p.id()))
.collect_vec();
fabric.new_gate_op(all_ids, move |mut args| {
let scalars = args.drain(..n).map(Scalar::from).collect_vec();
let points = args.into_iter().map(CurvePoint::from).collect_vec();
let res = CurvePoint::msm(&scalars, &points);
ResultValue::Point(res)
})
}
pub fn msm_results_iter<I, J>(scalars: I, points: J) -> CurvePointResult<C>
where
I: IntoIterator<Item = ScalarResult<C>>,
J: IntoIterator<Item = CurvePointResult<C>>,
{
Self::msm_results(
&scalars.into_iter().collect_vec(),
&points.into_iter().collect_vec(),
)
}
pub fn msm_authenticated(
scalars: &[AuthenticatedScalarResult<C>],
points: &[CurvePointResult<C>],
) -> AuthenticatedPointResult<C> {
assert_eq!(
scalars.len(),
points.len(),
"msm cannot compute on vectors of unequal length"
);
let n = scalars.len();
let fabric = scalars[0].fabric();
let all_ids = scalars
.iter()
.flat_map(|s| s.ids())
.chain(points.iter().map(|p| p.id()))
.collect_vec();
let res = fabric.new_batch_gate_op(
all_ids,
AUTHENTICATED_POINT_RESULT_LEN, move |mut args| {
let mut shares = Vec::with_capacity(n);
let mut macs = Vec::with_capacity(n);
let mut modifiers = Vec::with_capacity(n);
for mut chunk in args
.drain(..AUTHENTICATED_SCALAR_RESULT_LEN * n)
.map(Scalar::from)
.chunks(AUTHENTICATED_SCALAR_RESULT_LEN)
.into_iter()
{
shares.push(chunk.next().unwrap());
macs.push(chunk.next().unwrap());
modifiers.push(chunk.next().unwrap());
}
let points = args.into_iter().map(CurvePoint::from).collect_vec();
vec![
CurvePoint::msm(&shares, &points),
CurvePoint::msm(&macs, &points),
CurvePoint::msm(&modifiers, &points),
]
.into_iter()
.map(ResultValue::Point)
.collect_vec()
},
);
AuthenticatedPointResult {
share: res[0].to_owned().into(),
mac: res[1].to_owned().into(),
public_modifier: res[2].to_owned(),
}
}
pub fn msm_authenticated_iter<I, J>(scalars: I, points: J) -> AuthenticatedPointResult<C>
where
I: IntoIterator<Item = AuthenticatedScalarResult<C>>,
J: IntoIterator<Item = CurvePointResult<C>>,
{
let scalars: Vec<AuthenticatedScalarResult<C>> = scalars.into_iter().collect();
let points: Vec<CurvePointResult<C>> = points.into_iter().collect();
Self::msm_authenticated(&scalars, &points)
}
}
#[cfg(test)]
mod test {
use rand::thread_rng;
use crate::{test_helpers::mock_fabric, test_helpers::TestCurve};
use super::*;
pub type TestCurvePoint = CurvePoint<TestCurve>;
pub fn random_point() -> TestCurvePoint {
let mut rng = thread_rng();
let scalar = Scalar::random(&mut rng);
let point = TestCurvePoint::generator() * scalar;
point * scalar
}
#[tokio::test]
async fn test_point_addition() {
let fabric = mock_fabric();
let p1 = random_point();
let p2 = random_point();
let p1_res = fabric.allocate_point(p1);
let p2_res = fabric.allocate_point(p2);
let res = (p1_res + p2_res).await;
let expected_res = p1 + p2;
assert_eq!(res, expected_res);
fabric.shutdown();
}
#[tokio::test]
async fn test_scalar_mul() {
let fabric = mock_fabric();
let mut rng = thread_rng();
let s1 = Scalar::<TestCurve>::random(&mut rng);
let p1 = random_point();
let s1_res = fabric.allocate_scalar(s1);
let p1_res = fabric.allocate_point(p1);
let res = (s1_res * p1_res).await;
let expected_res = s1 * p1;
assert_eq!(res, expected_res);
fabric.shutdown();
}
#[tokio::test]
async fn test_additive_identity() {
let fabric = mock_fabric();
let p1 = random_point();
let p1_res = fabric.allocate_point(p1);
let identity_res = fabric.curve_identity();
let res = (p1_res + identity_res).await;
let expected_res = p1;
assert_eq!(res, expected_res);
fabric.shutdown();
}
}