fullcodec_plonk/constraint_system/
ecc.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7/// Curve addition gate
8pub mod curve_addition;
9/// Gates related to scalar multiplication
10pub mod scalar_mul;
11
12use crate::constraint_system::{TurboComposer, Witness};
13use dusk_bls12_381::BlsScalar;
14use dusk_jubjub::JubJubAffine;
15
16/// Represents a JubJub point in the circuit
17#[derive(Debug, Clone, Copy)]
18pub struct WitnessPoint {
19    x: Witness,
20    y: Witness,
21}
22
23impl WitnessPoint {
24    /// Return the X coordinate of the point
25    pub const fn x(&self) -> &Witness {
26        &self.x
27    }
28
29    /// Return the Y coordinate of the point
30    pub const fn y(&self) -> &Witness {
31        &self.y
32    }
33}
34
35impl TurboComposer {
36    /// Appends a point in affine form as [`WitnessPoint`]
37    pub fn append_point<P: Into<JubJubAffine>>(
38        &mut self,
39        affine: P,
40    ) -> WitnessPoint {
41        let affine = affine.into();
42
43        let x = self.append_witness(affine.get_x());
44        let y = self.append_witness(affine.get_y());
45
46        WitnessPoint { x, y }
47    }
48
49    /// Appends a point in affine form as [`WitnessPoint`]
50    ///
51    /// Creates two public inputs as `(x, y)`
52    pub fn append_public_point<P: Into<JubJubAffine>>(
53        &mut self,
54        affine: P,
55    ) -> WitnessPoint {
56        let affine = affine.into();
57        let point = self.append_point(affine);
58
59        self.assert_equal_constant(
60            point.x,
61            BlsScalar::zero(),
62            Some(-affine.get_x()),
63        );
64
65        self.assert_equal_constant(
66            point.y,
67            BlsScalar::zero(),
68            Some(-affine.get_y()),
69        );
70
71        point
72    }
73
74    /// Constrain a point into the circuit description and return an allocated
75    /// [`WitnessPoint`] with its coordinates
76    pub fn append_constant_point<P: Into<JubJubAffine>>(
77        &mut self,
78        affine: P,
79    ) -> WitnessPoint {
80        let affine = affine.into();
81
82        let x = self.append_constant(affine.get_x());
83        let y = self.append_constant(affine.get_y());
84
85        WitnessPoint { x, y }
86    }
87
88    /// Create an identity [`WitnessPoint`] constrained by the circuit
89    /// description
90    pub fn append_constant_identity(&mut self) -> WitnessPoint {
91        let x = Self::constant_zero();
92        let y = self.append_constant(BlsScalar::one());
93
94        WitnessPoint { x, y }
95    }
96
97    /// Asserts `point == public`.
98    ///
99    /// Will add `public` affine coordinates `(x,y)` as public inputs
100    pub fn assert_equal_public_point<P: Into<JubJubAffine>>(
101        &mut self,
102        point: WitnessPoint,
103        public: P,
104    ) {
105        let public = public.into();
106
107        self.assert_equal_constant(
108            point.x,
109            BlsScalar::zero(),
110            Some(-public.get_x()),
111        );
112
113        self.assert_equal_constant(
114            point.y,
115            BlsScalar::zero(),
116            Some(-public.get_y()),
117        );
118    }
119
120    /// Asserts `a == b` by appending two gates
121    pub fn assert_equal_point(&mut self, a: WitnessPoint, b: WitnessPoint) {
122        self.assert_equal(a.x, b.x);
123        self.assert_equal(b.y, b.y);
124    }
125
126    /// Conditionally selects a [`WitnessPoint`] based on an input bit.
127    ///
128    /// bit == 1 => a,
129    /// bit == 0 => b,
130    ///
131    /// `bit` is expected to be constrained by
132    /// [`TurboComposer::component_boolean`]
133    pub fn component_select_point(
134        &mut self,
135        a: WitnessPoint,
136        b: WitnessPoint,
137        bit: Witness,
138    ) -> WitnessPoint {
139        debug_assert!(
140            self.witnesses[&bit] == BlsScalar::one()
141                || self.witnesses[&bit] == BlsScalar::zero()
142        );
143
144        let x = self.component_select(bit, *a.x(), *b.x());
145        let y = self.component_select(bit, *a.y(), *b.y());
146
147        WitnessPoint { x, y }
148    }
149
150    /// Conditionally selects identity as [`WitnessPoint`] based on an input
151    /// bit.
152    ///
153    /// bit == 1 => a,
154    /// bit == 0 => identity,
155    ///
156    /// `bit` is expected to be constrained by
157    /// [`TurboComposer::component_boolean`]
158    pub fn component_select_identity(
159        &mut self,
160        bit: Witness,
161        a: WitnessPoint,
162    ) -> WitnessPoint {
163        debug_assert!(
164            self.witnesses[&bit] == BlsScalar::one()
165                || self.witnesses[&bit] == BlsScalar::zero()
166        );
167
168        let x = self.component_select_zero(bit, *a.x());
169        let y = self.component_select_one(bit, *a.y());
170
171        WitnessPoint { x, y }
172    }
173}
174
175#[cfg(feature = "std")]
176#[cfg(test)]
177mod tests {
178    use super::*;
179    use crate::constraint_system::helper::*;
180
181    #[test]
182    fn test_component_select_point() {
183        let res = gadget_tester(
184            |composer| {
185                let bit_1 = composer.append_witness(BlsScalar::one());
186                let bit_0 = TurboComposer::constant_zero();
187
188                let point_a = composer.append_constant_identity();
189                let point_b = WitnessPoint {
190                    x: composer.append_witness(BlsScalar::from(10u64)),
191                    y: composer.append_witness(BlsScalar::from(20u64)),
192                };
193
194                let choice =
195                    composer.component_select_point(point_a, point_b, bit_1);
196
197                composer.assert_equal_point(point_a, choice);
198
199                let choice =
200                    composer.component_select_point(point_a, point_b, bit_0);
201                composer.assert_equal_point(point_b, choice);
202            },
203            32,
204        );
205        assert!(res.is_ok());
206    }
207}