Skip to content

Commit cb598e3

Browse files
authored
Merge branch 'main' into jl/unconstrained_nibbles
2 parents 6047338 + 2dca59a commit cb598e3

File tree

4 files changed

+175
-23
lines changed

4 files changed

+175
-23
lines changed

Nargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ authors = [""]
55
compiler_version = ">=1.0.0"
66

77
[dependencies]
8-
bignum = { tag = "v0.7.3", git = "https://github.com/noir-lang/noir-bignum" }
8+
bignum = { tag = "v0.7.4", git = "https://github.com/noir-lang/noir-bignum" }
99
poseidon = { git = "https://github.com/noir-lang/poseidon", tag = "v0.1.1" }

src/bigcurve_test.nr

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ fn test_incomplete_add_with_hint() {
322322
}
323323

324324
#[test]
325-
fn test_add() {
325+
fn test_constrained_add() {
326326
unsafe {
327327
let P = BN254::one();
328328

@@ -380,6 +380,73 @@ fn test_add() {
380380
}
381381
}
382382

383+
#[test]
384+
unconstrained fn test_unconstrained_add() {
385+
let P = BN254::one();
386+
387+
// Q = 2P
388+
let Q = BN254 {
389+
x: BN254_Fq::from_limbs([
390+
0x7816a916871ca8d3c208c16d87cfd3,
391+
0x44e72e131a029b85045b68181585d9,
392+
0x0306,
393+
]),
394+
y: BN254_Fq::from_limbs([
395+
0xa6a449e3538fc7ff3ebf7a5a18a2c4,
396+
0x738c0e0a7c92e7845f96b2ae9c0a68,
397+
0x15ed,
398+
]),
399+
is_infinity: false,
400+
};
401+
402+
let result = BN254J::from(P.add(Q));
403+
404+
let P_j = BN254J::from(P);
405+
let Q_j = BN254J::from(Q);
406+
let expected = P_j.add(Q_j).0;
407+
408+
assert(result.eq(expected));
409+
}
410+
#[test]
411+
unconstrained fn test_unconstrained_add_one_side_infinity() {
412+
//Q + infinity and infinity + Q
413+
let Q = BN254::one();
414+
let P = BN254::point_at_infinity();
415+
let expected = BN254J::from(Q);
416+
let result = BN254J::from(Q.add(P));
417+
assert(result.eq(expected));
418+
let result = BN254J::from(P.add(Q));
419+
assert(result.eq(expected));
420+
}
421+
422+
#[test]
423+
unconstrained fn test_unconstrained_add_doubling() {
424+
// P + P
425+
let P = BN254::one();
426+
let Q = BN254::one();
427+
let P_j = BN254J::from(P);
428+
let result = BN254J::from(P.add(Q));
429+
let expected = P_j.dbl().0;
430+
assert(result.eq(expected));
431+
}
432+
433+
#[test]
434+
unconstrained fn test_unconstrained_add_infinity() {
435+
// P = -Q
436+
let P = BN254::one();
437+
let Q = P.neg();
438+
let result = BN254J::from(P.add(Q));
439+
let expected = BN254J::point_at_infinity();
440+
assert(result.eq(expected));
441+
442+
// both at infinity
443+
let P = BN254::point_at_infinity();
444+
let Q = BN254::point_at_infinity();
445+
let result = BN254J::from(Q.add(P));
446+
let expected = BN254J::point_at_infinity();
447+
assert(result.eq(expected));
448+
}
449+
383450
#[test]
384451
fn test_sub() {
385452
unsafe {
@@ -439,6 +506,78 @@ fn test_sub() {
439506
}
440507
}
441508

509+
#[test]
510+
unconstrained fn test_unconstrained_sub() {
511+
let P = BN254::one();
512+
513+
// Q = 2P
514+
let Q = BN254 {
515+
x: BN254_Fq::from_limbs([
516+
0x7816a916871ca8d3c208c16d87cfd3,
517+
0x44e72e131a029b85045b68181585d9,
518+
0x0306,
519+
]),
520+
y: BN254_Fq::from_limbs([
521+
0xa6a449e3538fc7ff3ebf7a5a18a2c4,
522+
0x738c0e0a7c92e7845f96b2ae9c0a68,
523+
0x15ed,
524+
]),
525+
is_infinity: false,
526+
};
527+
528+
let result = BN254J::from(P.sub(Q));
529+
530+
let P_j = BN254J::from(P);
531+
let Q_j = BN254J::from(Q);
532+
let expected = P_j.sub(Q_j).0;
533+
534+
assert(result.eq(expected));
535+
}
536+
537+
#[test]
538+
unconstrained fn test_unconstrained_sub_doubling() {
539+
// doubling
540+
let P = BN254::one();
541+
let Q = BN254::one();
542+
543+
let result = BN254J::from(P.sub(Q.neg()));
544+
let P_j = BN254J::from(P);
545+
let expected = P_j.dbl().0;
546+
assert(result.eq(expected));
547+
}
548+
549+
#[test]
550+
unconstrained fn test_unconstrained_sub_infinity() {
551+
// both at infinity
552+
let P = BN254::one();
553+
let Q = BN254::one();
554+
let result = BN254J::from(P.sub(Q));
555+
let expected = BN254J::point_at_infinity();
556+
assert(result.eq(expected));
557+
// both infinity
558+
let P = BN254::point_at_infinity();
559+
let Q = BN254::point_at_infinity();
560+
let result = BN254J::from(Q.sub(P));
561+
let expected = BN254J::point_at_infinity();
562+
assert(result.eq(expected));
563+
}
564+
565+
#[test]
566+
unconstrained fn test_unconstrained_sub_one_side_infinity() {
567+
let P = BN254::point_at_infinity();
568+
let Q = BN254::one();
569+
570+
// lhs infinity
571+
let result = BN254J::from(P.sub(Q));
572+
let expected = BN254J::from(Q.neg());
573+
assert(result.eq(expected));
574+
575+
// rhs infinity
576+
let result = BN254J::from(Q.sub(P));
577+
let expected = expected.neg();
578+
assert(result.eq(expected));
579+
}
580+
442581
#[test]
443582
fn test_make_table() {
444583
unsafe {

src/curve_jac.nr

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ where
304304
let y_equal_predicate = S2.eq(S1);
305305
let lhs_infinity = self.is_infinity;
306306
let rhs_infinity = p2.is_infinity;
307+
307308
let double_predicate =
308309
x_equal_predicate & y_equal_predicate & !lhs_infinity & !rhs_infinity;
309310
let add_predicate = !x_equal_predicate & !lhs_infinity & !rhs_infinity;
@@ -317,9 +318,13 @@ where
317318
} else if (infinity_predicate) {
318319
result = (CurveJ::point_at_infinity(), JTranscript::new());
319320
} else if (lhs_infinity & !rhs_infinity) {
320-
result = (p2, JTranscript::new());
321+
let new_transcript =
322+
JTranscript { x3: p2.x, y3: p2.y, z3: p2.z, lambda_numerator: B::zero() };
323+
result = (p2, new_transcript);
321324
} else if (rhs_infinity & !lhs_infinity) {
322-
result = (self, JTranscript::new());
325+
let new_transcript =
326+
JTranscript { x3: self.x, y3: self.y, z3: self.z, lambda_numerator: B::zero() };
327+
result = (self, new_transcript);
323328
}
324329
result
325330
// let (_, PP): (B, B ) = B::compute_quadratic_expression([[U2, U1]], [[false, true]], [[U2, U1]], [[false, true]], [], []);

src/lib.nr

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ pub comptime fn derive_curve_impl(
7979
let typ = struct_def.as_type();
8080
let CurveJ = quote { $crate::curve_jac::CurveJ };
8181
let AffineTranscript = quote { $crate::curve_jac::AffineTranscript };
82-
let ScalarField = quote { $crate::scalar_field::ScalarField };
8382

8483
quote {
8584
impl $crate::BigCurve<$field_type> for $typ {
@@ -184,12 +183,16 @@ pub comptime fn derive_curve_impl(
184183
// Expensive witness generation! Avoid if possible
185184
impl std::ops::Add for $typ {
186185
fn add(self, other: Self) -> Self {
187-
let lhsJ = $CurveJ::<$field_type, $typ>::from(self);
188-
let rhsJ = $CurveJ::<$field_type, $typ>::from(other);
189-
190-
let transcript = unsafe { $AffineTranscript::from_j(lhsJ.add(rhsJ).1) };
191-
192-
$crate::add_with_hint::<$field_type, $typ>(self,other, transcript)
186+
let lhsJ = $crate::curve_jac::CurveJ::<$field_type, $typ>::from(self);
187+
let rhsJ = $crate::curve_jac::CurveJ::<$field_type, $typ>::from(other);
188+
let (result_jac, j_transcript) = unsafe { lhsJ.add(rhsJ) };
189+
let transcript = unsafe { $crate::curve_jac::AffineTranscript::from_j(j_transcript) };
190+
if std::runtime::is_unconstrained() {
191+
$typ::from_coordinates(transcript.x3, transcript.y3, result_jac.is_infinity)
192+
193+
} else {
194+
$crate::add_with_hint::<$field_type, $typ>(self, other, transcript)
195+
}
193196
}
194197
}
195198

@@ -204,12 +207,17 @@ pub comptime fn derive_curve_impl(
204207

205208
impl std::ops::Sub for $typ {
206209
fn sub(self, other: Self) -> Self {
207-
let lhsJ = $CurveJ::<$field_type, $typ>::from(self);
208-
let rhsJ = $CurveJ::<$field_type, $typ>::from(other);
209-
210-
let transcript = unsafe { $AffineTranscript::from_j(lhsJ.sub(rhsJ).1) };
211-
212-
$crate::sub_with_hint::<$field_type, $typ>(self, other, transcript)
210+
let lhsJ = $crate::curve_jac::CurveJ::<$field_type, $typ>::from(self);
211+
let rhsJ = $crate::curve_jac::CurveJ::<$field_type, $typ>::from(other);
212+
let (result_jac, j_transcript) = unsafe { lhsJ.sub(rhsJ) };
213+
214+
// Convert back to affine coordinates using the transcript
215+
let transcript = unsafe { $crate::curve_jac::AffineTranscript::from_j(j_transcript) };
216+
if std::runtime::is_unconstrained() {
217+
$typ::from_coordinates(transcript.x3, transcript.y3, result_jac.is_infinity)
218+
} else {
219+
$crate::sub_with_hint::<$field_type, $typ>(self, other, transcript)
220+
}
213221
}
214222
}
215223

@@ -549,10 +557,10 @@ pub(crate) fn add_with_hint<B: BigNum, P: BigCurve<B>>(
549557

550558
// If we are skipping the evaluation of a group operation (x2 == x1, y2 == -y1 OR any input points are at infinity),
551559
// set input operands to 0!
552-
let (x1, y1, x2, y2) = if evaluate_group_operation_predicate {
553-
(x1, y1, x2, y2)
560+
let (x1, y1, x2, y2, x3, y3) = if evaluate_group_operation_predicate {
561+
(x1, y1, x2, y2, x3, y3)
554562
} else {
555-
(B::zero(), B::zero(), B::zero(), B::zero())
563+
(B::zero(), B::zero(), B::zero(), B::zero(), B::zero(), B::zero())
556564
};
557565

558566
// lambda * 2y - 3x * x = 0
@@ -678,10 +686,10 @@ pub(crate) fn sub_with_hint<B: BigNum, P: BigCurve<B>>(
678686

679687
// If we are skipping the evaluation of a group operation (x2 == x1, y2 == -y1 OR any input points are at infinity),
680688
// set input operands to 0!
681-
let (x1, y1, x2, y2) = if evaluate_group_operation_predicate {
682-
(x1, y1, x2, y2)
689+
let (x1, y1, x2, y2, x3, y3) = if evaluate_group_operation_predicate {
690+
(x1, y1, x2, y2, x3, y3)
683691
} else {
684-
(B::zero(), B::zero(), B::zero(), B::zero())
692+
(B::zero(), B::zero(), B::zero(), B::zero(), B::zero(), B::zero())
685693
};
686694

687695
// lambda * 2y - 3x*x = 0

0 commit comments

Comments
 (0)