Skip to content

Commit 78eba19

Browse files
oriziclaude
andauthored
refactor: Simplified EcState native representation to a plain EcPoint. (#1633)
Previously, EcState stored 4 felts (current state + a random point) to work around EC-OP builtin edge cases in CASM. Since native execution does direct EC arithmetic with no such constraints, the random point is unnecessary. EcState is now 2 felts (x, y) with (0, 0) as the infinity sentinel, matching the semantics of EcPoint::zero(). Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b1e2487 commit 78eba19

15 files changed

Lines changed: 172 additions & 367 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ num-traits = "0.2"
7474
p256 = "0.13.2"
7575
pretty_assertions_sorted = "1.2.3"
7676
proptest = "1.5.0"
77-
rand = "0.9.0"
7877
rayon = "1.10.0"
7978
rstest = "0.24.0"
8079
scarb-metadata = "1.12.0"
@@ -184,7 +183,6 @@ keccak.workspace = true
184183
sha2.workspace = true
185184

186185
# Runtime library dependencies.
187-
rand.workspace = true
188186
starknet-curve.workspace = true
189187
lambdaworks-math.workspace = true
190188

binaries/cairo-native-bin-utils/src/lib.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,9 @@ fn jitvalue_to_felt(value: &Value) -> Vec<Felt> {
152152
Value::Sint64(x) => vec![(*x).into()],
153153
Value::Sint128(x) => vec![(*x).into()],
154154
Value::Bytes31(bytes) => vec![Felt::from_bytes_le_slice(bytes)],
155-
Value::EcPoint(x, y) => {
155+
Value::EcPoint(x, y) | Value::EcState(x, y) => {
156156
vec![*x, *y]
157157
}
158-
Value::EcState(a, b, c, d) => {
159-
vec![*a, *b, *c, *d]
160-
}
161158
Value::QM31(a, b, c, d) => vec![
162159
Felt::from(*a),
163160
Felt::from(*b),
@@ -551,13 +548,8 @@ mod tests {
551548
#[test]
552549
fn test_jitvalue_to_felt_ec_state() {
553550
assert_eq!(
554-
jitvalue_to_felt(&Value::EcState(
555-
Felt::ONE,
556-
Felt::TWO,
557-
Felt::THREE,
558-
Felt::from(4)
559-
)),
560-
vec![Felt::ONE, Felt::TWO, Felt::THREE, Felt::from(4)]
551+
jitvalue_to_felt(&Value::EcState(Felt::ONE, Felt::TWO,)),
552+
vec![Felt::ONE, Felt::TWO,]
561553
);
562554
}
563555

debug_utils/sierra-emu/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ num-integer.workspace = true
3131
num-bigint.workspace = true
3232
num-traits.workspace = true
3333
p256.workspace = true
34-
rand.workspace = true
3534
sec1 = { workspace = true, features = ["std"] }
3635
serde = { workspace = true, features = ["derive"] }
3736
serde_json.workspace = true

debug_utils/sierra-emu/src/value.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,8 @@ pub enum Value {
5555
y: Felt,
5656
},
5757
EcState {
58-
x0: Felt,
59-
y0: Felt,
60-
x1: Felt,
61-
y1: Felt,
58+
x: Felt,
59+
y: Felt,
6260
},
6361
I128(i128),
6462
I64(i64),

debug_utils/sierra-emu/src/vm/ec.rs

Lines changed: 26 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use cairo_lang_sierra::{
99
program_registry::ProgramRegistry,
1010
};
1111
use num_traits::identities::Zero;
12-
use rand::Rng;
1312
use smallvec::smallvec;
1413
use starknet_crypto::Felt;
1514
use starknet_curve::curve_params::BETA;
@@ -113,15 +112,11 @@ fn eval_state_init(
113112
_info: &SignatureOnlyConcreteLibfunc,
114113
_args: Vec<Value>,
115114
) -> EvalAction {
116-
let state = random_ec_point();
117-
118115
EvalAction::NormalBranch(
119116
0,
120117
smallvec![Value::EcState {
121-
x0: state.x(),
122-
y0: state.y(),
123-
x1: state.x(),
124-
y1: state.y(),
118+
x: 0.into(),
119+
y: 0.into()
125120
}],
126121
)
127122
}
@@ -131,84 +126,65 @@ fn eval_state_add(
131126
_info: &SignatureOnlyConcreteLibfunc,
132127
args: Vec<Value>,
133128
) -> EvalAction {
134-
let [Value::EcState { x0, y0, x1, y1 }, Value::EcPoint { x, y }]: [Value; 2] =
129+
let [Value::EcState { x: s_x, y: s_y }, Value::EcPoint { x, y }]: [Value; 2] =
135130
args.try_into().unwrap()
136131
else {
137132
panic!()
138133
};
139134

140-
let mut state = ProjectivePoint::from_affine(x0, y0).unwrap();
135+
if s_x.is_zero() && s_y.is_zero() {
136+
return EvalAction::NormalBranch(0, smallvec![Value::EcState { x, y }]);
137+
}
138+
let mut state = ProjectivePoint::from_affine(s_x, s_y).unwrap();
141139
let point = AffinePoint::new(x, y).unwrap();
142140

143141
state += &point;
144-
let state = state.to_affine().unwrap();
145-
146-
EvalAction::NormalBranch(
147-
0,
148-
smallvec![Value::EcState {
149-
x0: state.x(),
150-
y0: state.y(),
151-
x1,
152-
y1
153-
}],
154-
)
142+
let (x, y) = match state.to_affine() {
143+
Ok(state) => (state.x(), state.y()),
144+
Err(_) => (Felt::ZERO, Felt::ZERO),
145+
};
146+
EvalAction::NormalBranch(0, smallvec![Value::EcState { x, y }])
155147
}
156148

157149
fn eval_state_add_mul(
158150
_registry: &ProgramRegistry<CoreType, CoreLibfunc>,
159151
_info: &SignatureOnlyConcreteLibfunc,
160152
args: Vec<Value>,
161153
) -> EvalAction {
162-
let [ec @ Value::Unit, Value::EcState { x0, y0, x1, y1 }, Value::Felt(scalar), Value::EcPoint { x, y }]: [Value; 4] =
154+
let [ec @ Value::Unit, Value::EcState { x: s_x, y: s_y }, Value::Felt(scalar), Value::EcPoint { x, y }]: [Value; 4] =
163155
args.try_into().unwrap()
164156
else {
165157
panic!()
166158
};
167159

168-
let mut state = ProjectivePoint::from_affine(x0, y0).unwrap();
160+
let mut state = if s_x.is_zero() && s_y.is_zero() {
161+
ProjectivePoint::identity()
162+
} else {
163+
ProjectivePoint::from_affine(s_x, s_y).unwrap()
164+
};
169165
let point = ProjectivePoint::from_affine(x, y).unwrap();
170166

171167
state += &point.mul(scalar);
172-
let state = state.to_affine().unwrap();
173-
174-
EvalAction::NormalBranch(
175-
0,
176-
smallvec![
177-
ec,
178-
Value::EcState {
179-
x0: state.x(),
180-
y0: state.y(),
181-
x1,
182-
y1
183-
}
184-
],
185-
)
168+
let (x, y) = match state.to_affine() {
169+
Ok(state) => (state.x(), state.y()),
170+
Err(_) => (Felt::ZERO, Felt::ZERO),
171+
};
172+
EvalAction::NormalBranch(0, smallvec![ec, Value::EcState { x, y }])
186173
}
187174

188175
fn eval_state_finalize(
189176
_registry: &ProgramRegistry<CoreType, CoreLibfunc>,
190177
_info: &SignatureOnlyConcreteLibfunc,
191178
args: Vec<Value>,
192179
) -> EvalAction {
193-
let [Value::EcState { x0, y0, x1, y1 }]: [Value; 1] = args.try_into().unwrap() else {
180+
let [Value::EcState { x, y }]: [Value; 1] = args.try_into().unwrap() else {
194181
panic!()
195182
};
196183

197-
let state = ProjectivePoint::from_affine(x0, y0).unwrap();
198-
let random_point = ProjectivePoint::from_affine(x1, y1).unwrap();
199-
200-
if state.x() == random_point.x() && state.y() == random_point.y() {
184+
if x.is_zero() && y.is_zero() {
201185
EvalAction::NormalBranch(1, smallvec![])
202186
} else {
203-
let point = &state - &random_point;
204-
let point = point.to_affine().unwrap();
205-
EvalAction::NormalBranch(
206-
0,
207-
smallvec![Value::EcPoint {
208-
x: point.x(),
209-
y: point.y(),
210-
}],
211-
)
187+
EvalAction::NormalBranch(0, smallvec![Value::EcPoint { x, y }])
212188
}
213189
}
214190

@@ -244,22 +220,6 @@ fn eval_point_from_x(
244220
}
245221
}
246222

247-
fn random_ec_point() -> AffinePoint {
248-
// https://github.com/starkware-libs/cairo/blob/aaad921bba52e729dc24ece07fab2edf09ccfa15/crates/cairo-lang-runner/src/casm_run/mod.rs#L1802
249-
let mut rng = rand::rng();
250-
let (random_x, random_y) = loop {
251-
// Randominzing 31 bytes to make sure is in range.
252-
let x_bytes: [u8; 31] = rng.random();
253-
let random_x = Felt::from_bytes_be_slice(&x_bytes);
254-
let random_y_squared = random_x * random_x * random_x + random_x + BETA;
255-
if let Some(random_y) = random_y_squared.sqrt() {
256-
break (random_x, random_y);
257-
}
258-
};
259-
260-
AffinePoint::new(random_x, random_y).unwrap()
261-
}
262-
263223
fn eval_zero(
264224
_registry: &ProgramRegistry<CoreType, CoreLibfunc>,
265225
_info: &SignatureOnlyConcreteLibfunc,

debug_utils/sierra-emu/tests/common/mod.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,9 @@ pub fn value_to_felt(value: &Value) -> Vec<Felt> {
2929
felts.push(modulus.into());
3030
felts
3131
}
32-
Value::EcPoint { x, y } => {
32+
Value::EcPoint { x, y } | Value::EcState { x, y } => {
3333
vec![*x, *y]
3434
}
35-
Value::EcState { x0, y0, x1, y1 } => {
36-
vec![*x0, *y0, *x1, *y1]
37-
}
3835
Value::Enum {
3936
self_ty,
4037
index,

src/arch.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,9 @@ impl AbiArgument for ValueWithInfoWrapper<'_> {
112112
x.to_bytes(buffer)?;
113113
y.to_bytes(buffer)?;
114114
}
115-
(Value::EcState(x, y, x0, y0), CoreTypeConcrete::EcState(_)) => {
115+
(Value::EcState(x, y), CoreTypeConcrete::EcState(_)) => {
116116
x.to_bytes(buffer)?;
117117
y.to_bytes(buffer)?;
118-
x0.to_bytes(buffer)?;
119-
y0.to_bytes(buffer)?;
120118
}
121119
(Value::QM31(a, b, c, d), CoreTypeConcrete::QM31(_)) => {
122120
a.to_bytes(buffer)?;

0 commit comments

Comments
 (0)