Skip to content

Commit a2d2d47

Browse files
committed
Add Sum for nonnative
1 parent c28febd commit a2d2d47

File tree

4 files changed

+137
-28
lines changed

4 files changed

+137
-28
lines changed

src/fields/fp/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ impl<F: PrimeField> AllocatedFp<F> {
142142
/// Add many allocated Fp elements together.
143143
///
144144
/// This does not create any constraints and only creates one linear combination.
145-
pub fn addmany<'a, I: Iterator<Item = &'a Self>>(iter: I) -> Self {
145+
pub fn add_many<'a, I: Iterator<Item = &'a Self>>(iter: I) -> Self {
146146
let mut cs = ConstraintSystemRef::None;
147147
let mut has_value = true;
148148
let mut value = F::zero();
@@ -1062,7 +1062,7 @@ impl<F: PrimeField> AllocVar<F, F> for FpVar<F> {
10621062
impl<'a, F: PrimeField> Sum<&'a FpVar<F>> for FpVar<F> {
10631063
fn sum<I: Iterator<Item = &'a FpVar<F>>>(iter: I) -> FpVar<F> {
10641064
let mut sum_constants = F::zero();
1065-
let sum_variables = FpVar::Var(AllocatedFp::<F>::addmany(iter.filter_map(|x| match x {
1065+
let sum_variables = FpVar::Var(AllocatedFp::<F>::add_many(iter.filter_map(|x| match x {
10661066
FpVar::Constant(c) => {
10671067
sum_constants += c;
10681068
None
@@ -1087,7 +1087,7 @@ impl<F: PrimeField> Sum<FpVar<F>> for FpVar<F> {
10871087
FpVar::Var(v) => Some(v),
10881088
})
10891089
.collect::<Vec<_>>();
1090-
let sum_variables = FpVar::Var(AllocatedFp::<F>::addmany(vars.iter()));
1090+
let sum_variables = FpVar::Var(AllocatedFp::<F>::add_many(vars.iter()));
10911091

10921092
let sum = sum_variables + sum_constants;
10931093
sum

src/fields/nonnative/allocated_field_var.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,48 @@ impl<TargetField: PrimeField, BaseField: PrimeField>
176176
Ok(res)
177177
}
178178

179+
/// Add many allocated elements together.
180+
///
181+
/// This does not create any constraints and only creates #limbs linear combinations.
182+
///
183+
/// If there are 0 items in the iterator, then this returns `Ok(None)`.
184+
pub fn add_many<'a, I: Iterator<Item = &'a Self>>(
185+
iter: I,
186+
) -> Result<Option<Self>, SynthesisError> {
187+
let mut limbs_iter = Vec::new();
188+
let cs;
189+
let mut num_of_additions_over_normal_form = BaseField::zero();
190+
let is_in_the_normal_form = false;
191+
if let Some(first) = iter.next() {
192+
cs = first.cs();
193+
for limb in &first.limbs {
194+
limbs_iter.push(vec![limb]);
195+
}
196+
for elem in iter {
197+
for (cur_limb, limbs) in elem.limbs.iter().zip(limbs_iter) {
198+
limbs.push(cur_limb);
199+
}
200+
num_of_additions_over_normal_form += BaseField::one();
201+
}
202+
let limbs = limbs_iter
203+
.into_iter()
204+
.map(|limbs| limbs.into_iter().sum::<FpVar<_>>())
205+
.collect::<Vec<_>>();
206+
207+
let result = Self {
208+
cs,
209+
limbs,
210+
num_of_additions_over_normal_form,
211+
is_in_the_normal_form,
212+
target_phantom: PhantomData,
213+
};
214+
Reducer::<TargetField, BaseField>::post_add_reduce(&mut result)?;
215+
Ok(Some(result))
216+
} else {
217+
Ok(None)
218+
}
219+
}
220+
179221
/// Subtract a nonnative field element, without the final reduction step
180222
#[tracing::instrument(target = "r1cs")]
181223
pub fn sub_without_reduce(&self, other: &Self) -> R1CSResult<Self> {

src/fields/nonnative/field_var.rs

Lines changed: 88 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use ark_ff::{to_bytes, FpParameters};
1010
use ark_relations::r1cs::Result as R1CSResult;
1111
use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError};
1212
use ark_std::hash::{Hash, Hasher};
13-
use ark_std::{borrow::Borrow, vec::Vec};
13+
use ark_std::{borrow::Borrow, iter::Sum, vec::Vec};
1414

1515
/// A gadget for representing non-native (`TargetField`) field elements over the constraint field (`BaseField`).
1616
#[derive(Clone, Debug)]
@@ -116,11 +116,30 @@ impl<TargetField: PrimeField, BaseField: PrimeField> FieldVar<TargetField, BaseF
116116
}
117117

118118
#[tracing::instrument(target = "r1cs")]
119-
fn negate(&self) -> R1CSResult<Self> {
120-
match self {
121-
Self::Constant(c) => Ok(Self::Constant(-*c)),
122-
Self::Var(v) => Ok(Self::Var(v.negate()?)),
123-
}
119+
fn negate_in_place(&mut self) -> R1CSResult<&mut Self> {
120+
*self = match self {
121+
Self::Constant(c) => Self::Constant(-*c),
122+
Self::Var(v) => Self::Var(v.negate()?),
123+
};
124+
Ok(self)
125+
}
126+
127+
#[tracing::instrument(target = "r1cs")]
128+
fn double_in_place(&mut self) -> R1CSResult<&mut Self> {
129+
*self = match self {
130+
Self::Constant(c) => Self::Constant(c.double()),
131+
Self::Var(v) => Self::Var(v.add(&*v)?),
132+
};
133+
Ok(self)
134+
}
135+
136+
#[tracing::instrument(target = "r1cs")]
137+
fn square_in_place(&mut self) -> R1CSResult<&mut Self> {
138+
*self = match self {
139+
Self::Constant(c) => Self::Constant(c.square()),
140+
Self::Var(v) => Self::Var(v.mul(&*v)?),
141+
};
142+
Ok(self)
124143
}
125144

126145
#[tracing::instrument(target = "r1cs")]
@@ -154,15 +173,15 @@ impl_bounded_ops!(
154173
add,
155174
AddAssign,
156175
add_assign,
157-
|this: &'a NonNativeFieldVar<TargetField, BaseField>, other: &'a NonNativeFieldVar<TargetField, BaseField>| {
176+
|this: &mut NonNativeFieldVar<TargetField, BaseField>, other: &'a NonNativeFieldVar<TargetField, BaseField>| {
158177
use NonNativeFieldVar::*;
159-
match (this, other) {
178+
*this = match (&*this, other) {
160179
(Constant(c1), Constant(c2)) => Constant(*c1 + c2),
161180
(Constant(c), Var(v)) | (Var(v), Constant(c)) => Var(v.add_constant(c).unwrap()),
162181
(Var(v1), Var(v2)) => Var(v1.add(v2).unwrap()),
163-
}
182+
};
164183
},
165-
|this: &'a NonNativeFieldVar<TargetField, BaseField>, other: TargetField| { this + &NonNativeFieldVar::Constant(other) },
184+
|this: &mut NonNativeFieldVar<TargetField, BaseField>, other: TargetField| { *this = &*this + &NonNativeFieldVar::Constant(other) },
166185
(TargetField: PrimeField, BaseField: PrimeField),
167186
);
168187

@@ -173,17 +192,17 @@ impl_bounded_ops!(
173192
sub,
174193
SubAssign,
175194
sub_assign,
176-
|this: &'a NonNativeFieldVar<TargetField, BaseField>, other: &'a NonNativeFieldVar<TargetField, BaseField>| {
195+
|this: &mut NonNativeFieldVar<TargetField, BaseField>, other: &'a NonNativeFieldVar<TargetField, BaseField>| {
177196
use NonNativeFieldVar::*;
178-
match (this, other) {
197+
*this = match (&*this, other) {
179198
(Constant(c1), Constant(c2)) => Constant(*c1 - c2),
180199
(Var(v), Constant(c)) => Var(v.sub_constant(c).unwrap()),
181200
(Constant(c), Var(v)) => Var(v.sub_constant(c).unwrap().negate().unwrap()),
182201
(Var(v1), Var(v2)) => Var(v1.sub(v2).unwrap()),
183-
}
202+
};
184203
},
185-
|this: &'a NonNativeFieldVar<TargetField, BaseField>, other: TargetField| {
186-
this - &NonNativeFieldVar::Constant(other)
204+
|this: &mut NonNativeFieldVar<TargetField, BaseField>, other: TargetField| {
205+
*this = &*this - &NonNativeFieldVar::Constant(other)
187206
},
188207
(TargetField: PrimeField, BaseField: PrimeField),
189208
);
@@ -195,20 +214,20 @@ impl_bounded_ops!(
195214
mul,
196215
MulAssign,
197216
mul_assign,
198-
|this: &'a NonNativeFieldVar<TargetField, BaseField>, other: &'a NonNativeFieldVar<TargetField, BaseField>| {
217+
|this: &mut NonNativeFieldVar<TargetField, BaseField>, other: &'a NonNativeFieldVar<TargetField, BaseField>| {
199218
use NonNativeFieldVar::*;
200-
match (this, other) {
219+
*this = match (&*this, other) {
201220
(Constant(c1), Constant(c2)) => Constant(*c1 * c2),
202221
(Constant(c), Var(v)) | (Var(v), Constant(c)) => Var(v.mul_constant(c).unwrap()),
203222
(Var(v1), Var(v2)) => Var(v1.mul(v2).unwrap()),
204223
}
205224
},
206-
|this: &'a NonNativeFieldVar<TargetField, BaseField>, other: TargetField| {
207-
if other.is_zero() {
225+
|this: &mut NonNativeFieldVar<TargetField, BaseField>, other: TargetField| {
226+
*this = if other.is_zero() {
208227
NonNativeFieldVar::zero()
209228
} else {
210-
this * &NonNativeFieldVar::Constant(other)
211-
}
229+
&*this * &NonNativeFieldVar::Constant(other)
230+
};
212231
},
213232
(TargetField: PrimeField, BaseField: PrimeField),
214233
);
@@ -454,6 +473,54 @@ impl<TargetField: PrimeField, BaseField: PrimeField> ToConstraintFieldGadget<Bas
454473
}
455474
}
456475

476+
impl<'a, TargetField: PrimeField, BaseField: PrimeField> Sum<&'a Self>
477+
for NonNativeFieldVar<TargetField, BaseField>
478+
{
479+
fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
480+
let mut sum_constants = TargetField::zero();
481+
let vars = iter
482+
.filter_map(|x| match x {
483+
Self::Constant(c) => {
484+
sum_constants += c;
485+
None
486+
}
487+
Self::Var(v) => Some(v),
488+
})
489+
.collect::<Vec<_>>();
490+
let sum_variables = AllocatedNonNativeFieldVar::add_many(vars.into_iter())
491+
.unwrap()
492+
.map(Self::Var)
493+
.unwrap_or(Self::zero());
494+
495+
let sum = sum_variables + sum_constants;
496+
sum
497+
}
498+
}
499+
500+
impl<TargetField: PrimeField, BaseField: PrimeField> Sum<Self>
501+
for NonNativeFieldVar<TargetField, BaseField>
502+
{
503+
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
504+
let mut sum_constants = TargetField::zero();
505+
let vars = iter
506+
.filter_map(|x| match x {
507+
Self::Constant(c) => {
508+
sum_constants += c;
509+
None
510+
}
511+
Self::Var(v) => Some(v),
512+
})
513+
.collect::<Vec<_>>();
514+
let sum_variables = AllocatedNonNativeFieldVar::add_many(vars.iter())
515+
.unwrap()
516+
.map(Self::Var)
517+
.unwrap_or(Self::zero());
518+
519+
let sum = sum_variables + sum_constants;
520+
sum
521+
}
522+
}
523+
457524
impl<TargetField: PrimeField, BaseField: PrimeField> NonNativeFieldVar<TargetField, BaseField> {
458525
/// The `mul_without_reduce` for `NonNativeFieldVar`
459526
#[tracing::instrument(target = "r1cs")]

src/fields/nonnative/mul_result.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,14 @@ impl_bounded_ops!(
6565
add,
6666
AddAssign,
6767
add_assign,
68-
|this: &'a NonNativeFieldMulResultVar<TargetField, BaseField>, other: &'a NonNativeFieldMulResultVar<TargetField, BaseField>| {
68+
|this: &mut NonNativeFieldMulResultVar<TargetField, BaseField>, other: &'a NonNativeFieldMulResultVar<TargetField, BaseField>| {
6969
use NonNativeFieldMulResultVar::*;
70-
match (this, other) {
70+
*this = match (&*this, other) {
7171
(Constant(c1), Constant(c2)) => Constant(*c1 + c2),
7272
(Constant(c), Var(v)) | (Var(v), Constant(c)) => Var(v.add_constant(c).unwrap()),
7373
(Var(v1), Var(v2)) => Var(v1.add(v2).unwrap()),
74-
}
74+
};
7575
},
76-
|this: &'a NonNativeFieldMulResultVar<TargetField, BaseField>, other: TargetField| { this + &NonNativeFieldMulResultVar::Constant(other) },
76+
|this: &mut NonNativeFieldMulResultVar<TargetField, BaseField>, other: TargetField| { *this = &*this + &NonNativeFieldMulResultVar::Constant(other) },
7777
(TargetField: PrimeField, BaseField: PrimeField),
7878
);

0 commit comments

Comments
 (0)