Skip to content

Commit

Permalink
cairo: basic ec_add circuit test and failing contract
Browse files Browse the repository at this point in the history
  • Loading branch information
feltroidprime committed Jun 20, 2024
1 parent e533494 commit ce36474
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 51 deletions.
7 changes: 7 additions & 0 deletions src/cairo/Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@ version = 1
[[package]]
name = "garaga"
version = "0.1.0"

[[package]]
name = "garaga_contracts"
version = "0.1.0"
dependencies = [
"garaga",
]
6 changes: 5 additions & 1 deletion src/cairo/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ repository = "https://github.com/keep-starknet-strange/garaga"

# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html

[workspace]
members = ["garaga_contracts"]
[dependencies]

[dev-dependencies]
cairo_test = "2.6.4+nightly-2024-06-19"
cairo_test = "2.6.4+nightly-2024-06-19"
[cairo]
sierra-replace-ids = false
10 changes: 10 additions & 0 deletions src/cairo/garaga_contracts/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "garaga_contracts"
version = "0.1.0"
edition = "2023_11"

[dependencies]
garaga = { path = ".." }
starknet = "2.6.4"

[[target.starknet-contract]]
29 changes: 29 additions & 0 deletions src/cairo/garaga_contracts/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use garaga::definitions::{u384, u96, G1Point};

#[starknet::interface]
trait IGaraga<TContractState> {
fn get_p(self: @TContractState, curve_index: usize) -> (felt252, felt252, felt252, felt252);
fn ec_add_unchecked(self: @TContractState, inputs: Array<u384>, curve_index: usize) -> G1Point;
}

#[starknet::contract]
mod Garaga {
use core::array::ArrayTrait;
use garaga::definitions::{get_p, u384, G1Point, u96};
use garaga::ec_ops::{ec_add_unchecked2};
#[storage]
struct Storage {}

#[abi(embed_v0)]
impl IGaraga of super::IGaraga<ContractState> {
fn get_p(self: @ContractState, curve_index: usize) -> (felt252, felt252, felt252, felt252) {
let p = get_p(curve_index);
return (p.limb0.into(), p.limb1.into(), p.limb2.into(), p.limb3.into());
}
fn ec_add_unchecked(
self: @ContractState, inputs: Array<u384>, curve_index: usize
) -> G1Point {
return ec_add_unchecked2(inputs, curve_index);
}
}
}
3 changes: 3 additions & 0 deletions src/cairo/src/definitions.cairo
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use core::circuit::{u96, u384};

#[derive(Drop, Debug, PartialEq)]
struct G1Point {
x: u384,
y: u384,
}

#[derive(Drop, Debug, PartialEq)]
struct Fq2 {
a0: u384,
a1: u384,
}

#[derive(Drop, Debug, PartialEq)]
struct G2Point {
x: Fq2,
y: Fq2,
Expand Down
173 changes: 173 additions & 0 deletions src/cairo/src/ec_ops.cairo
Original file line number Diff line number Diff line change
@@ -1 +1,174 @@
use core::circuit::{
RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, circuit_sub,
circuit_mul, circuit_inverse, EvalCircuitResult, EvalCircuitTrait, u384, CircuitOutputsTrait,
CircuitModulus, FillInputResultTrait, CircuitInputs, FillInputResult
};
use garaga::definitions::{get_a, get_b, get_p, get_g, get_min_one, G1Point};


fn ec_add_unchecked(p1: G1Point, p2: G1Point, curve_index: usize) -> G1Point {
let in1 = CircuitElement::<CircuitInput<0>> {}; // px
let in2 = CircuitElement::<CircuitInput<1>> {}; // py
let in3 = CircuitElement::<CircuitInput<2>> {}; // qx
let in4 = CircuitElement::<CircuitInput<3>> {}; // qy

let t0 = circuit_sub(in2, in4);
let t1 = circuit_sub(in1, in3);
let t2 = circuit_inverse(t1);
let t3 = circuit_mul(t0, t2); // slope
let t4 = circuit_mul(t3, t3); // slope^2

let t5 = circuit_sub(t4, in1); // slope^2 - px
let t6 = circuit_sub(t5, in3); // nx

let t7 = circuit_sub(in1, t6); // px - nx
let t8 = circuit_mul(t3, t7); // slope * (px - nx)
let t9 = circuit_sub(t8, in2); // ny

let p = get_p(curve_index);
let modulus = TryInto::<_, CircuitModulus>::try_into([p.limb0, p.limb1, p.limb2, p.limb3])
.unwrap();
let outputs =
match (t9,).new_inputs().next(p1.x).next(p1.y).next(p2.x).next(p2.y).done().eval(modulus) {
EvalCircuitResult::Success(outputs) => { outputs },
EvalCircuitResult::Failure((_, _)) => { panic!("Expected success") }
};

let x = outputs.get_output(t6);
let y = outputs.get_output(t9);

return G1Point { x: x, y: y };
}


fn ec_add_unchecked2(input: Array<u384>, curve_index: usize) -> G1Point {
let in1 = CircuitElement::<CircuitInput<0>> {}; // px
let in2 = CircuitElement::<CircuitInput<1>> {}; // py
let in3 = CircuitElement::<CircuitInput<2>> {}; // qx
let in4 = CircuitElement::<CircuitInput<3>> {}; // qy

let t0 = circuit_sub(in2, in4);
let t1 = circuit_sub(in1, in3);
let t2 = circuit_inverse(t1);
let t3 = circuit_mul(t0, t2); // slope
let t4 = circuit_mul(t3, t3); // slope^2

let t5 = circuit_sub(t4, in1); // slope^2 - px
let t6 = circuit_sub(t5, in3); // nx

let t7 = circuit_sub(in1, t6); // px - nx
let t8 = circuit_mul(t3, t7); // slope * (px - nx)
let t9 = circuit_sub(t8, in2); // ny

let p = get_p(curve_index);
let modulus = TryInto::<_, CircuitModulus>::try_into([p.limb0, p.limb1, p.limb2, p.limb3])
.unwrap();

let ins0 = *input.at(0);
let ins1 = *input.at(1);
let ins2 = *input.at(2);
let ins3 = *input.at(3);

let outputs =
match (t9,).new_inputs().next(ins0).next(ins1).next(ins2).next(ins3).done().eval(modulus) {
EvalCircuitResult::Success(outputs) => { outputs },
EvalCircuitResult::Failure((_, _)) => { panic!("Expected success") }
};

let x = outputs.get_output(t6);
let y = outputs.get_output(t9);

return G1Point { x: x, y: y };
}

#[cfg(test)]
mod tests {
use core::traits::TryInto;

use core::circuit::{
RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, circuit_sub,
circuit_mul, circuit_inverse, EvalCircuitResult, EvalCircuitTrait, u384,
CircuitOutputsTrait, CircuitModulus, FillInputResultTrait, CircuitInputs,
};

use super::{ec_add_unchecked, ec_add_unchecked2, G1Point};

#[test]
fn test_ec_add_unchecked() {
let p1 = G1Point {
x: u384 { limb0: 1, limb1: 0, limb2: 0, limb3: 0 },
y: u384 { limb0: 2, limb1: 0, limb2: 0, limb3: 0 }
};
let p2 = G1Point {
x: u384 {
limb0: 6972010542290859298145161171,
limb1: 48130984231937642362735957673,
limb2: 217937391675185666,
limb3: 0
},
y: u384 {
limb0: 70354117060174814309938406084,
limb1: 71651066881622725552431866953,
limb2: 1580046089645096082,
limb3: 0
}
};
let p3 = ec_add_unchecked(p1, p2, 0);
assert_eq!(
p3,
G1Point {
x: u384 {
limb0: 6722715950901854229040049136,
limb1: 75516999847165085857686607943,
limb2: 534168702278167103,
limb3: 0
},
y: u384 {
limb0: 3593358890951276345950085729,
limb1: 26402767470382383152362316724,
limb2: 3078097915416712233,
limb3: 0
}
}
);
}

#[test]
fn test_ec_add_unchecked2() {
let inputs = array![
u384 { limb0: 1, limb1: 0, limb2: 0, limb3: 0 },
u384 { limb0: 2, limb1: 0, limb2: 0, limb3: 0 },
u384 {
limb0: 6972010542290859298145161171,
limb1: 48130984231937642362735957673,
limb2: 217937391675185666,
limb3: 0
},
u384 {
limb0: 70354117060174814309938406084,
limb1: 71651066881622725552431866953,
limb2: 1580046089645096082,
limb3: 0
}
];

let p3 = ec_add_unchecked2(inputs, 0);
assert_eq!(
p3,
G1Point {
x: u384 {
limb0: 6722715950901854229040049136,
limb1: 75516999847165085857686607943,
limb2: 534168702278167103,
limb3: 0
},
y: u384 {
limb0: 3593358890951276345950085729,
limb1: 26402767470382383152362316724,
limb2: 3078097915416712233,
limb3: 0
}
}
);
}
}
89 changes: 39 additions & 50 deletions src/cairo/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ mod definitions;
mod utils;
mod ec_ops;


#[cfg(test)]
mod tests {
use core::traits::TryInto;

use core::circuit::{
RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, CircuitDefinition,
circuit_add, circuit_sub, circuit_mul, circuit_inverse, EvalCircuitResult, FillInputResult,
u384, CircuitOutputsTrait, CircuitModulus
RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, circuit_sub,
circuit_mul, circuit_inverse, EvalCircuitResult, EvalCircuitTrait, u384,
CircuitOutputsTrait, CircuitModulus, FillInputResultTrait, CircuitInputs,
};
use super::utils::{scalar_to_base_neg3_le, neg_3_base_le};

Expand All @@ -24,56 +26,43 @@ mod tests {
core::internal::require_implicit::<AddMod>();
core::internal::require_implicit::<MulMod>();
}
// #[test]
// fn test_circuit_success() {
// let in1 = CircuitElement::<CircuitInput<0>> {};
// let in2 = CircuitElement::<CircuitInput<1>> {};
// let add = circuit_add(in1, in2);
// let inv = circuit_inverse(add);
// let sub = circuit_sub(inv, in2);
// let mul = circuit_mul(inv, sub);
// let circ = (mul,);
// let inputs = circ.init();

// let inputs = match inputs.fill_input([3, 0, 0, 0]) {
// FillInputResult::More(new_inputs) => new_inputs,
// FillInputResult::Done(_data) => { panic!("Expected more inputs") }
// };
// let data = match inputs.fill_input([6, 0, 0, 0]) {
// FillInputResult::More(_new_inputs) => panic!("Expected Done"),
// FillInputResult::Done(data) => data
// };

// let modulus = TryInto::<_, CircuitModulus>::try_into([7, 0, 0, 0]).unwrap();
// let outputs = match circ.get_descriptor().eval(data, modulus) {
// EvalCircuitResult::Success(outputs) => { outputs },
// EvalCircuitResult::Failure((_, _)) => { panic!("Expected success") }
// };

// assert_eq!(outputs.get_output(add), u384 { limb0: 2, limb1: 0, limb2: 0, limb3: 0 });
// assert_eq!(outputs.get_output(inv), u384 { limb0: 4, limb1: 0, limb2: 0, limb3: 0 });
// assert_eq!(outputs.get_output(sub), u384 { limb0: 5, limb1: 0, limb2: 0, limb3: 0 });
// assert_eq!(outputs.get_output(mul), u384 { limb0: 6, limb1: 0, limb2: 0, limb3: 0 });
// }
#[test]
fn test_circuit_success() {
let in1 = CircuitElement::<CircuitInput<0>> {};
let in2 = CircuitElement::<CircuitInput<1>> {};
let add = circuit_add(in1, in2);
let inv = circuit_inverse(add);
let sub = circuit_sub(inv, in2);
let mul = circuit_mul(inv, sub);

// #[test]
// fn test_circuit_failure() {
// let in0 = CircuitElement::<CircuitInput<0>> {};
// let out0 = circuit_inverse(in0);
// let circ = (out0,);
// let inputs = circ.init();
let modulus = TryInto::<_, CircuitModulus>::try_into([7, 0, 0, 0]).unwrap();
let outputs =
match (mul, add, inv)
.new_inputs()
.next([3, 0, 0, 0])
.next([6, 0, 0, 0])
.done()
.eval(modulus) {
EvalCircuitResult::Success(outputs) => { outputs },
EvalCircuitResult::Failure((_, _)) => { panic!("Expected success") }
};

// let data = match inputs.fill_input([11, 0, 0, 0]) {
// FillInputResult::More(_new_inputs) => panic!("Expected Done"),
// FillInputResult::Done(data) => data
// };
assert_eq!(outputs.get_output(add), u384 { limb0: 2, limb1: 0, limb2: 0, limb3: 0 });
assert_eq!(outputs.get_output(inv), u384 { limb0: 4, limb1: 0, limb2: 0, limb3: 0 });
assert_eq!(outputs.get_output(sub), u384 { limb0: 5, limb1: 0, limb2: 0, limb3: 0 });
assert_eq!(outputs.get_output(mul), u384 { limb0: 6, limb1: 0, limb2: 0, limb3: 0 });
}

// let modulus = TryInto::<_, CircuitModulus>::try_into([55, 0, 0, 0]).unwrap();

// match circ.get_descriptor().eval(data, modulus) {
// EvalCircuitResult::Failure((_, _)) => {},
// EvalCircuitResult::Success(_outputs) => { panic!("Expected failure"); }
// }
// }
#[test]
fn test_circuit_failure() {
let in0 = CircuitElement::<CircuitInput<0>> {};
let out0 = circuit_inverse(in0);

let modulus = TryInto::<_, CircuitModulus>::try_into([55, 0, 0, 0]).unwrap();
match (out0,).new_inputs().next([11, 0, 0, 0]).done().eval(modulus) {
EvalCircuitResult::Failure((_, _)) => {},
EvalCircuitResult::Success(_outputs) => { panic!("Expected failure"); }
}
}
}

0 comments on commit ce36474

Please sign in to comment.