Skip to content

Commit 1ee079c

Browse files
it works
will see if I can make it work with the expression builder framework
1 parent 2a0a2e5 commit 1ee079c

File tree

12 files changed

+348
-305
lines changed

12 files changed

+348
-305
lines changed

Cargo.lock

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

extensions/ecc/circuit/src/edwards_chip/add.rs

Lines changed: 67 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
use std::{cell::RefCell, iter, rc::Rc, sync::Arc};
1+
use std::{cell::RefCell, iter, rc::Rc};
22

33
use itertools::{zip_eq, Itertools};
4-
use num_bigint_dig::BigUint;
5-
use num_traits::One;
4+
use num_bigint::BigUint;
5+
use num_traits::{One, Zero};
66
use openvm_circuit::arch::{
77
AdapterAirContext, AdapterRuntimeContext, DynAdapterInterface, DynArray, MinimalInstruction,
88
Result, VmAdapterInterface, VmCoreAir, VmCoreChip,
99
};
1010
use openvm_circuit_primitives::{
1111
bigint::utils::big_uint_to_num_limbs,
12-
var_range::{VariableRangeCheckerBus, VariableRangeCheckerChip},
12+
var_range::{SharedVariableRangeCheckerChip, VariableRangeCheckerBus},
1313
SubAir, TraceSubRowGenerator,
1414
};
15-
use openvm_ecc_transpiler::Rv32WeierstrassOpcode;
15+
use openvm_ecc_transpiler::Rv32EdwardsOpcode;
1616
use openvm_instructions::instruction::Instruction;
1717
use openvm_mod_circuit_builder::{
1818
utils::{biguint_to_limbs_vec, limbs_to_biguint},
@@ -51,9 +51,6 @@ impl TeEcAddCoreAir {
5151
let builder = ExprBuilder::new(config, range_bus.range_max_bits);
5252
let builder = Rc::new(RefCell::new(builder));
5353

54-
// TODO: do the setup row, if needed
55-
// might have to define a CoreChip and CoreAir
56-
5754
let x1 = ExprBuilder::new_input(builder.clone());
5855
let y1 = ExprBuilder::new_input(builder.clone());
5956
let x2 = ExprBuilder::new_input(builder.clone());
@@ -76,11 +73,9 @@ impl TeEcAddCoreAir {
7673

7774
let builder = builder.borrow().clone();
7875

79-
let expr = FieldExpr::new_with_setup_values(
80-
builder,
81-
range_bus,
82-
true,
83-
vec![a_biguint.clone(), d_biguint.clone()],
76+
let expr = FieldExpr::new(
77+
builder, range_bus, true,
78+
//vec![a_biguint.clone(), d_biguint.clone()],
8479
);
8580
Self {
8681
expr,
@@ -117,8 +112,7 @@ where
117112
) -> AdapterAirContext<AB::Expr, I> {
118113
assert_eq!(local.len(), BaseAir::<AB::F>::width(&self.expr));
119114

120-
// TODO
121-
//self.expr.eval(builder, local);
115+
self.expr.eval(builder, local);
122116

123117
let FieldExprCols {
124118
is_valid,
@@ -131,7 +125,6 @@ where
131125
assert_eq!(vars.len(), 12);
132126
assert_eq!(flags.len(), 1);
133127

134-
//let reads: Vec<AB::Expr> = inputs.into_iter().flatten().map(Into::into).collect();
135128
let reads: Vec<AB::Expr> = inputs
136129
.clone()
137130
.into_iter()
@@ -148,35 +141,15 @@ where
148141
let is_setup = is_valid - flags[0];
149142
builder.assert_bool(is_setup.clone());
150143
let local_opcode_idx = flags[0]
151-
* AB::Expr::from_canonical_usize(Rv32WeierstrassOpcode::EC_DOUBLE as usize)
144+
* AB::Expr::from_canonical_usize(Rv32EdwardsOpcode::EC_ADD as usize)
152145
+ is_setup.clone()
153-
* AB::Expr::from_canonical_usize(Rv32WeierstrassOpcode::SETUP_EC_DOUBLE as usize);
154-
155-
let dbg = iter::empty()
156-
.chain(self.expr.builder.prime_limbs.clone())
157-
.chain(big_uint_to_num_limbs(
158-
&self.a_biguint,
159-
self.expr.builder.limb_bits,
160-
self.expr.builder.num_limbs,
161-
))
162-
.chain(big_uint_to_num_limbs(
163-
&self.d_biguint,
164-
self.expr.builder.limb_bits,
165-
self.expr.builder.num_limbs,
166-
))
167-
.collect_vec();
168-
println!("dbg: {:?}", dbg);
146+
* AB::Expr::from_canonical_usize(Rv32EdwardsOpcode::SETUP_EC_ADD as usize);
169147

170-
// when is_setup, assert `reads` equals `(modulus, a)`
148+
// when is_setup, assert `reads` equals `(modulus, a, d, 0)`
171149
for (lhs, &rhs) in zip_eq(
172-
//&reads,
173-
inputs
174-
.into_iter()
175-
.flatten()
176-
.map(Into::into)
177-
.take(1 * self.expr.builder.num_limbs),
178-
iter::empty().chain(&self.expr.builder.prime_limbs),
179-
/*
150+
&reads,
151+
iter::empty()
152+
.chain(&self.expr.builder.prime_limbs)
180153
.chain(&big_uint_to_num_limbs(
181154
&self.a_biguint,
182155
self.expr.builder.limb_bits,
@@ -186,13 +159,12 @@ where
186159
&self.d_biguint,
187160
self.expr.builder.limb_bits,
188161
self.expr.builder.num_limbs,
162+
))
163+
.chain(&big_uint_to_num_limbs(
164+
&BigUint::zero(),
165+
self.expr.builder.limb_bits,
166+
self.expr.builder.num_limbs,
189167
)),
190-
.chain(&big_uint_to_num_limbs(
191-
&BigUint::default(),
192-
self.expr.builder.limb_bits,
193-
self.expr.builder.num_limbs,
194-
)),
195-
*/
196168
) {
197169
builder
198170
.when(is_setup.clone())
@@ -212,17 +184,21 @@ where
212184
};
213185
ctx.into()
214186
}
187+
188+
fn start_offset(&self) -> usize {
189+
self.offset
190+
}
215191
}
216192

217193
pub struct TeEcAddCoreChip {
218194
pub air: TeEcAddCoreAir,
219-
pub range_checker: Arc<VariableRangeCheckerChip>,
195+
pub range_checker: SharedVariableRangeCheckerChip,
220196
}
221197

222198
impl TeEcAddCoreChip {
223199
pub fn new(
224200
config: ExprBuilderConfig,
225-
range_checker: Arc<VariableRangeCheckerChip>,
201+
range_checker: SharedVariableRangeCheckerChip,
226202
a_biguint: BigUint,
227203
d_biguint: BigUint,
228204
offset: usize,
@@ -243,7 +219,7 @@ pub struct TeEcAddCoreRecord {
243219
pub x2: BigUint,
244220
#[serde_as(as = "DisplayFromStr")]
245221
pub y2: BigUint,
246-
pub is_double_flag: bool,
222+
pub is_add_flag: bool,
247223
}
248224

249225
impl<F: PrimeField32, I> VmCoreChip<F, I> for TeEcAddCoreChip
@@ -291,7 +267,7 @@ where
291267
let x2_biguint = limbs_to_biguint(&x2, limb_bits);
292268
let y2_biguint = limbs_to_biguint(&y2, limb_bits);
293269

294-
let is_double_flag = local_opcode_idx == Rv32WeierstrassOpcode::EC_DOUBLE as usize;
270+
let is_add_flag = local_opcode_idx == Rv32EdwardsOpcode::EC_ADD as usize;
295271

296272
let vars = self.air.expr.execute(
297273
vec![
@@ -300,7 +276,7 @@ where
300276
x2_biguint.clone(),
301277
y2_biguint.clone(),
302278
],
303-
vec![is_double_flag],
279+
vec![is_add_flag],
304280
);
305281
assert_eq!(vars.len(), 12);
306282

@@ -323,7 +299,7 @@ where
323299
y1: y1_biguint,
324300
x2: x2_biguint,
325301
y2: y2_biguint,
326-
is_double_flag,
302+
is_add_flag,
327303
},
328304
))
329305
}
@@ -335,9 +311,9 @@ where
335311
fn generate_trace_row(&self, row_slice: &mut [F], record: Self::Record) {
336312
self.air.expr.generate_subrow(
337313
(
338-
&self.range_checker,
314+
self.range_checker.as_ref(),
339315
vec![record.x1, record.y1, record.x2, record.y2],
340-
vec![record.is_double_flag],
316+
vec![record.is_add_flag],
341317
),
342318
row_slice,
343319
);
@@ -354,15 +330,42 @@ where
354330
}
355331
let core_width = <Self::Air as BaseAir<F>>::width(&self.air);
356332
let adapter_width = trace.width() - core_width;
357-
// We will be setting is_valid = 0. That forces is_double to be 0 (otherwise setup will be -1).
358-
// So the computation is like doing setup.
359-
// Thus we will copy over the first row (which is a setup row) and set is_valid = 0.
360-
let first_row = trace.rows().nth(0).unwrap().collect::<Vec<_>>();
361-
let first_row_core = first_row.split_at(adapter_width).1;
333+
let dummy_row = self.generate_dummy_trace_row(adapter_width, core_width);
362334
for row in trace.rows_mut().skip(num_records) {
363-
let core_row = row.split_at_mut(adapter_width).1;
364-
core_row.copy_from_slice(first_row_core);
365-
core_row[0] = F::ZERO; // is_valid = 0
335+
row.copy_from_slice(&dummy_row);
366336
}
367337
}
368338
}
339+
340+
impl TeEcAddCoreChip {
341+
// We will be setting is_valid = 0. That forces is_add to be 0 (otherwise setup will be -1).
342+
// We generate a dummy row with is_add = 0, then we set is_valid = 0.
343+
fn generate_dummy_trace_row<F: PrimeField32>(
344+
&self,
345+
adapter_width: usize,
346+
core_width: usize,
347+
) -> Vec<F> {
348+
let record = TeEcAddCoreRecord {
349+
x1: BigUint::zero(),
350+
y1: BigUint::zero(),
351+
x2: BigUint::zero(),
352+
y2: BigUint::zero(),
353+
is_add_flag: false,
354+
};
355+
let mut row = vec![F::ZERO; adapter_width + core_width];
356+
let core_row = &mut row[adapter_width..];
357+
// We **do not** want this trace row to update the range checker
358+
// so we must create a temporary range checker
359+
let tmp_range_checker = SharedVariableRangeCheckerChip::new(self.range_checker.bus());
360+
self.air.expr.generate_subrow(
361+
(
362+
tmp_range_checker.as_ref(),
363+
vec![record.x1, record.y1, record.x2, record.y2],
364+
vec![record.is_add_flag],
365+
),
366+
core_row,
367+
);
368+
core_row[0] = F::ZERO; // is_valid = 0
369+
row
370+
}
371+
}

extensions/ecc/circuit/src/edwards_chip/mod.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ mod tests;
66

77
use std::sync::{Arc, Mutex};
88

9-
use num_bigint_dig::{algorithms::jacobi, BigUint};
9+
// TODO figure out how to do jacobi symbol for num_bigint::BigUint
10+
//use num_bigint::{algorithms::jacobi, BigUint};
11+
use num_bigint::BigUint;
1012
use openvm_circuit::{arch::VmChipWrapper, system::memory::OfflineMemory};
11-
use openvm_circuit_derive::{InstructionExecutor, Stateful};
12-
use openvm_circuit_primitives::var_range::VariableRangeCheckerChip;
13-
use openvm_circuit_primitives_derive::{Chip, ChipUsageGetter};
13+
use openvm_circuit_derive::InstructionExecutor;
14+
use openvm_circuit_primitives::var_range::SharedVariableRangeCheckerChip;
15+
use openvm_circuit_primitives_derive::{BytesStateful, Chip, ChipUsageGetter};
1416
use openvm_ecc_transpiler::Rv32EdwardsOpcode;
1517
use openvm_mod_circuit_builder::{ExprBuilderConfig, FieldExpressionCoreChip};
1618
use openvm_rv32_adapters::Rv32VecHeapAdapterChip;
@@ -68,7 +70,7 @@ impl<F: PrimeField32, const BLOCKS: usize, const BLOCK_SIZE: usize>
6870
/// BLOCKS: how many blocks do we need to represent one input or output
6971
/// For example, for bls12_381, BLOCK_SIZE = 16, each element has 3 blocks and with two elements per input AffinePoint, BLOCKS = 6.
7072
/// For secp256k1, BLOCK_SIZE = 32, BLOCKS = 2.
71-
#[derive(Chip, ChipUsageGetter, InstructionExecutor, Stateful)]
73+
#[derive(Chip, ChipUsageGetter, InstructionExecutor, BytesStateful)]
7274
pub struct TeEcAddChip<F: PrimeField32, const BLOCKS: usize, const BLOCK_SIZE: usize>(
7375
VmChipWrapper<
7476
F,
@@ -86,12 +88,13 @@ impl<F: PrimeField32, const BLOCKS: usize, const BLOCK_SIZE: usize>
8688
offset: usize,
8789
a: BigUint,
8890
d: BigUint,
89-
range_checker: Arc<VariableRangeCheckerChip>,
91+
range_checker: SharedVariableRangeCheckerChip,
9092
offline_memory: Arc<Mutex<OfflineMemory<F>>>,
9193
) -> Self {
9294
// Ensure that the addition operation is complete
93-
assert!(jacobi(&a.clone().into(), &config.modulus.clone().into()) == 1);
94-
assert!(jacobi(&d.clone().into(), &config.modulus.clone().into()) == -1);
95+
// TODO fix
96+
//assert!(jacobi(&a.clone().into(), &config.modulus.clone().into()) == 1);
97+
//assert!(jacobi(&d.clone().into(), &config.modulus.clone().into()) == -1);
9598
let core = TeEcAddCoreChip::new(config, range_checker.clone(), a, d, offset);
9699
Self(VmChipWrapper::new(adapter, core, offline_memory))
97100
}

extensions/ecc/guest/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ openvm-algebra-guest = { workspace = true }
2323
openvm-ecc-sw-setup = { workspace = true }
2424
openvm-ecc-te-setup = { workspace = true }
2525
openvm-algebra-moduli-setup = { workspace = true }
26+
num-bigint = { workspace = true }
2627

2728
# Used for `halo2curves` feature
2829
# TODO[yj]: Transition to PSE halo2curves

extensions/ecc/guest/src/edwards.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,11 @@ use openvm_algebra_guest::{Field, IntMod};
44

55
pub trait TwistedEdwardsPoint: Sized {
66
/// The `a` coefficient in the twisted Edwards curve equation `ax^2 + y^2 = 1 + d x^2 y^2`.
7-
const CURVE_A_BYTES: &[u8];
7+
const CURVE_A: Self::Coordinate;
88
/// The `d` coefficient in the twisted Edwards curve equation `ax^2 + y^2 = 1 + d x^2 y^2`.
9-
const CURVE_D_BYTES: &[u8];
9+
const CURVE_D: Self::Coordinate;
1010
const IDENTITY: Self;
1111

12-
fn curve_a() -> Self::Coordinate {
13-
Self::Coordinate::from_le_bytes(Self::CURVE_A_BYTES)
14-
}
15-
fn curve_d() -> Self::Coordinate {
16-
Self::Coordinate::from_le_bytes(Self::CURVE_D_BYTES)
17-
}
18-
1912
type Coordinate: IntMod + Field;
2013
const ZERO: Self::Coordinate = <Self::Coordinate as IntMod>::ZERO;
2114
const ONE: Self::Coordinate = <Self::Coordinate as IntMod>::ONE;
@@ -52,8 +45,8 @@ pub trait TwistedEdwardsPoint: Sized {
5245
where
5346
for<'a> &'a Self::Coordinate: Mul<&'a Self::Coordinate, Output = Self::Coordinate>,
5447
{
55-
let lhs = &Self::curve_a() * &x * &x + &y * &y;
56-
let rhs = &Self::curve_d() * &x * &x * &y * &y + &Self::ONE;
48+
let lhs = Self::CURVE_A * &x * &x + &y * &y;
49+
let rhs = Self::CURVE_D * &x * &x * &y * &y + &Self::ONE;
5750
if lhs != rhs {
5851
return None;
5952
}

extensions/ecc/te-setup/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ repository.workspace = true
1010
syn = { version = "2.0", features = ["full"] }
1111
quote = "1.0"
1212
openvm-macros-common = { workspace = true, default-features = false }
13-
num-bigint-dig = "0.8.4"
13+
num-bigint.workspace = true
1414
proc-macro2 = "1.0.38"
1515

1616
[lib]

0 commit comments

Comments
 (0)