Skip to content

Commit c6daba5

Browse files
bitzoicxgreenxvaivaswatha
authored
Std-lib support for ZK opcodes (#6832)
## Description This PR adds support for the `ecop` and `epar` opcodes in the std-lib. It also introduces the `Point2D` and `Scalar` type support cryptographic operations. The new crypto module follows the same format as developed in #5747 which is still yet to come, ensuring compatibility. The `Point2D` and `Scalar` types also use `Bytes` under the hood to ensure future curves with points larger than 32 bytes are still supported. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: green <xgreenx9999@gmail.com> Co-authored-by: Vaivaswatha Nagaraj <vaivaswatha.nagaraj@fuel.sh>
1 parent 47e75f7 commit c6daba5

File tree

12 files changed

+1460
-1
lines changed

12 files changed

+1460
-1
lines changed

sway-lib-std/src/crypto.sw

+3
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ pub mod ed25519;
77
pub mod secp256k1;
88
pub mod secp256r1;
99
pub mod signature;
10+
pub mod point2d;
11+
pub mod scalar;
12+
pub mod alt_bn128;

sway-lib-std/src/crypto/alt_bn128.sw

+222
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
library;
2+
3+
use ::vec::*;
4+
use ::bytes::{Bytes, *};
5+
use ::revert::require;
6+
use ::crypto::{point2d::*, scalar::*};
7+
use ::alloc::alloc;
8+
9+
/// The error type used when performing elliptic curve operations for the Alt BN128 curve.
10+
pub enum AltBn128Error {
11+
/// The elliptic curve point used was invalid.
12+
InvalidEllipticCurvePoint: (),
13+
/// The elliptic curve scalar used was invalid.
14+
InvalidEllipticCurveScalar: (),
15+
}
16+
17+
/// Performs an elliptic curve multiplication with a given curve, point, and scalar.
18+
///
19+
/// # Additional Information
20+
///
21+
/// The Fuel VM currently only supports the Alt BN128 curve.
22+
///
23+
/// # Arguments
24+
///
25+
/// * `point`: [Point2D] - The point used to perform the multiplication.
26+
/// * `scalar`: [Scalar] - The scalar used perform the multiplication.
27+
///
28+
/// # Returns
29+
///
30+
/// * [Point2D] - The resulting computed point.
31+
///
32+
/// # Examples
33+
///
34+
/// ```sway
35+
/// use std::{point2d::Point2D, scalar::Scalar, alt_bn128::alt_bn128_mul};
36+
///
37+
/// fn foo(point: Point2D, scalar: Scalar) {
38+
/// let result = alt_bn128_mul(point, scalar);
39+
/// assert(!result.is_zero());
40+
/// }
41+
/// ```
42+
pub fn alt_bn128_mul(point: Point2D, scalar: Scalar) -> Point2D {
43+
require(
44+
valid_alt_bn128_point(point),
45+
AltBn128Error::InvalidEllipticCurvePoint,
46+
);
47+
require(
48+
valid_alt_bn128_scalar(scalar),
49+
AltBn128Error::InvalidEllipticCurveScalar,
50+
);
51+
52+
// 1P = ([32 bytes], [32 bytes])
53+
let mut result = [b256::zero(), b256::zero()];
54+
// 1P1S = (X, Y), Z = ([32 bytes], [32 bytes]), [32 bytes] = 3 * 32 bytes
55+
let mut ptr = alloc::<b256>(3);
56+
point.x().ptr().copy_to::<b256>(ptr.add::<b256>(0), 1);
57+
point.y().ptr().copy_to::<b256>(ptr.add::<b256>(1), 1);
58+
scalar.bytes().ptr().copy_to::<b256>(ptr.add::<b256>(2), 1);
59+
60+
asm(buffer: result, curve: 0, operation: 1, scalar: ptr) {
61+
ecop buffer curve operation scalar;
62+
};
63+
64+
Point2D::from(result)
65+
}
66+
67+
/// Performs an elliptic curve additions with a given curve and 2 points.
68+
///
69+
/// # Additional Information
70+
///
71+
/// The Fuel VM currently only supports the Alt BN128 curve.
72+
///
73+
/// # Arguments
74+
///
75+
/// * `point_1`: [Point2D] - The first point used to perform the addition.
76+
/// * `point_2`: [Point2D] - The second point used to perform the addition.
77+
///
78+
/// # Returns
79+
///
80+
/// * [Point2D] - The resulting computed point.
81+
///
82+
/// # Examples
83+
///
84+
/// ```sway
85+
/// use std::{point2d::Point2D, scalar::Scalar, alt_bn128::alt_bn128_add};
86+
///
87+
/// fn foo(point_1: Point2D, point_2: Point2D) {
88+
/// let result = alt_bn128_add(point_1, point_2);
89+
/// assert(!result.is_zero());
90+
/// }
91+
/// ```
92+
pub fn alt_bn128_add(point_1: Point2D, point_2: Point2D) -> Point2D {
93+
require(
94+
valid_alt_bn128_point(point_1),
95+
AltBn128Error::InvalidEllipticCurvePoint,
96+
);
97+
require(
98+
valid_alt_bn128_point(point_2),
99+
AltBn128Error::InvalidEllipticCurvePoint,
100+
);
101+
102+
// 1P = ([32 bytes], [32 bytes])
103+
let mut result = [b256::zero(), b256::zero()];
104+
// 1P1P = (X, Y), (X, Y) = ([32 bytes], [32 bytes]), ([32 bytes], [32 bytes]) = 4 * 32 bytes
105+
let mut points_ptr = alloc::<b256>(4);
106+
point_1
107+
.x()
108+
.ptr()
109+
.copy_to::<b256>(points_ptr.add::<b256>(0), 1);
110+
point_1
111+
.y()
112+
.ptr()
113+
.copy_to::<b256>(points_ptr.add::<b256>(1), 1);
114+
point_2
115+
.x()
116+
.ptr()
117+
.copy_to::<b256>(points_ptr.add::<b256>(2), 1);
118+
point_2
119+
.y()
120+
.ptr()
121+
.copy_to::<b256>(points_ptr.add::<b256>(3), 1);
122+
123+
asm(buffer: result, curve: 0, operation: 0, points: points_ptr) {
124+
ecop buffer curve operation points;
125+
};
126+
127+
Point2D::from(result)
128+
}
129+
130+
/// Performs an elliptic curve paring check with a given curve and 3 points.
131+
///
132+
/// # Additional Information
133+
///
134+
/// The Fuel VM currently only supports the Alt BN128 curve.
135+
///
136+
/// # Arguments
137+
///
138+
/// * `points`: [Vec<(Point2D, [Point2D; 2])>] - The points used to perform the pairing check.
139+
///
140+
/// # Returns
141+
///
142+
/// * [bool] - True if the pairing is valid, false otherwise.
143+
///
144+
/// # Examples
145+
///
146+
/// ```sway
147+
/// use std::{point2d::Point2D, scalar::Scalar, alt_bn128::alt_bn128_pairing_check};
148+
///
149+
/// fn foo(points: Vec<(Point2D, [Point2D; 2])>) {
150+
/// let result = alt_bn128_pairing_check(points);
151+
/// assert(result);
152+
/// }
153+
/// ```
154+
pub fn alt_bn128_pairing_check(points: Vec<(Point2D, [Point2D; 2])>) -> bool {
155+
// Total bytes is (P1, (G1, G2)) = ([32 bytes, 32 bytes], ([32 bytes, 32 bytes], [32 bytes, 32 bytes])) = 6 * 32 bytes * length
156+
let mut points_ptr = alloc::<b256>(points.len() * 6);
157+
let mut iter = 0;
158+
while iter < points.len() {
159+
let p1 = points.get(iter).unwrap().0;
160+
let p2 = points.get(iter).unwrap().1[0];
161+
let p3 = points.get(iter).unwrap().1[1];
162+
163+
require(
164+
valid_alt_bn128_point(p1),
165+
AltBn128Error::InvalidEllipticCurvePoint,
166+
);
167+
require(
168+
valid_alt_bn128_point(p2),
169+
AltBn128Error::InvalidEllipticCurvePoint,
170+
);
171+
require(
172+
valid_alt_bn128_point(p3),
173+
AltBn128Error::InvalidEllipticCurvePoint,
174+
);
175+
176+
// Copy all 6 32 byte length points to the single slice
177+
p1
178+
.x()
179+
.ptr()
180+
.copy_to::<b256>(points_ptr.add::<b256>(iter * 6), 1);
181+
p1
182+
.y()
183+
.ptr()
184+
.copy_to::<b256>(points_ptr.add::<b256>((iter * 6) + 1), 1);
185+
p2
186+
.x()
187+
.ptr()
188+
.copy_to::<b256>(points_ptr.add::<b256>((iter * 6) + 2), 1);
189+
p2
190+
.y()
191+
.ptr()
192+
.copy_to::<b256>(points_ptr.add::<b256>((iter * 6) + 3), 1);
193+
p3
194+
.x()
195+
.ptr()
196+
.copy_to::<b256>(points_ptr.add::<b256>((iter * 6) + 4), 1);
197+
p3
198+
.y()
199+
.ptr()
200+
.copy_to::<b256>(points_ptr.add::<b256>((iter * 6) + 5), 1);
201+
202+
iter += 1;
203+
}
204+
205+
// Result is bool
206+
asm(buffer, curve: 0, length: points.len(), points: points_ptr) {
207+
epar buffer curve length points;
208+
buffer: bool
209+
}
210+
}
211+
212+
// Returns true if the point is in valid alt bn128 format.
213+
fn valid_alt_bn128_point(point: Point2D) -> bool {
214+
// 1P = ([32 bytes], [32 bytes])
215+
point.x().len() == 32 && point.y().len() == 32
216+
}
217+
218+
// Returns true if the scalar is in valid alt bn128 format.
219+
fn valid_alt_bn128_scalar(scalar: Scalar) -> bool {
220+
// 1S = [32 bytes]
221+
scalar.bytes().len() == 32
222+
}

0 commit comments

Comments
 (0)