---
# System prepended metadata

title: Understanding and modifying the LTChip gadget in zkevm-circuits for Summa

---

The PSE's [zkEVM circuits](https://github.com/privacy-scaling-explorations/zkevm-circuits) have a variety of helpful 'gadgets' for various functionalities. 

One of these is the [```LTChip```](https://github.com/privacy-scaling-explorations/zkevm-circuits/blob/main/gadgets/src/less_than.rs) gadget, which is used for checking, given inputs ```lhs``` and ```rhs```, whether ```lhs < rhs ``` holds true. It can be used as a helper as a part of various larger circuits, something like this:

```rust 
    
    struct SomeLargerCircuitConfig<F> {
        q_enable: Selector,
        ....
        ....
        check: Column<Advice>,
        lt: LtConfig<F, NUM_BYTES>
}

```

Here, ```LTConfig``` is the configuration for the gadget as defined in the zkevm-circuits. But how does it look like and work under the hood and what limitations does it possess?

## Analysing ```LTConfig```

The default ```LTConfig``` is defined in the following manner:

```rust 
/// Config for the Lt chip.
#[derive(Clone, Copy, Debug)]
pub struct LtConfig<F, const N_BYTES: usize> {
    /// Denotes the lt outcome. If lhs < rhs then lt == 1, otherwise lt == 0.
    pub lt: Column<Advice>,
    /// Denotes the bytes representation of the difference between lhs and rhs.
    pub diff: [Column<Advice>; N_BYTES],
    /// Denotes the range within which each byte should lie.
    pub u8: Column<Fixed>,
    /// Denotes the range within which both lhs and rhs lie.
    pub range: F,
}
```

What this means is that the configuration looks something like this: 

| lt | diff[0] | diff[1] | diff [2] | ..... | diff[N_BYTES-1] | u8|
| -------- | -------- | -------- | -------- |-------- | --------- | --------
|1 | ```0xff``` | ``0xff`` | ```0xff```| ....| ```0xff``` | 


The column contains a lookup table ```u8``` which can be used to perform a range check on the value of each byte, 1 advice column for the ```lt``` status (1 if ```lhs<rhs``` and 0 otherwise) and the 2<sup>N_BYTES</sup> advice columns for the difference. 

``` diff[0], diff[1], diff[2] .... diff[N_BYTES-1] ``` denote the respective bytes of the difference of the LHS and RHS. 

### How is this difference calculated and hence, how is the circuit constrained?

Remember the ``` range ``` field in the ```LTConfig``` struct? This will come into play now. ```range``` is defined as ```NUM_BYTES*8``` (basically the decimal range in which the LHS and RHS will lie)

This difference is calculated using the following high level logic:

``` 
if lhs < rhs: 
    difference = lhs - rhs + range
else
    difference = lhs - rhs
``` 

What this logic does is that it prevents overflow by adding ```range``` in case ```lhs<rhs```and this comes in handy when constraining the circuit as well. 

Now, we constrain the "larger" circuit with the following conditions:

1. Check the fact that, given inputs ```lhs``` and ```rhs``` to the circuit, ```lhs - rhs - difference + (range*lt) == 0``` 

2. The ```lt``` value is a boolean. 


## So what's the issue?

We use this gadget in [Summa](https://github.com/summa-dev/summa-solvency), and the main issue here is that this 'horizontal' approach results in a huge number of advice columns. 

Specifically, for our use case, ```N_BYTES = 31 ``` and hence this results in 31 advice columns for difference in the ```LTChip``` alone. We need to reduce this to 3. 