1use crate::{syscall_handler::syscall_process_exit_code, RuntimeContext};
2use fluentbase_types::{
3 ExitCode, BLS12381_G1_RAW_AFFINE_SIZE, BN254_G1_RAW_AFFINE_SIZE, SECP256K1_G1_RAW_AFFINE_SIZE,
4 SECP256R1_G1_RAW_AFFINE_SIZE,
5};
6use rwasm::{StoreTr, TrapCode, Value};
7use sp1_curves::{
8 params::FieldParameters,
9 weierstrass::{
10 bls12_381::{Bls12381, Bls12381BaseField},
11 bn254::{Bn254, Bn254BaseField},
12 secp256k1::{Secp256k1, Secp256k1BaseField},
13 secp256r1::{Secp256r1, Secp256r1BaseField},
14 },
15 AffinePoint, BigUint, EllipticCurve,
16};
17
18pub fn syscall_secp256k1_add_handler(
19 ctx: &mut impl StoreTr<RuntimeContext>,
20 params: &[Value],
21 result: &mut [Value],
22) -> Result<(), TrapCode> {
23 syscall_weierstrass_add_handler::<Secp256k1, Secp256k1BaseField, { SECP256K1_G1_RAW_AFFINE_SIZE }>(
24 ctx, params, result,
25 )
26}
27pub fn syscall_secp256r1_add_handler(
28 ctx: &mut impl StoreTr<RuntimeContext>,
29 params: &[Value],
30 result: &mut [Value],
31) -> Result<(), TrapCode> {
32 syscall_weierstrass_add_handler::<Secp256r1, Secp256r1BaseField, { SECP256R1_G1_RAW_AFFINE_SIZE }>(
33 ctx, params, result,
34 )
35}
36pub fn syscall_bn254_add_handler(
37 ctx: &mut impl StoreTr<RuntimeContext>,
38 params: &[Value],
39 result: &mut [Value],
40) -> Result<(), TrapCode> {
41 syscall_weierstrass_add_handler::<Bn254, Bn254BaseField, { BN254_G1_RAW_AFFINE_SIZE }>(
42 ctx, params, result,
43 )
44}
45pub fn syscall_bls12381_add_handler(
46 ctx: &mut impl StoreTr<RuntimeContext>,
47 params: &[Value],
48 result: &mut [Value],
49) -> Result<(), TrapCode> {
50 syscall_weierstrass_add_handler::<Bls12381, Bls12381BaseField, { BLS12381_G1_RAW_AFFINE_SIZE }>(
51 ctx, params, result,
52 )
53}
54
55fn syscall_weierstrass_add_handler<
56 E: EllipticCurve,
57 P: FieldParameters,
58 const POINT_SIZE: usize,
59>(
60 ctx: &mut impl StoreTr<RuntimeContext>,
61 params: &[Value],
62 _result: &mut [Value],
63) -> Result<(), TrapCode> {
64 let p_ptr = params[0].i32().unwrap() as usize;
65 let q_ptr = params[1].i32().unwrap() as usize;
66
67 let mut p = [0u8; POINT_SIZE];
68 ctx.memory_read(p_ptr, &mut p)?;
69 let mut q = [0u8; POINT_SIZE];
70 ctx.memory_read(q_ptr, &mut q)?;
71
72 let result = syscall_weierstrass_add_impl::<E, P, POINT_SIZE>(p, q)
73 .map_err(|exit_code| syscall_process_exit_code(ctx, exit_code))?;
74 ctx.memory_write(p_ptr, &result)?;
75 Ok(())
76}
77
78pub fn syscall_secp256k1_add_impl(
89 p: [u8; SECP256K1_G1_RAW_AFFINE_SIZE],
90 q: [u8; SECP256K1_G1_RAW_AFFINE_SIZE],
91) -> Result<[u8; SECP256K1_G1_RAW_AFFINE_SIZE], ExitCode> {
92 syscall_weierstrass_add_impl::<Secp256k1, Secp256k1BaseField, { SECP256K1_G1_RAW_AFFINE_SIZE }>(
93 p, q,
94 )
95}
96
97pub fn syscall_secp256r1_add_impl(
108 p: [u8; SECP256R1_G1_RAW_AFFINE_SIZE],
109 q: [u8; SECP256R1_G1_RAW_AFFINE_SIZE],
110) -> Result<[u8; SECP256R1_G1_RAW_AFFINE_SIZE], ExitCode> {
111 syscall_weierstrass_add_impl::<Secp256r1, Secp256r1BaseField, { SECP256R1_G1_RAW_AFFINE_SIZE }>(
112 p, q,
113 )
114}
115
116pub fn syscall_bn254_add_impl(
127 p: [u8; BN254_G1_RAW_AFFINE_SIZE],
128 q: [u8; BN254_G1_RAW_AFFINE_SIZE],
129) -> Result<[u8; BN254_G1_RAW_AFFINE_SIZE], ExitCode> {
130 syscall_weierstrass_add_impl::<Bn254, Bn254BaseField, { BN254_G1_RAW_AFFINE_SIZE }>(p, q)
131}
132
133pub fn syscall_bls12381_add_impl(
144 p: [u8; BLS12381_G1_RAW_AFFINE_SIZE],
145 q: [u8; BLS12381_G1_RAW_AFFINE_SIZE],
146) -> Result<[u8; BLS12381_G1_RAW_AFFINE_SIZE], ExitCode> {
147 syscall_weierstrass_add_impl::<Bls12381, Bls12381BaseField, { BLS12381_G1_RAW_AFFINE_SIZE }>(
148 p, q,
149 )
150}
151
152fn syscall_weierstrass_add_impl<E: EllipticCurve, P: FieldParameters, const POINT_SIZE: usize>(
163 p: [u8; POINT_SIZE],
164 q: [u8; POINT_SIZE],
165) -> Result<[u8; POINT_SIZE], ExitCode> {
166 let (px, py) = p.split_at(POINT_SIZE / 2);
167 let p_affine = AffinePoint::<E>::new(BigUint::from_bytes_le(px), BigUint::from_bytes_le(py));
168 let (qx, qy) = q.split_at(POINT_SIZE / 2);
169 let q_affine = AffinePoint::<E>::new(BigUint::from_bytes_le(qx), BigUint::from_bytes_le(qy));
170 if p_affine.x == q_affine.x && p_affine.y == q_affine.y {
172 return Err(ExitCode::MalformedBuiltinParams);
173 }
174 let modulus = P::modulus();
176 if p_affine.x >= modulus
177 || p_affine.y >= modulus
178 || q_affine.x >= modulus
179 || q_affine.y >= modulus
180 {
181 return Err(ExitCode::MalformedBuiltinParams);
182 }
183 let result_affine = p_affine + q_affine;
184 let (rx, ry) = (result_affine.x, result_affine.y);
185 let mut result = [0u8; POINT_SIZE];
186 let mut rx = rx.to_bytes_le();
187 rx.resize(POINT_SIZE / 2, 0);
188 let mut ry = ry.to_bytes_le();
189 ry.resize(POINT_SIZE / 2, 0);
190 result[..POINT_SIZE / 2].copy_from_slice(&rx);
191 result[POINT_SIZE / 2..].copy_from_slice(&ry);
192 Ok(result)
193}
194
195#[cfg(test)]
203mod tests {
204 use super::*;
205 use sp1_curves::{params::FieldParameters, weierstrass::secp256k1::Secp256k1BaseField};
206
207 #[test]
208 fn test_bls12381_add() {
209 const A: [u8; 96] = [
213 187, 198, 34, 219, 10, 240, 58, 251, 239, 26, 122, 249, 63, 232, 85, 108, 88, 172, 27,
214 23, 63, 58, 78, 161, 5, 185, 116, 151, 79, 140, 104, 195, 15, 172, 169, 79, 140, 99,
215 149, 38, 148, 215, 151, 49, 167, 211, 241, 23, 225, 231, 197, 70, 41, 35, 170, 12, 228,
216 138, 136, 162, 68, 199, 60, 208, 237, 179, 4, 44, 203, 24, 219, 0, 246, 10, 208, 213,
217 149, 224, 245, 252, 228, 138, 29, 116, 237, 48, 158, 160, 241, 160, 170, 227, 129, 244,
218 179, 8,
219 ];
220
221 const B: [u8; 96] = [
225 78, 15, 191, 41, 85, 140, 154, 195, 66, 124, 28, 143, 187, 117, 143, 226, 42, 166, 88,
226 195, 10, 45, 144, 67, 37, 1, 40, 145, 48, 219, 33, 151, 12, 69, 169, 80, 235, 200, 8,
227 136, 70, 103, 77, 144, 234, 203, 114, 5, 40, 157, 116, 121, 25, 136, 134, 186, 27, 189,
228 22, 205, 212, 217, 86, 76, 106, 215, 95, 29, 2, 185, 59, 247, 97, 228, 112, 134, 203,
229 62, 186, 34, 56, 142, 157, 119, 115, 166, 253, 34, 163, 115, 198, 171, 140, 157, 106,
230 22,
231 ];
232
233 const C: [u8; 96] = [
237 36, 82, 78, 2, 201, 192, 210, 150, 155, 23, 162, 44, 11, 122, 116, 129, 249, 63, 91,
238 51, 81, 10, 120, 243, 241, 165, 233, 155, 31, 214, 18, 177, 151, 150, 169, 236, 45, 33,
239 101, 23, 19, 240, 209, 249, 8, 227, 236, 9, 209, 48, 174, 144, 5, 59, 71, 163, 92, 244,
240 74, 99, 108, 37, 69, 231, 230, 59, 212, 15, 49, 39, 156, 157, 127, 9, 195, 171, 221,
241 12, 154, 166, 12, 248, 197, 137, 51, 98, 132, 138, 159, 176, 245, 166, 211, 128, 43, 3,
242 ];
243 let result = syscall_bls12381_add_impl(A, B).unwrap();
244 assert_eq!(result, C);
245 }
246
247 #[test]
248 fn test_bn254_add() {
249 const A: [u8; 64] = [
253 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
254 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
255 0, 0, 0, 0, 0, 0,
256 ];
257
258 const B: [u8; 64] = [
262 211, 207, 135, 109, 193, 8, 194, 211, 168, 28, 135, 22, 169, 22, 120, 217, 133, 21, 24,
263 104, 91, 4, 133, 155, 2, 26, 19, 46, 231, 68, 6, 3, 196, 162, 24, 90, 122, 191, 62,
264 255, 199, 143, 83, 227, 73, 164, 166, 104, 10, 156, 174, 178, 150, 95, 132, 231, 146,
265 124, 10, 14, 140, 115, 237, 21,
266 ];
267
268 const C: [u8; 64] = [
272 240, 171, 21, 25, 150, 85, 211, 242, 121, 230, 184, 21, 71, 216, 21, 147, 21, 189, 182,
273 177, 188, 50, 2, 244, 63, 234, 107, 197, 154, 191, 105, 7, 97, 34, 254, 217, 61, 255,
274 241, 205, 87, 91, 156, 11, 180, 99, 158, 49, 117, 100, 8, 141, 124, 219, 79, 85, 41,
275 148, 72, 224, 190, 153, 183, 42,
276 ];
277 let result = syscall_bn254_add_impl(A, B).unwrap();
278 assert_eq!(result, C);
279 }
280
281 #[test]
282 fn test_secp256k1_add() {
283 const A: [u8; 64] = [
284 152, 23, 248, 22, 91, 129, 242, 89, 217, 40, 206, 45, 219, 252, 155, 2, 7, 11, 135,
285 206, 149, 98, 160, 85, 172, 187, 220, 249, 126, 102, 190, 121, 184, 212, 16, 251, 143,
286 208, 71, 156, 25, 84, 133, 166, 72, 180, 23, 253, 168, 8, 17, 14, 252, 251, 164, 93,
287 101, 196, 163, 38, 119, 218, 58, 72,
288 ];
289 const B: [u8; 64] = [
293 229, 158, 112, 92, 185, 9, 172, 171, 167, 60, 239, 140, 75, 142, 119, 92, 216, 124,
294 192, 149, 110, 64, 69, 48, 109, 125, 237, 65, 148, 127, 4, 198, 42, 229, 207, 80, 169,
295 49, 100, 35, 225, 208, 102, 50, 101, 50, 246, 247, 238, 234, 108, 70, 25, 132, 197,
296 163, 57, 195, 61, 166, 254, 104, 225, 26,
297 ];
298 const C: [u8; 64] = [
302 249, 54, 224, 188, 19, 241, 1, 134, 176, 153, 111, 131, 69, 200, 49, 181, 41, 82, 157,
303 248, 133, 79, 52, 73, 16, 195, 88, 146, 1, 138, 48, 249, 114, 230, 184, 132, 117, 253,
304 185, 108, 27, 35, 194, 52, 153, 169, 0, 101, 86, 243, 55, 42, 230, 55, 227, 15, 20,
305 232, 45, 99, 15, 123, 143, 56,
306 ];
307 let result = syscall_secp256k1_add_impl(A, B).unwrap();
308 assert_eq!(result, C);
309 }
310
311 #[test]
312 fn test_secp256r1_add() {
313 const A: [u8; 64] = [
317 150, 194, 152, 216, 69, 57, 161, 244, 160, 51, 235, 45, 129, 125, 3, 119, 242, 64, 164,
318 99, 229, 230, 188, 248, 71, 66, 44, 225, 242, 209, 23, 107, 245, 81, 191, 55, 104, 64,
319 182, 203, 206, 94, 49, 107, 87, 51, 206, 43, 22, 158, 15, 124, 74, 235, 231, 142, 155,
320 127, 26, 254, 226, 66, 227, 79,
321 ];
322
323 const B: [u8; 64] = [
327 120, 153, 102, 71, 252, 72, 11, 166, 53, 27, 242, 119, 226, 105, 137, 192, 195, 26,
328 181, 4, 3, 56, 82, 138, 126, 79, 3, 141, 24, 123, 242, 124, 209, 115, 120, 34, 157,
329 183, 4, 158, 41, 130, 233, 60, 230, 173, 125, 186, 219, 48, 116, 159, 198, 154, 61, 41,
330 64, 208, 142, 219, 16, 85, 119, 7,
331 ];
332
333 const C: [u8; 64] = [
337 108, 253, 231, 198, 27, 102, 65, 251, 133, 169, 173, 239, 33, 183, 198, 230, 101, 241,
338 75, 29, 149, 239, 247, 200, 68, 10, 51, 166, 209, 228, 203, 94, 50, 80, 125, 162, 39,
339 177, 121, 154, 61, 184, 79, 56, 54, 176, 42, 216, 236, 162, 100, 26, 206, 6, 75, 55,
340 126, 255, 152, 73, 12, 100, 52, 135,
341 ];
342 let result = syscall_secp256r1_add_impl(A, B).unwrap();
344 assert_eq!(result, C);
345 }
346
347 #[test]
348 fn test_add_with_self_dont_panic() {
349 const A: [u8; 64] = [
350 150, 194, 152, 216, 69, 57, 161, 244, 160, 51, 235, 45, 129, 125, 3, 119, 242, 64, 164,
351 99, 229, 230, 188, 248, 71, 66, 44, 225, 242, 209, 23, 107, 245, 81, 191, 55, 104, 64,
352 182, 203, 206, 94, 49, 107, 87, 51, 206, 43, 22, 158, 15, 124, 74, 235, 231, 142, 155,
353 127, 26, 254, 226, 66, 227, 79,
354 ];
355 let exit_code = syscall_secp256r1_add_impl(A, A).unwrap_err();
356 assert_eq!(exit_code, ExitCode::MalformedBuiltinParams);
357 }
358
359 #[test]
360 fn test_secp256k1_unreduced_coordinates_trigger_panic() {
361 let p = [0xffu8; 64];
364 let mut q = [0xffu8; 64];
365 q[32] = 0xfe;
367
368 let modulus = Secp256k1BaseField::modulus();
369 let px = BigUint::from_bytes_le(&p[..32]);
370 let py = BigUint::from_bytes_le(&p[32..]);
371 let qx = BigUint::from_bytes_le(&q[..32]);
372 let qy = BigUint::from_bytes_le(&q[32..]);
373
374 assert!(
375 px >= modulus && py >= modulus && qx >= modulus && qy >= modulus,
376 "constructed points must have unreduced coordinates"
377 );
378
379 let exit_code = syscall_secp256k1_add_impl(p, q).unwrap_err();
380 assert_eq!(exit_code, ExitCode::MalformedBuiltinParams);
381 }
382}