@@ -1171,6 +1171,17 @@ declare_builtin_function!(
11711171 use solana_zk_token_sdk:: curve25519:: {
11721172 curve_syscall_traits:: * , edwards, ristretto, scalar,
11731173 } ;
1174+
1175+ let restrict_msm_length = invoke_context
1176+ . feature_set
1177+ . is_active( & feature_set:: curve25519_restrict_msm_length:: id( ) ) ;
1178+ #[ allow( clippy:: collapsible_if) ]
1179+ if restrict_msm_length {
1180+ if points_len > 512 {
1181+ return Err ( Box :: new( SyscallError :: InvalidLength ) ) ;
1182+ }
1183+ }
1184+
11741185 match curve_id {
11751186 CURVE25519_EDWARDS => {
11761187 let cost = invoke_context
@@ -3211,6 +3222,122 @@ mod tests {
32113222 assert_eq ! ( expected_product, result_point) ;
32123223 }
32133224
3225+ #[ test]
3226+ fn test_syscall_multiscalar_multiplication_maximum_length_exceeded ( ) {
3227+ use solana_zk_token_sdk:: curve25519:: curve_syscall_traits:: {
3228+ CURVE25519_EDWARDS , CURVE25519_RISTRETTO ,
3229+ } ;
3230+
3231+ let config = Config :: default ( ) ;
3232+ prepare_mockup ! ( invoke_context, program_id, bpf_loader:: id( ) ) ;
3233+
3234+ let scalar: [ u8 ; 32 ] = [
3235+ 254 , 198 , 23 , 138 , 67 , 243 , 184 , 110 , 236 , 115 , 236 , 205 , 205 , 215 , 79 , 114 , 45 , 250 ,
3236+ 78 , 137 , 3 , 107 , 136 , 237 , 49 , 126 , 117 , 223 , 37 , 191 , 88 , 6 ,
3237+ ] ;
3238+ let scalars = [ scalar; 513 ] ;
3239+ let scalars_va = 0x100000000 ;
3240+
3241+ let edwards_point: [ u8 ; 32 ] = [
3242+ 252 , 31 , 230 , 46 , 173 , 95 , 144 , 148 , 158 , 157 , 63 , 10 , 8 , 68 , 58 , 176 , 142 , 192 , 168 ,
3243+ 53 , 61 , 105 , 194 , 166 , 43 , 56 , 246 , 236 , 28 , 146 , 114 , 133 ,
3244+ ] ;
3245+ let edwards_points = [ edwards_point; 513 ] ;
3246+ let edwards_points_va = 0x200000000 ;
3247+
3248+ let ristretto_point: [ u8 ; 32 ] = [
3249+ 130 , 35 , 97 , 25 , 18 , 199 , 33 , 239 , 85 , 143 , 119 , 111 , 49 , 51 , 224 , 40 , 167 , 185 , 240 ,
3250+ 179 , 25 , 194 , 213 , 41 , 14 , 155 , 104 , 18 , 181 , 197 , 15 , 112 ,
3251+ ] ;
3252+ let ristretto_points = [ ristretto_point; 513 ] ;
3253+ let ristretto_points_va = 0x300000000 ;
3254+
3255+ let mut result_point: [ u8 ; 32 ] = [ 0 ; 32 ] ;
3256+ let result_point_va = 0x400000000 ;
3257+
3258+ let mut memory_mapping = MemoryMapping :: new (
3259+ vec ! [
3260+ MemoryRegion :: new_readonly( bytes_of_slice( & scalars) , scalars_va) ,
3261+ MemoryRegion :: new_readonly( bytes_of_slice( & edwards_points) , edwards_points_va) ,
3262+ MemoryRegion :: new_readonly( bytes_of_slice( & ristretto_points) , ristretto_points_va) ,
3263+ MemoryRegion :: new_writable( bytes_of_slice_mut( & mut result_point) , result_point_va) ,
3264+ ] ,
3265+ & config,
3266+ & SBPFVersion :: V2 ,
3267+ )
3268+ . unwrap ( ) ;
3269+
3270+ // test Edwards
3271+ invoke_context. mock_set_remaining ( 500_000 ) ;
3272+ let result = SyscallCurveMultiscalarMultiplication :: rust (
3273+ & mut invoke_context,
3274+ CURVE25519_EDWARDS ,
3275+ scalars_va,
3276+ edwards_points_va,
3277+ 512 , // below maximum vector length
3278+ result_point_va,
3279+ & mut memory_mapping,
3280+ ) ;
3281+
3282+ assert_eq ! ( 0 , result. unwrap( ) ) ;
3283+ let expected_product = [
3284+ 20 , 146 , 226 , 37 , 22 , 61 , 86 , 249 , 208 , 40 , 38 , 11 , 126 , 101 , 10 , 82 , 81 , 77 , 88 , 209 ,
3285+ 15 , 76 , 82 , 251 , 180 , 133 , 84 , 243 , 162 , 0 , 11 , 145 ,
3286+ ] ;
3287+ assert_eq ! ( expected_product, result_point) ;
3288+
3289+ invoke_context. mock_set_remaining ( 500_000 ) ;
3290+ let result = SyscallCurveMultiscalarMultiplication :: rust (
3291+ & mut invoke_context,
3292+ CURVE25519_EDWARDS ,
3293+ scalars_va,
3294+ edwards_points_va,
3295+ 513 , // above maximum vector length
3296+ result_point_va,
3297+ & mut memory_mapping,
3298+ )
3299+ . unwrap_err ( )
3300+ . downcast :: < SyscallError > ( )
3301+ . unwrap ( ) ;
3302+
3303+ assert_eq ! ( * result, SyscallError :: InvalidLength ) ;
3304+
3305+ // test Ristretto
3306+ invoke_context. mock_set_remaining ( 500_000 ) ;
3307+ let result = SyscallCurveMultiscalarMultiplication :: rust (
3308+ & mut invoke_context,
3309+ CURVE25519_RISTRETTO ,
3310+ scalars_va,
3311+ ristretto_points_va,
3312+ 512 , // below maximum vector length
3313+ result_point_va,
3314+ & mut memory_mapping,
3315+ ) ;
3316+
3317+ assert_eq ! ( 0 , result. unwrap( ) ) ;
3318+ let expected_product = [
3319+ 146 , 224 , 127 , 193 , 252 , 64 , 196 , 181 , 246 , 104 , 27 , 116 , 183 , 52 , 200 , 239 , 2 , 108 ,
3320+ 21 , 27 , 97 , 44 , 95 , 65 , 26 , 218 , 223 , 39 , 197 , 132 , 51 , 49 ,
3321+ ] ;
3322+ assert_eq ! ( expected_product, result_point) ;
3323+
3324+ invoke_context. mock_set_remaining ( 500_000 ) ;
3325+ let result = SyscallCurveMultiscalarMultiplication :: rust (
3326+ & mut invoke_context,
3327+ CURVE25519_RISTRETTO ,
3328+ scalars_va,
3329+ ristretto_points_va,
3330+ 513 , // above maximum vector length
3331+ result_point_va,
3332+ & mut memory_mapping,
3333+ )
3334+ . unwrap_err ( )
3335+ . downcast :: < SyscallError > ( )
3336+ . unwrap ( ) ;
3337+
3338+ assert_eq ! ( * result, SyscallError :: InvalidLength ) ;
3339+ }
3340+
32143341 fn create_filled_type < T : Default > ( zero_init : bool ) -> T {
32153342 let mut val = T :: default ( ) ;
32163343 let p = & mut val as * mut _ as * mut u8 ;
0 commit comments