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 num::BigUint;
7use rwasm::{StoreTr, TrapCode, Value};
8use sp1_curves::{
9 params::FieldParameters,
10 weierstrass::{
11 bls12_381::{Bls12381, Bls12381BaseField},
12 bn254::{Bn254, Bn254BaseField},
13 secp256k1::{Secp256k1, Secp256k1BaseField},
14 secp256r1::{Secp256r1, Secp256r1BaseField},
15 },
16 AffinePoint, EllipticCurve,
17};
18
19pub fn syscall_secp256k1_double_handler(
20 ctx: &mut impl StoreTr<RuntimeContext>,
21 params: &[Value],
22 result: &mut [Value],
23) -> Result<(), TrapCode> {
24 syscall_weierstrass_double_handler::<
25 Secp256k1,
26 Secp256k1BaseField,
27 { SECP256K1_G1_RAW_AFFINE_SIZE },
28 >(ctx, params, result)
29}
30pub fn syscall_secp256r1_double_handler(
31 ctx: &mut impl StoreTr<RuntimeContext>,
32 params: &[Value],
33 result: &mut [Value],
34) -> Result<(), TrapCode> {
35 syscall_weierstrass_double_handler::<
36 Secp256r1,
37 Secp256r1BaseField,
38 { SECP256R1_G1_RAW_AFFINE_SIZE },
39 >(ctx, params, result)
40}
41pub fn syscall_bn254_double_handler(
42 ctx: &mut impl StoreTr<RuntimeContext>,
43 params: &[Value],
44 result: &mut [Value],
45) -> Result<(), TrapCode> {
46 syscall_weierstrass_double_handler::<Bn254, Bn254BaseField, { BN254_G1_RAW_AFFINE_SIZE }>(
47 ctx, params, result,
48 )
49}
50pub fn syscall_bls12381_double_handler(
51 ctx: &mut impl StoreTr<RuntimeContext>,
52 params: &[Value],
53 result: &mut [Value],
54) -> Result<(), TrapCode> {
55 syscall_weierstrass_double_handler::<Bls12381, Bls12381BaseField, { BLS12381_G1_RAW_AFFINE_SIZE }>(
56 ctx, params, result,
57 )
58}
59
60fn syscall_weierstrass_double_handler<
61 E: EllipticCurve,
62 P: FieldParameters,
63 const POINT_SIZE: usize,
64>(
65 ctx: &mut impl StoreTr<RuntimeContext>,
66 params: &[Value],
67 _result: &mut [Value],
68) -> Result<(), TrapCode> {
69 let p_ptr: u32 = params[0].i32().unwrap() as u32;
70
71 let mut p = [0u8; POINT_SIZE];
72 ctx.memory_read(p_ptr as usize, &mut p)?;
73
74 let result = syscall_weierstrass_double_impl::<E, P, POINT_SIZE>(p)
75 .map_err(|exit_code| syscall_process_exit_code(ctx, exit_code))?;
76 ctx.memory_write(p_ptr as usize, &result)?;
77
78 Ok(())
79}
80
81pub fn syscall_secp256k1_double_impl(
91 p: [u8; SECP256K1_G1_RAW_AFFINE_SIZE],
92) -> Result<[u8; SECP256K1_G1_RAW_AFFINE_SIZE], ExitCode> {
93 syscall_weierstrass_double_impl::<Secp256k1, Secp256k1BaseField, { SECP256K1_G1_RAW_AFFINE_SIZE }>(
94 p,
95 )
96}
97
98pub fn syscall_secp256r1_double_impl(
108 p: [u8; SECP256R1_G1_RAW_AFFINE_SIZE],
109) -> Result<[u8; SECP256R1_G1_RAW_AFFINE_SIZE], ExitCode> {
110 syscall_weierstrass_double_impl::<Secp256r1, Secp256r1BaseField, { SECP256R1_G1_RAW_AFFINE_SIZE }>(
111 p,
112 )
113}
114
115pub fn syscall_bn254_double_impl(
125 p: [u8; BN254_G1_RAW_AFFINE_SIZE],
126) -> Result<[u8; BN254_G1_RAW_AFFINE_SIZE], ExitCode> {
127 syscall_weierstrass_double_impl::<Bn254, Bn254BaseField, { BN254_G1_RAW_AFFINE_SIZE }>(p)
128}
129
130pub fn syscall_bls12381_double_impl(
140 p: [u8; BLS12381_G1_RAW_AFFINE_SIZE],
141) -> Result<[u8; BLS12381_G1_RAW_AFFINE_SIZE], ExitCode> {
142 syscall_weierstrass_double_impl::<Bls12381, Bls12381BaseField, { BLS12381_G1_RAW_AFFINE_SIZE }>(
143 p,
144 )
145}
146
147fn syscall_weierstrass_double_impl<
148 E: EllipticCurve,
149 P: FieldParameters,
150 const POINT_SIZE: usize,
151>(
152 p: [u8; POINT_SIZE],
153) -> Result<[u8; POINT_SIZE], ExitCode> {
154 let (px, py) = p.split_at(p.len() / 2);
155 let (px, py) = (BigUint::from_bytes_le(px), BigUint::from_bytes_le(py));
156 let modulus = P::modulus();
158 if px >= modulus || py >= modulus {
159 return Err(ExitCode::MalformedBuiltinParams);
160 }
161 let p_affine = AffinePoint::<E>::new(px, py);
162 let result_affine = E::ec_double(&p_affine);
163 let (rx, ry) = (result_affine.x, result_affine.y);
164 let mut result = [0u8; POINT_SIZE];
165 let mut rx = rx.to_bytes_le();
166 rx.resize(POINT_SIZE / 2, 0);
167 let mut ry = ry.to_bytes_le();
168 ry.resize(POINT_SIZE / 2, 0);
169 result[..POINT_SIZE / 2].copy_from_slice(&rx);
170 result[POINT_SIZE / 2..].copy_from_slice(&ry);
171 Ok(result)
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn test_bls12381_double() {
180 let generator: [u8; 96] = [
184 187, 198, 34, 219, 10, 240, 58, 251, 239, 26, 122, 249, 63, 232, 85, 108, 88, 172, 27,
185 23, 63, 58, 78, 161, 5, 185, 116, 151, 79, 140, 104, 195, 15, 172, 169, 79, 140, 99,
186 149, 38, 148, 215, 151, 49, 167, 211, 241, 23, 225, 231, 197, 70, 41, 35, 170, 12, 228,
187 138, 136, 162, 68, 199, 60, 208, 237, 179, 4, 44, 203, 24, 219, 0, 246, 10, 208, 213,
188 149, 224, 245, 252, 228, 138, 29, 116, 237, 48, 158, 160, 241, 160, 170, 227, 129, 244,
189 179, 8,
190 ];
191
192 let expected_doubled: [u8; 96] = [
196 78, 15, 191, 41, 85, 140, 154, 195, 66, 124, 28, 143, 187, 117, 143, 226, 42, 166, 88,
197 195, 10, 45, 144, 67, 37, 1, 40, 145, 48, 219, 33, 151, 12, 69, 169, 80, 235, 200, 8,
198 136, 70, 103, 77, 144, 234, 203, 114, 5, 40, 157, 116, 121, 25, 136, 134, 186, 27, 189,
199 22, 205, 212, 217, 86, 76, 106, 215, 95, 29, 2, 185, 59, 247, 97, 228, 112, 134, 203,
200 62, 186, 34, 56, 142, 157, 119, 115, 166, 253, 34, 163, 115, 198, 171, 140, 157, 106,
201 22,
202 ];
203
204 let result = syscall_bls12381_double_impl(generator).unwrap();
205 assert_eq!(result, expected_doubled);
206 }
207
208 #[test]
209 fn test_bn254_double() {
210 for _ in 0..10i64.pow(3) {
211 let a: [u8; 64] = [
215 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,
216 0, 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,
217 0, 0, 0, 0, 0, 0, 0, 0,
218 ];
219 let b: [u8; 64] = [
223 211, 207, 135, 109, 193, 8, 194, 211, 168, 28, 135, 22, 169, 22, 120, 217, 133, 21,
224 24, 104, 91, 4, 133, 155, 2, 26, 19, 46, 231, 68, 6, 3, 196, 162, 24, 90, 122, 191,
225 62, 255, 199, 143, 83, 227, 73, 164, 166, 104, 10, 156, 174, 178, 150, 95, 132,
226 231, 146, 124, 10, 14, 140, 115, 237, 21,
227 ];
228
229 let result = syscall_bn254_double_impl(a).unwrap();
230 assert_eq!(result, b);
231 }
232 }
233
234 #[test]
235 fn test_secp256k1_double() {
236 for _ in 0..10 {
237 let a: [u8; 64] = [
241 152, 23, 248, 22, 91, 129, 242, 89, 217, 40, 206, 45, 219, 252, 155, 2, 7, 11, 135,
242 206, 149, 98, 160, 85, 172, 187, 220, 249, 126, 102, 190, 121, 184, 212, 16, 251,
243 143, 208, 71, 156, 25, 84, 133, 166, 72, 180, 23, 253, 168, 8, 17, 14, 252, 251,
244 164, 93, 101, 196, 163, 38, 119, 218, 58, 72,
245 ];
246
247 let b: [u8; 64] = [
251 229, 158, 112, 92, 185, 9, 172, 171, 167, 60, 239, 140, 75, 142, 119, 92, 216, 124,
252 192, 149, 110, 64, 69, 48, 109, 125, 237, 65, 148, 127, 4, 198, 42, 229, 207, 80,
253 169, 49, 100, 35, 225, 208, 102, 50, 101, 50, 246, 247, 238, 234, 108, 70, 25, 132,
254 197, 163, 57, 195, 61, 166, 254, 104, 225, 26,
255 ];
256
257 let result = syscall_secp256k1_double_impl(a).unwrap();
258 assert_eq!(result, b);
259 }
260 }
261
262 #[test]
263 fn test_secp256r1_double() {
264 let a: [u8; 64] = [
268 150, 194, 152, 216, 69, 57, 161, 244, 160, 51, 235, 45, 129, 125, 3, 119, 242, 64, 164,
269 99, 229, 230, 188, 248, 71, 66, 44, 225, 242, 209, 23, 107, 245, 81, 191, 55, 104, 64,
270 182, 203, 206, 94, 49, 107, 87, 51, 206, 43, 22, 158, 15, 124, 74, 235, 231, 142, 155,
271 127, 26, 254, 226, 66, 227, 79,
272 ];
273
274 let b: [u8; 64] = [
278 120, 153, 102, 71, 252, 72, 11, 166, 53, 27, 242, 119, 226, 105, 137, 192, 195, 26,
279 181, 4, 3, 56, 82, 138, 126, 79, 3, 141, 24, 123, 242, 124, 209, 115, 120, 34, 157,
280 183, 4, 158, 41, 130, 233, 60, 230, 173, 125, 186, 219, 48, 116, 159, 198, 154, 61, 41,
281 64, 208, 142, 219, 16, 85, 119, 7,
282 ];
283
284 let result = syscall_secp256r1_double_impl(a).unwrap();
285 assert_eq!(result, b);
286 }
287
288 #[test]
291 fn test_coords_above_modulus_halt() {
292 let mut coords_above_modulus_point = [0u8; 96];
294
295 coords_above_modulus_point[..48].fill(0xff);
297
298 let exit_code = syscall_bls12381_double_impl(coords_above_modulus_point).unwrap_err();
299 assert_eq!(exit_code, ExitCode::MalformedBuiltinParams);
300 }
301}