Skip to content

Commit 9e912a3

Browse files
committed
Add component_sub_point to composer
1 parent 0e75be5 commit 9e912a3

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Add component to subtract points in-circuit [#842]
13+
1014
## [0.20.2] - 2024-11-14
1115

1216
### Changed
@@ -601,6 +605,7 @@ is necessary since `rkyv/validation` was required as a bound.
601605
- Proof system module.
602606

603607
<!-- ISSUES -->
608+
[#842]: https://github.com/dusk-network/plonk/issues/842
604609
[#834]: https://github.com/dusk-network/plonk/issues/834
605610
[#831]: https://github.com/dusk-network/plonk/issues/831
606611
[#819]: https://github.com/dusk-network/plonk/issues/819

src/composer.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,23 @@ impl Composer {
749749
);
750750
}
751751

752+
/// Subtracts a curve point from another by consuming 3 gates.
753+
pub fn component_sub_point(
754+
&mut self,
755+
a: WitnessPoint,
756+
b: WitnessPoint,
757+
) -> WitnessPoint {
758+
// We negate the 'x' coordinate of the point 'b', so that neg_b = (-b.x,
759+
// b.y)
760+
let constraint = Constraint::new().left(-BlsScalar::one()).a(*b.x());
761+
let neg_b_x = self.gate_mul(constraint);
762+
763+
let neg_b = WitnessPoint::new(neg_b_x, *b.y());
764+
765+
// We perform a - b = (a.x, a.y) + (-b.x, b.y)
766+
self.component_add_point(a, neg_b)
767+
}
768+
752769
/// Adds two curve points by consuming 2 gates.
753770
pub fn component_add_point(
754771
&mut self,

tests/ecc.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,90 @@ fn component_add_point() {
108108
check_unsatisfied_circuit(&prover, &circuit, &mut rng, msg);
109109
}
110110

111+
#[test]
112+
fn component_sub_point() {
113+
pub struct TestCircuit {
114+
p1: JubJubExtended,
115+
p2: JubJubExtended,
116+
sub: JubJubExtended,
117+
}
118+
119+
impl TestCircuit {
120+
pub fn new(
121+
p1: JubJubExtended,
122+
p2: JubJubExtended,
123+
sub: JubJubExtended,
124+
) -> Self {
125+
Self { p1, p2, sub }
126+
}
127+
}
128+
129+
impl Default for TestCircuit {
130+
fn default() -> Self {
131+
let p1 = JubJubExtended::identity();
132+
let p2 = JubJubExtended::identity();
133+
let sub = JubJubExtended::identity();
134+
Self::new(p1.into(), p2.into(), sub.into())
135+
}
136+
}
137+
138+
impl Circuit for TestCircuit {
139+
fn circuit(&self, composer: &mut Composer) -> Result<(), Error> {
140+
let w_p1 = composer.append_point(self.p1);
141+
let w_p2 = composer.append_point(self.p2);
142+
let w_sub = composer.append_point(self.sub);
143+
144+
let sub_circuit = composer.component_sub_point(w_p1, w_p2);
145+
146+
composer.assert_equal_point(w_sub, sub_circuit);
147+
148+
Ok(())
149+
}
150+
}
151+
152+
// Compile common circuit descriptions for the prover and verifier to be
153+
// used by all tests
154+
let label = b"component_sub_point";
155+
let mut rng = StdRng::seed_from_u64(0xcafe);
156+
let capacity = 1 << 4;
157+
let pp = PublicParameters::setup(capacity, &mut rng)
158+
.expect("Creation of public parameter shouldn't fail");
159+
let (prover, verifier) = Compiler::compile::<TestCircuit>(&pp, label)
160+
.expect("Circuit should compile");
161+
162+
// Test default works:
163+
let msg = "Default circuit verification should pass";
164+
let circuit = TestCircuit::default();
165+
let pi = vec![];
166+
check_satisfied_circuit(&prover, &verifier, &pi, &circuit, &mut rng, &msg);
167+
168+
// Test identity works:
169+
let msg = "Random point subtraction should satisfy the circuit";
170+
let p1 = dusk_jubjub::GENERATOR_EXTENDED * &JubJubScalar::random(&mut rng);
171+
let p2 = JubJubExtended::identity();
172+
let sub = p1.clone();
173+
let circuit = TestCircuit::new(p1, p2, sub);
174+
let pi = vec![];
175+
check_satisfied_circuit(&prover, &verifier, &pi, &circuit, &mut rng, &msg);
176+
177+
// Test random works:
178+
let msg = "Random point subtraction should satisfy the circuit";
179+
let p1 = dusk_jubjub::GENERATOR_EXTENDED * &JubJubScalar::random(&mut rng);
180+
let p2 = dusk_jubjub::GENERATOR_EXTENDED * &JubJubScalar::random(&mut rng);
181+
let sub = p1 - p2;
182+
let circuit = TestCircuit::new(p1, p2, sub);
183+
let pi = vec![];
184+
check_satisfied_circuit(&prover, &verifier, &pi, &circuit, &mut rng, &msg);
185+
186+
// Unsatisfied circuit
187+
let msg = "Unsatisfied circuit should not pass";
188+
let p1 = dusk_jubjub::GENERATOR_EXTENDED * &JubJubScalar::from(0xdecafu64);
189+
let p2 = dusk_jubjub::GENERATOR_EXTENDED * &JubJubScalar::from(0xcafeu64);
190+
let sub = dusk_jubjub::GENERATOR_EXTENDED * &JubJubScalar::from(0xcabu64);
191+
let circuit = TestCircuit::new(p1, p2, sub);
192+
check_unsatisfied_circuit(&prover, &circuit, &mut rng, msg);
193+
}
194+
111195
#[test]
112196
fn component_mul_generator() {
113197
pub struct TestCircuit {

0 commit comments

Comments
 (0)