Skip to content

Commit

Permalink
finished a buggy addition
Browse files Browse the repository at this point in the history
  • Loading branch information
zhenfeizhang committed Dec 3, 2024
1 parent 341718b commit 45c8b85
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 42 deletions.
1 change: 1 addition & 0 deletions rsa_circuit/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod native;
mod u120_add;
mod u120_mul;
mod u120_comp;
mod u2048_add;
mod u2048_comp;
mod util;
124 changes: 124 additions & 0 deletions rsa_circuit/src/tests/u120_comp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use std::mem::transmute;
use expander_compiler::frontend::*;
use expander_compiler::{declare_circuit, frontend::{BN254Config, Define, Variable, API}};
use halo2curves::bn256::Fr;

use crate::constants::MASK120;
use crate::u120::is_less_than_u120;

declare_circuit!(LessThanCircuit {
x: Variable,
y: Variable,
result: Variable,
});

impl Define<BN254Config> for LessThanCircuit<Variable> {
fn define(&self, builder: &mut API<BN254Config>) {
let res = is_less_than_u120(&self.x, &self.y, builder);
builder.assert_is_equal(res, self.result);
}
}

impl LessThanCircuit<Fr> {
fn create_circuit(x: [u64; 2], y: [u64; 2], result: [u64; 2]) -> LessThanCircuit<Fr> {
Self {
x: Fr::from_raw([x[0], x[1], 0, 0]),
y: Fr::from_raw([y[0], y[1], 0, 0]),
result: Fr::from_raw([result[0], result[1], 0, 0]),
}
}
}

#[test]
fn test_u120_less_than() {
let compile_result = compile(&LessThanCircuit::default()).unwrap();

{
// Test case: Simple less than
let x = [5, 0];
let y = [10, 0];
let result = [1, 0]; // true: 5 < 10

let assignment = LessThanCircuit::<Fr>::create_circuit(x, y, result);
let witness = compile_result.witness_solver.solve_witness(&assignment).unwrap();
let output = compile_result.layered_circuit.run(&witness);
assert_eq!(output, vec![true]);
}
{
// Test case: Equal values
let x = [42, 0];
let y = [42, 0];
let result = [0, 0]; // false: 42 = 42

let assignment = LessThanCircuit::<Fr>::create_circuit(x, y, result);
let witness = compile_result.witness_solver.solve_witness(&assignment).unwrap();
let output = compile_result.layered_circuit.run(&witness);
assert_eq!(output, vec![true]);
}
{
// Test case: Greater than
let x = [100, 0];
let y = [50, 0];
let result = [0, 0]; // false: 100 > 50

let assignment = LessThanCircuit::<Fr>::create_circuit(x, y, result);
let witness = compile_result.witness_solver.solve_witness(&assignment).unwrap();
let output = compile_result.layered_circuit.run(&witness);
assert_eq!(output, vec![true]);
}
{
// Test case: Using second limb
let x = [0, 1]; // 2^64
let y = [u64::MAX, 0];
let result = [0, 0]; // false: 2^64 > u64::MAX

let assignment = LessThanCircuit::<Fr>::create_circuit(x, y, result);
let witness = compile_result.witness_solver.solve_witness(&assignment).unwrap();
let output = compile_result.layered_circuit.run(&witness);
assert_eq!(output, vec![true]);
}
{
// Test case: Large numbers near 120-bit limit
let x = unsafe { transmute(MASK120 - 1) }; // 2^120 - 2
let y = unsafe { transmute(MASK120) }; // 2^120 - 1
let result = [1, 0]; // true: (2^120 - 2) < (2^120 - 1)

let assignment = LessThanCircuit::<Fr>::create_circuit(x, y, result);
let witness = compile_result.witness_solver.solve_witness(&assignment).unwrap();
let output = compile_result.layered_circuit.run(&witness);
assert_eq!(output, vec![true]);
}
{
// Test case: Equal large numbers
let x = unsafe { transmute(MASK120) }; // 2^120 - 1
let y = unsafe { transmute(MASK120) }; // 2^120 - 1
let result = [0, 0]; // false: equal values

let assignment = LessThanCircuit::<Fr>::create_circuit(x, y, result);
let witness = compile_result.witness_solver.solve_witness(&assignment).unwrap();
let output = compile_result.layered_circuit.run(&witness);
assert_eq!(output, vec![true]);
}
{
// Test case: Negative case (incorrect result)
let x = [5, 0];
let y = [10, 0];
let result = [0, 0]; // incorrect: should be 1 since 5 < 10

let assignment = LessThanCircuit::<Fr>::create_circuit(x, y, result);
let witness = compile_result.witness_solver.solve_witness(&assignment).unwrap();
let output = compile_result.layered_circuit.run(&witness);
assert_eq!(output, vec![false]);
}
{
// Test case: Negative case (incorrect result)
let x = [5, 0];
let y = [5, 0];
let result = [1, 0]; // incorrect: should be 0 since 5 = 5

let assignment = LessThanCircuit::<Fr>::create_circuit(x, y, result);
let witness = compile_result.witness_solver.solve_witness(&assignment).unwrap();
let output = compile_result.layered_circuit.run(&witness);
assert_eq!(output, vec![false]);
}
}
75 changes: 37 additions & 38 deletions rsa_circuit/src/tests/u2048_comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl Define<BN254Config> for CompareCircuit<Variable> {
let x = U2048Variable { limbs: self.x };
let y = U2048Variable { limbs: self.y };

let comparison_result = x.unconstrained_greater_eq(&y, builder);
let comparison_result = x.assert_is_less_than(&y, builder);
builder.assert_is_equal(comparison_result, self.result);
}
}
Expand Down Expand Up @@ -54,7 +54,7 @@ fn test_u2048_comparison() {
let x = vec![5; N_LIMBS];
let y = vec![5; N_LIMBS];

let assignment = CompareCircuit::<Fr>::create_circuit(x, y, true);
let assignment = CompareCircuit::<Fr>::create_circuit(x, y, false); // x < y is false when equal
let witness = compile_result
.witness_solver
.solve_witness(&assignment)
Expand All @@ -65,13 +65,13 @@ fn test_u2048_comparison() {
}

{
// Test case: Greater in most significant limb
// Test case: Less than in most significant limb
let mut x = vec![0; N_LIMBS];
let mut y = vec![0; N_LIMBS];
x[N_LIMBS - 1] = 10;
y[N_LIMBS - 1] = 5;
x[N_LIMBS - 1] = 5;
y[N_LIMBS - 1] = 10;

let assignment = CompareCircuit::<Fr>::create_circuit(x, y, true);
let assignment = CompareCircuit::<Fr>::create_circuit(x, y, true); // x < y is true
let witness = compile_result
.witness_solver
.solve_witness(&assignment)
Expand All @@ -82,13 +82,13 @@ fn test_u2048_comparison() {
}

{
// Test case: Less in most significant limb
// Test case: Greater in most significant limb
let mut x = vec![0; N_LIMBS];
let mut y = vec![0; N_LIMBS];
x[N_LIMBS - 1] = 5;
y[N_LIMBS - 1] = 10;
x[N_LIMBS - 1] = 10;
y[N_LIMBS - 1] = 5;

let assignment = CompareCircuit::<Fr>::create_circuit(x, y, false);
let assignment = CompareCircuit::<Fr>::create_circuit(x, y, false); // x < y is false
let witness = compile_result
.witness_solver
.solve_witness(&assignment)
Expand All @@ -99,15 +99,15 @@ fn test_u2048_comparison() {
}

{
// Test case: Equal in most significant limb, greater in next limb
// Test case: Equal in most significant limb, less than in next limb
let mut x = vec![0; N_LIMBS];
let mut y = vec![0; N_LIMBS];
x[N_LIMBS - 1] = 5;
y[N_LIMBS - 1] = 5;
x[N_LIMBS - 2] = 10;
y[N_LIMBS - 2] = 5;
x[N_LIMBS - 2] = 5;
y[N_LIMBS - 2] = 10;

let assignment = CompareCircuit::<Fr>::create_circuit(x, y, true);
let assignment = CompareCircuit::<Fr>::create_circuit(x, y, true); // x < y is true
let witness = compile_result
.witness_solver
.solve_witness(&assignment)
Expand All @@ -119,11 +119,11 @@ fn test_u2048_comparison() {

// Negative test cases
{
// Negative test: Claiming x >= y when x < y
// Negative test: Claiming x < y when x > y
let mut x = vec![0; N_LIMBS];
let mut y = vec![0; N_LIMBS];
x[N_LIMBS - 1] = 5;
y[N_LIMBS - 1] = 10;
x[N_LIMBS - 1] = 10;
y[N_LIMBS - 1] = 5;

let assignment = CompareCircuit::<Fr>::create_circuit(x, y, true); // incorrect result
let witness = compile_result
Expand All @@ -140,7 +140,7 @@ fn test_u2048_comparison() {
let x = vec![5; N_LIMBS];
let y = vec![5; N_LIMBS];

let assignment = CompareCircuit::<Fr>::create_circuit(x, y, false); // incorrect result
let assignment = CompareCircuit::<Fr>::create_circuit(x, y, true); // incorrect result
let witness = compile_result
.witness_solver
.solve_witness(&assignment)
Expand All @@ -150,23 +150,22 @@ fn test_u2048_comparison() {
assert_eq!(output, vec![false]); // should fail
}

// {
// // soundness bug: this test should fail but it passes
// // Negative test: Equal in most significant limbs but claiming wrong result for lower limbs
// let mut x = vec![0; N_LIMBS];
// let mut y = vec![0; N_LIMBS];
// x[N_LIMBS - 1] = 5;
// y[N_LIMBS - 1] = 5;
// x[N_LIMBS - 2] = 4;
// y[N_LIMBS - 2] = 5;

// let assignment = CompareCircuit::<Fr>::create_circuit(x, y, true); // incorrect result
// let witness = compile_result
// .witness_solver
// .solve_witness(&assignment)
// .unwrap();

// let output = compile_result.layered_circuit.run(&witness);
// assert_eq!(output, vec![false]); // should fail
// }
}
{
// Test case: Equal in most significant limb, comparison in lower limb
let mut x = vec![0; N_LIMBS];
let mut y = vec![0; N_LIMBS];
x[N_LIMBS - 1] = 5;
y[N_LIMBS - 1] = 5;
x[N_LIMBS - 2] = 4;
y[N_LIMBS - 2] = 5;

let assignment = CompareCircuit::<Fr>::create_circuit(x, y, true); // x < y is true
let witness = compile_result
.witness_solver
.solve_witness(&assignment)
.unwrap();

let output = compile_result.layered_circuit.run(&witness);
assert_eq!(output, vec![true]);
}
}
15 changes: 13 additions & 2 deletions rsa_circuit/src/u120.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,18 @@ pub(crate) fn is_less_than_u120(
builder: &mut API<BN254Config>,
) -> Variable {
let diff = builder.sub(x, y);
// if x < y, then diff will underflow a range check will fail
let byte_decomp = crate::util::unconstrained_byte_decomposition(&diff, builder);
let res = builder.unconstrained_lesser(x, y);

todo!()
// if res = 1: x < y, then diff will underflow so byte_decomp[31] will be non-zero
// if res = 0: x >= y, then diff will not underflow so byte_decomp[31] will be zero
let zero = builder.constant(0);
let one = builder.constant(1);
let one_minus_res = builder.sub(one, res);
let t1 = builder.mul(one_minus_res, byte_decomp[31]);
let t2 = builder.mul(res, zero);
let t3 = builder.add(t1, t2);
builder.assert_is_zero(t3);

res
}
Loading

0 comments on commit 45c8b85

Please sign in to comment.