@@ -49,7 +49,10 @@ use lambdaworks_math::{
4949use num_bigint:: { BigInt , BigUint , Sign } ;
5050use pretty_assertions_sorted:: assert_eq_sorted;
5151use proptest:: { strategy:: Strategy , test_runner:: TestCaseError } ;
52- use starknet_types_core:: felt:: Felt ;
52+ use starknet_types_core:: {
53+ curve:: { AffinePoint , ProjectivePoint } ,
54+ felt:: Felt ,
55+ } ;
5356use std:: { collections:: HashMap , env:: var, fs, ops:: Neg , path:: Path } ;
5457
5558#[ allow( unused_macros) ]
@@ -491,7 +494,9 @@ pub fn compare_outputs(
491494 . map ( |member_ty| map_vm_sizes ( size_cache, registry, member_ty) )
492495 . sum ( ) ,
493496 CoreTypeConcrete :: NonZero ( info) => map_vm_sizes ( size_cache, registry, & info. ty ) ,
494- CoreTypeConcrete :: EcState ( _) => 4 ,
497+ // In the VM an `EcState` is `(x, y, random_ptr)` = 3 felts (the third
498+ // being a pointer to the random shift point), unlike native which uses 2.
499+ CoreTypeConcrete :: EcState ( _) => 3 ,
495500 CoreTypeConcrete :: Snapshot ( info) => {
496501 map_vm_sizes ( size_cache, registry, & info. ty )
497502 }
@@ -703,12 +708,31 @@ pub fn compare_outputs(
703708 )
704709 }
705710 CoreTypeConcrete :: EcState ( _) => {
706- assert_eq ! ( values. len( ) , 2 ) ;
707-
708- Value :: EcState (
709- Felt :: from_bytes_le ( & values[ 0 ] . to_bytes_le ( ) ) ,
710- Felt :: from_bytes_le ( & values[ 1 ] . to_bytes_le ( ) ) ,
711- )
711+ // The VM lays out an `EcState` as `(x, y, random_ptr)`, where `(x, y)` is the
712+ // accumulated point *shifted* by a random point sampled at `ec_state_init`, and
713+ // `random_ptr` points to that random shift point `(random_x, random_y)`.
714+ //
715+ // Native represents an `EcState` as the plain accumulated point (starting from
716+ // the identity `(0, 0)`), so to compare we must undo the shift by computing
717+ // `(x, y) - (random_x, random_y)`.
718+ assert_eq ! ( values. len( ) , 3 ) ;
719+
720+ let x = Felt :: from_bytes_le ( & values[ 0 ] . to_bytes_le ( ) ) ;
721+ let y = Felt :: from_bytes_le ( & values[ 1 ] . to_bytes_le ( ) ) ;
722+
723+ let random_ptr = values[ 2 ] . to_usize ( ) . unwrap ( ) ;
724+ let random_x = memory[ random_ptr] . unwrap ( ) ;
725+ let random_y = memory[ random_ptr + 1 ] . unwrap ( ) ;
726+
727+ // `(x, y) - (random_x, random_y) == (x, y) + (random_x, -random_y)`.
728+ let mut state = ProjectivePoint :: from_affine_unchecked ( x, y) ;
729+ state += & AffinePoint :: new_unchecked ( random_x, -random_y) ;
730+
731+ match state. to_affine ( ) {
732+ Ok ( point) => Value :: EcState ( point. x ( ) , point. y ( ) ) ,
733+ // Native uses `(0, 0)` to represent the point at infinity.
734+ Err ( _) => Value :: EcState ( Felt :: ZERO , Felt :: ZERO ) ,
735+ }
712736 }
713737 CoreTypeConcrete :: Bytes31 ( _) => {
714738 let mut bytes = values[ 0 ] . to_bytes_le ( ) . to_vec ( ) ;
0 commit comments