Skip to content

Commit 14e94eb

Browse files
committed
chore: add implementation and tests for more linear relation operations.
1 parent 83f20f7 commit 14e94eb

File tree

6 files changed

+205
-89
lines changed

6 files changed

+205
-89
lines changed

src/linear_relation/convert.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,5 +153,4 @@ impl<G: Group> From<Sum<Weighted<GroupVar<G>, G::Scalar>>> for Sum<Weighted<Term
153153
let sum = sum.0.into_iter().map(|x| x.into()).collect::<Vec<_>>();
154154
Self(sum)
155155
}
156-
157-
}
156+
}

src/linear_relation/mod.rs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use ff::Field;
1717
use group::prime::PrimeGroup;
1818

1919
use crate::codec::Shake128DuplexSponge;
20-
use crate::errors::Error;
20+
use crate::errors::{Error, InvalidInstance};
2121
use crate::schnorr_protocol::SchnorrProof;
2222
use crate::Nizk;
2323

@@ -159,15 +159,11 @@ impl<G: PrimeGroup> GroupMap<G> {
159159
/// Get the element value assigned to the given point var.
160160
///
161161
/// Returns [`Error::UnassignedGroupVar`] if a value is not assigned.
162-
pub fn get(&self, var: GroupVar<G>) -> Result<G, Error> {
162+
pub fn get(&self, var: GroupVar<G>) -> Result<G, InvalidInstance> {
163163
match self.0.get(var.0) {
164164
Some(Some(elem)) => Ok(*elem),
165-
Some(None) => Err(Error::UnassignedGroupVar {
166-
var_debug: format!("{var:?}"),
167-
}),
168-
None => Err(Error::UnassignedGroupVar {
169-
var_debug: format!("{var:?}"),
170-
}),
165+
Some(None) => Err(InvalidInstance::new("unassigned group variable")),
166+
None => Err(InvalidInstance::new("unassigned group variable")),
171167
}
172168
}
173169

@@ -310,7 +306,7 @@ impl<G: PrimeGroup> LinearMap<G> {
310306
let elements =
311307
lc.0.iter()
312308
.map(|weighted| self.group_elements.get(weighted.term.elem))
313-
.collect::<Result<Vec<_>, Error>>()?;
309+
.collect::<Result<Vec<_>, _>>()?;
314310
Ok(msm_pr(&weighted_coefficients, &elements))
315311
})
316312
.collect()
@@ -369,7 +365,7 @@ impl<G: PrimeGroup> CanonicalLinearRelation<G> {
369365
weight: &G::Scalar,
370366
original_group_elements: &GroupMap<G>,
371367
weighted_group_cache: &mut HashMap<GroupVar<G>, Vec<(G::Scalar, GroupVar<G>)>>,
372-
) -> Result<GroupVar<G>, Error> {
368+
) -> Result<GroupVar<G>, InvalidInstance> {
373369
// Check if we already have this (weight, group_var) combination
374370
let entry = weighted_group_cache.entry(group_var).or_default();
375371

@@ -398,7 +394,7 @@ impl<G: PrimeGroup> CanonicalLinearRelation<G> {
398394
equation: &LinearCombination<G>,
399395
original_relation: &LinearRelation<G>,
400396
weighted_group_cache: &mut HashMap<GroupVar<G>, Vec<(G::Scalar, GroupVar<G>)>>,
401-
) -> Result<(), Error> {
397+
) -> Result<(), InvalidInstance> {
402398
let mut rhs_terms = Vec::new();
403399

404400
// Collect RHS terms that have scalar variables and apply weights
@@ -667,24 +663,28 @@ impl<G: PrimeGroup> CanonicalLinearRelation<G> {
667663
}
668664

669665
impl<G: PrimeGroup> TryFrom<&LinearRelation<G>> for CanonicalLinearRelation<G> {
670-
type Error = Error;
666+
type Error = InvalidInstance;
671667

672668
fn try_from(relation: &LinearRelation<G>) -> Result<Self, Self::Error> {
673-
// Number of equations and image variables must match
674669
if relation.image.len() != relation.linear_map.linear_combinations.len() {
675-
return Err(Error::InvalidInstanceWitnessPair);
670+
return Err(InvalidInstance::new(
671+
"Equations and image elements must match",
672+
));
676673
}
677674

678-
// If the image is the identity, then the relation must be trivial, or else the proof will be unsound
679675
if !relation
680676
.image()
681677
.is_ok_and(|img| img.iter().all(|&x| x != G::identity()))
682678
{
683-
return Err(Error::InvalidInstanceWitnessPair);
679+
return Err(InvalidInstance::new(
680+
"Image contains identity element"
681+
));
684682
}
685-
// Empty relations (without constraints) cannot be proven
683+
686684
if relation.linear_map.linear_combinations.is_empty() {
687-
return Err(Error::InvalidInstanceWitnessPair);
685+
return Err(InvalidInstance::new(
686+
"Empty relations cannot be proven"
687+
));
688688
}
689689

690690
// If any linear combination is empty, the relation is invalid
@@ -694,21 +694,19 @@ impl<G: PrimeGroup> TryFrom<&LinearRelation<G>> for CanonicalLinearRelation<G> {
694694
.iter()
695695
.any(|lc| lc.0.is_empty())
696696
{
697-
return Err(Error::InvalidInstanceWitnessPair);
697+
return Err(InvalidInstance::new(
698+
"Linear combinations cannot be empty",
699+
));
698700
}
699701

700702
// If any linear combination has no witness variables, the relation is invalid
701-
if relation
702-
.linear_map
703-
.linear_combinations
704-
.iter()
705-
.any(|lc| lc.0.iter().all(|weighted| matches!(weighted.term.scalar, ScalarTerm::Unit)))
706-
{
707-
return Err(Error::InvalidInstanceWitnessPair);
703+
if relation.linear_map.linear_combinations.iter().any(|lc| {
704+
lc.0.iter()
705+
.all(|weighted| matches!(weighted.term.scalar, ScalarTerm::Unit))
706+
}) {
707+
return Err(InvalidInstance::new("A linear combination does not have any witness variables"));
708708
}
709709

710-
711-
712710
let mut canonical = CanonicalLinearRelation::new();
713711
canonical.num_scalars = relation.linear_map.num_scalars;
714712

@@ -878,7 +876,7 @@ impl<G: PrimeGroup> LinearRelation<G> {
878876
let elements =
879877
lc.0.iter()
880878
.map(|weighted| self.linear_map.group_elements.get(weighted.term.elem))
881-
.collect::<Result<Vec<_>, Error>>()?;
879+
.collect::<Result<Vec<_>, _>>()?;
882880
self.linear_map
883881
.group_elements
884882
.assign_element(*lhs, msm_pr(&weighted_coefficients, &elements))
@@ -892,7 +890,7 @@ impl<G: PrimeGroup> LinearRelation<G> {
892890
///
893891
/// A vector of group elements (`Vec<G>`) representing the linear map's image.
894892
// TODO: Should this return GroupMap?
895-
pub fn image(&self) -> Result<Vec<G>, Error> {
893+
pub fn image(&self) -> Result<Vec<G>, InvalidInstance> {
896894
self.image
897895
.iter()
898896
.map(|&var| self.linear_map.group_elements.get(var))

src/linear_relation/ops.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,30 @@ mod add {
268268
rhs + self
269269
}
270270
}
271+
272+
impl<T: Field + Into<G::Scalar>, G: Group> Add<T> for Sum<ScalarVar<G>> {
273+
type Output = Sum<Weighted<ScalarTerm<G>, G::Scalar>>;
274+
275+
fn add(self, rhs: T) -> Self::Output {
276+
// Convert Sum<ScalarVar<G>> to Sum<Weighted<ScalarTerm<G>, G::Scalar>>
277+
let mut weighted_terms = Vec::new();
278+
for var in self.0 {
279+
weighted_terms.push(Weighted {
280+
term: ScalarTerm::from(var),
281+
weight: G::Scalar::ONE,
282+
});
283+
}
284+
let weighted_sum: Sum<Weighted<ScalarTerm<G>, G::Scalar>> = Sum(weighted_terms);
285+
286+
// Convert the scalar to a weighted term
287+
let weighted_scalar = Weighted {
288+
term: ScalarTerm::Unit,
289+
weight: rhs.into(),
290+
};
291+
292+
weighted_sum + weighted_scalar
293+
}
294+
}
271295
}
272296

273297
mod mul {

src/schnorr_protocol.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! a Sigma protocol proving different types of discrete logarithm relations (eg. Schnorr, Pedersen's commitments)
55
//! through a group morphism abstraction (see [Maurer09](https://crypto-test.ethz.ch/publications/files/Maurer09.pdf)).
66
7-
use crate::errors::Error;
7+
use crate::errors::{Error, InvalidInstance};
88
use crate::linear_relation::{CanonicalLinearRelation, LinearRelation};
99
use crate::{
1010
serialization::{
@@ -85,10 +85,10 @@ impl<G: PrimeGroup> SchnorrProof<G> {
8585
}
8686

8787
impl<G: PrimeGroup> TryFrom<LinearRelation<G>> for SchnorrProof<G> {
88-
type Error = Error;
88+
type Error = InvalidInstance;
8989

9090
fn try_from(linear_relation: LinearRelation<G>) -> Result<Self, Self::Error> {
91-
let canonical_linear_relation = (&linear_relation).try_into()?;
91+
let canonical_linear_relation = CanonicalLinearRelation::try_from(&linear_relation)?;
9292
Ok(Self(canonical_linear_relation))
9393
}
9494
}

0 commit comments

Comments
 (0)