Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circuit improvements #198

Merged
2 changes: 1 addition & 1 deletion backend/src/contracts/abi/InclusionVerifier.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion backend/src/contracts/abi/Summa.json

Large diffs are not rendered by default.

12,820 changes: 6,486 additions & 6,334 deletions backend/src/contracts/generated/inclusion_verifier.rs

Large diffs are not rendered by default.

2,997 changes: 1,700 additions & 1,297 deletions backend/src/contracts/generated/summa_contract.rs

Large diffs are not rendered by default.

22 changes: 18 additions & 4 deletions backend/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{sync::Arc, time::Duration};

use ethers::{
abi::Token,
prelude::SignerMiddleware,
providers::{Http, Middleware, Provider},
signers::{LocalWallet, Signer},
Expand Down Expand Up @@ -56,22 +57,35 @@ pub async fn initialize_test_env(
.await;
}

if block_time != None {
if block_time.is_some() {
time::sleep(Duration::from_secs(block_time.unwrap())).await;
};

let inclusion_verifer_contract = InclusionVerifier::deploy(Arc::clone(&client), ())
let inclusion_verifier_contract = InclusionVerifier::deploy(Arc::clone(&client), ())
.unwrap()
.send()
.await
.unwrap();

if block_time != None {
if block_time.is_some() {
time::sleep(Duration::from_secs(block_time.unwrap())).await;
};

// The number of levels of the Merkle sum tree
let mst_levels = 4;
//The number of cryptocurrency assets per user included in the Merkle sum tree
let assets_count = 2;
// The number of bytes used to represent the balance of a cryptocurrency in the Merkle sum tree
let balance_byte_range = 14;

let args: &[Token] = &[
Token::Address(inclusion_verifier_contract.address()),
Token::Uint(mst_levels.into()),
Token::Uint(assets_count.into()),
Token::Uint(balance_byte_range.into()),
];
// Deploy Summa contract
let summa_contract = Summa::deploy(Arc::clone(&client), inclusion_verifer_contract.address())
let summa_contract = Summa::deploy(Arc::clone(&client), args)
.unwrap()
.send()
.await
Expand Down
6 changes: 6 additions & 0 deletions contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,11 @@ npx hardhat coverage
npx hardhat run scripts/deploy.ts --network localhost
```

The following Summa contract parameters are passed to its constructor inside the deployment script:

- verifier contract address (set automatically after the script deploys the verifier);
- the number of levels of the Merkle sum tree;
- the number of bytes used to represent the balance of a cryptocurrency in the Merkle sum tree.

The deployment script writes the latest deployment address for the chain to the [deployments](./../backend/src/contracts/deployments.json) file in the backend project. This data can later be used by the backend module to connect to the deployed contract.
The deployment script will copy the contract ABIs from the ./artifacts/src/ to the [backend](./../backend/src/contracts/abi/) module. The backend buildscript will then be able to generate the updated contract interfaces (see the backend [readme](./../backend/README.md)).
9 changes: 9 additions & 0 deletions contracts/scripts/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@ async function main() {
);
await inclusionVerifier.deployed();

// The number of levels of the Merkle sum tree
const mstLevels = 4;
//The number of cryptocurrency assets per user included in the Merkle sum tree
const assetsCount = 2;
// The number of bytes used to represent the balance of a cryptocurrency in the Merkle sum tree
const balanceByteRange = 14;
const summa = await ethers.deployContract("Summa", [
inclusionVerifier.address,
mstLevels,
assetsCount,
balanceByteRange,
]);

await summa.deployed();
Expand Down
4 changes: 2 additions & 2 deletions contracts/src/InclusionVerifier.sol

Large diffs are not rendered by default.

1,614 changes: 809 additions & 805 deletions contracts/src/InclusionVerifier.yul

Large diffs are not rendered by default.

22 changes: 21 additions & 1 deletion contracts/src/Summa.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/IVerifier.sol";

contract Summa is Ownable {
/**
* @dev Struct representing the configuration of the Summa instance
* @param mstLevels The number of levels of the Merkle sum tree
* @param assetsCount The number of cryptocurrency assets per user included in the Merkle sum tree
* @param balanceByteRange The number of bytes used to represent the balance of a cryptocurrency in the Merkle sum tree
*/
struct SummaConfig {
uint16 mstLevels;
uint16 assetsCount;
uint8 balanceByteRange;
}
/**
* @dev Struct representing an address ownership proof submitted by the CEX
* @param cexAddress The address owned by the CEX (submitted as a string, as it can be a non-EVM address)
Expand Down Expand Up @@ -47,6 +58,9 @@ contract Summa is Ownable {
string[] blockchainNames;
}

// Summa configuration
SummaConfig public config;

// User inclusion proof verifier
IVerifier private immutable inclusionVerifier;

Expand Down Expand Up @@ -81,8 +95,14 @@ contract Summa is Ownable {
Cryptocurrency[] cryptocurrencies
);

constructor(IVerifier _inclusionVerifier) {
constructor(
IVerifier _inclusionVerifier,
uint16 mstLevels,
uint16 assetsCount,
uint8 balanceByteRange
) {
inclusionVerifier = _inclusionVerifier;
config = SummaConfig(mstLevels, assetsCount, balanceByteRange);
}

/**
Expand Down
3 changes: 3 additions & 0 deletions contracts/test/Summa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ describe("Summa Contract", () => {

const summa = await ethers.deployContract("Summa", [
inclusionVerifier.address,
4, // The number of levels of the Merkle sum tree
2, // The number of cryptocurrency assets per user included in the Merkle sum tree
14, // The number of bytes used to represent the balance of a cryptocurrency in the Merkle sum tree
]);
await summa.deployed();

Expand Down
2 changes: 1 addition & 1 deletion zk_prover/examples/inclusion_proof_solidity_calldata.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"proof": "0x1c7a5d502a29a2c3c3e2d2d518ec2a8543c19bdce5135bbe59e14ef5d178efe9139c3838b4b11d607cc8ee22c32509d3d14227953cb313518d80be18655af6ba245790f70d7dcf5f046fb8580dfc9b13cd24f332e7f2cfc17f591aa3d69f11f4252f8e212b1ccc58ab58aba219d55b5e2f595e357ad30f0dc7d4675c2bdd2d780cacd8f89bcc10d41525a0395a64086b74826bb451a851f1d0379f4764b735400794ffe274246e09667ec9a321c8e9367fe1a4fa3ba21bfded36795e6e9d09bb1524bafd5994754519bdafef12f7191e50df6b1a6dce272ffcefa1d436119e1b057250dfa475092a7f9aafdec82ec0fecc9cc9b3bea3858fbc890bc41d013d402fd44923523a328647a94dedca98ba214ed7369079b114aa1ec4e8ba322628c91b648bc0336a5643a58a00ba809f772e7afaff4e857f25eac8c9458303fb2a5b18961ab5f9e67915a387d986b3b07efb1ecbdde42e4cbe8e3d5af03a59952ac61356f8dcbae85a0978509355d663eb844c5acd48726310c8415c7a3aafe6535a1b0e9765adcb39bc4afdfced654cad6f397d9892ee1ae503884c1db9a0c168af2797b4f4dee6f03f476b01941ceecad88cf3036b0f706d5b7cab16b0a3f71b440bb7c5afaedcd7c00b29aa45261b7e85e76a5777e8c0560439c5a121fa2c3bdd0395ac07afde7f5d1c0cdf752434721295767f238f178d6812bd28b99444047b121546f5a344aaca511e65d52de324bf27e51f432d511af05eb95f37e43aef0f1659bab2049626661782686ad5468d094cd7e301e580754f398ebec01867db1023333e83253fae9f8412781499ec436e0368bdff9da07288e96cc38606bc1f6d227f325d5a1c8757441d2d84a3b2f5afd7092d17df5525edea2b8f0dd69012af063061290aa7ec3ab913d1cf2869be3e739b3d3deacbb6a0f81a185ad42d8d8801147c4f8346d59f98cb77e8b8240988911e89ec7fdb53ad9848f721cf7167eb30124b79fdec15f3993c137462ba73410e3299530163790f0fc433adb808cfc928d38ff9793b82f359d27367c29d4d426e9dff1bc6a4391249df6a478818ac7910c7b98cca67e4bfb8b51e5b1060c3645cb9190abc407ccdd7f556fcb21730d9106a526538708a8202297cf5d454b7b49060b7c5de6d3fc199b376fc071b22830304cdc209c8dcd6f387ca9508e682ed717adba04c0c94e15cfb023f3a32739e1e8803aeb32c8b5dcc0ff1f49c734a50df27ba77beb4b25ed51ecc7642dae797051cfa5298b0c5928587dd3db85d4f701df82f32ea95aef6b8f349f289775cb12657e6d4996793f259ff15db0c84474a130613f1c261908972cd62e8ff8e69730e001a12ce4d710e0367c7f10206852aac0ed64c2b1354ab7030e97e2ccc914729427f7619b8b5f3174c4beed8666b7bc4edfdf9347fc2e48eabd43ddbde5b1b22545e1acd6f2b75161ad7520d8789d8732a4b716c01327c8f04cd05807fe98e0a7c235e358c069e583dca4a1a4651652f33305b2552c2f7233e7c876f55702c2f430c3236e25d642849059e3b3ac44decdbc041bdb3dc40953ba1cc6c3ca73b03dc19085ce3281e342c51f5331e245209afd51743d14495adec32c3679de8962deef6d7a950f0512ab3e7f5fb324b68315bf321d77a0b3d79c943fe1791174f2091f458d2e8a0e0524f4439e8d5f1a9a6ae80337942661f316ae6b619be2c1f2e71f83a586b6de95226f7fe5dc1b24bc82d2ea56d06e37d9f63008388ab9f1311d69721625f59ce4b2047b54ca06f42eaf9745919f8b1da480ad2931a1e63261ec10afd1ef6c9403c088dc958773610059645fab6b09b621adffa689fb6fb822cd3c726bc692e33c6bbb255f6238b9083e802817c59203e294494abf57813340898377954dd72fc368ea59cc7c75cbd098954b58498fcb1cca5d7552ae808e501c30108153b1ee4f77511ba5cff4e5578347413b9a0e9a5317bd194c04797bf11ec726054bda2d4103ab9831ea235f8eef31a6a4103eaed66a22b957bd6ca9c108948fe9c61f804148229c49be669e36e605c75800d69bfac1e856e6c54e72605c473b79cd7ac2883dd5a2bb83ce384c62e4a77ebf210444754645a983acb422214fbbf18f0c418257539a0e113cd1dd974111f23d9cb76f07bd92278321b060ce9a08de60fe584ad879d145cbfd0402776b572b37b8103410c277ca4bbc7201f694bf1f66c90b081200be85f0421c92573660273d303034d7ba80b996eb79230194ca93f1f565261aaa7e2dc4ac5be538503af632c9f3129f6a91e984fc7522d28537a9b256610ee029d6a3741445c939e7801a24c2b2e8a7f3b57d29137d92af9029cda44a25342151145dac9d679e9187c6efe4913ce3b8279f8b9962a1e06698d5777ca294f3d234b86bec1ffb670d61a51c6e9b7015e2a67ff59348df422fba53644e696f92bac9513b14a512c5ad1323cf02c2212af25c31dea96565016af135a3067869dfafa1f72de025b129fc79173da2c2b39ad8c2c01928ee8b92409600b405fb6980cc5cdf0b2b91756cad269889b924c7518a6d822f87193800bc0da2d76c38c1b7604293523827f0356dc594d7a442dba34a5a82a521a38bd11e98aab00ca4a7862552cb7621b5910b449a1ae1a12b26c6d94c7845ccc7d8229232baf261186ee10d14f6b1fb56464090dc1392cbd945609a9fa67beecb7041c015398c138b2359ddfe16745071076693338adba97cc636d71f04b2e0d44ba2a7b0447db18d72189fa27d174d1b379070aefbe30a6522f099025e8562de1a91a9ff2fa4564862f66f1bc37aac344ce2eb6a137b53bf76dce07c3ba31cf4d8c1b784c93768215706873f7c934b39aee003210f81527fd8c1c4845f39830adac02f4ab84229a373628b681f40e0c145277e2aae03438c155079fe26455f031631b0b835dbc2c654236708eb9831082be7976a05dc924ada3e44ebf6043074406248e34900dfc647ed17480f698e93556f2ce5a0cee266378a39fce8e20dd2c6c",
"proof": "0x1e94df5c9e64286482e5050d12f10c53aa607cacd84fcd3a408737cead3693ad0f8e478f584318016f885c0e4be56a1636097d8b7424d64855de037d349fd92825862131d1648f278249284b604b4f5d93dfc50d0004f8474bf569f972b113650da88dc30d36b0ae248d8754d55662af2c7aac4ba1c86372785af882100e61d217bd21ad7a8819c037ef132f2a340dd8fcf4c5b5dd661bf1844993c6ec82dfd92b91b7f6fb83a72a5262b18f8f324c425dffa7ad2b23a285c1b1bdb1c8bde4030f42e31819c3537ff954577c47ae8a0747a8a8390bfed8faa59188112f61216e1549c7aeeb46d2963adde4bd51d844784d449fdd54c75fdbb713dd8fd8764a1607159a94b280978d855eb0a11c7a578b6ea07c6d6d0c97350e18b5e8d36927372d79f80df140bc930b5678f407342dd9067a82fe9c75e4113754fc19310e4757289e2025af670afc8aafc721d3e66834c4867a1d1dbd63359f7b5b354f9f93e327550e310805831e15dfa2376775d7e66c47747a89e4494fdb4d8e72a6476e2e2c741d4eed06fcb84ca69d7aee5bcdb9963187e098fedb7d5f405a31febb6bc3106004d8dad642cc32ff95aab5fc3330d8dc260197db3ba080fb2ebb1bf238351ffdfa4e5035ebf3e987f6d3da44ee87ee96d16e6a187d6a9b3bb28fc1570492240ee384c6682c222540ecbc3d6f4d1cba8f403d28ca6e1a395e64dd4527665c08810e1fb264f8ce06552f268fea148055c1f5729c207dd576ca28765b4cc0900155eefd6fd19255a20eacbbaf3c87a7b62dffa5b73c046bad798f27c6623fe610290fc95e4a0073e52b3b5708aac83f505e15940956abe3db3d2f312bbc01ea0577ffc2ecd8e5f1326a255af26d19adbddf7f495843ab0bf1957693530ec9410d47037d00345c5743c63fb3c6fbd771823d63558584fc4f6fe571d449ae1bb62fbf0906b43c8b81d657380606f2e6012e081fe1a702380875161832e19e9eb22df226ad3769820128866d631b0c366ad69ae7df6039bacc0856444abb45587e2841231df7c4edd7b664087d46b39a53c3cc010466169d3c4b1f6bf3b80cf7661c7b1c59e43a04d737851b448273a1c9f41680c8b024921541a08ed2b737ba8e25a921838b6d2730e8058c91ef25d2251a6d09e3056eed5f0948418ad2e106ec14f7100b366d055525317cb40ed75d9bda85c8fd98cd29f0a93aa6f90539334119f762877fbf7f4f2a6b6f9a10145f709257104b9ae2dec184a7c1df8275159f2d2fd9fff812ec5fc42f93c472e617fc1563e813dc6cd6ca7cdbfb41bea2a72e228ecbf9bab2c50e5304b664772db087ac2a53d45d8a4b8c63f55335ee644ef52fd5f9b6e746b25bb6cd19e744d76cd1414ebe8d6b5fde6b468cca5107819a6d05ba9c2c1091a4eb1d79629636ca3400a3b69a781ba8ecbc7f59779634e5ae132f250945ffd72ade50063fb5a07dc6f56c3ff1cae9ae3d1c2bf201258bf79f1329ed689867a7e51e0d50920019f42a45f1b812b8f4de5a47ecabe2f32c20384f16e94dc9c5f78799506b33b59723e7dc5386bc31002eb3867b50ded5b92658de12f0e914b260e8f61a1184842721087c79021c54283e68635b0cb0cd9aa7d6bf0a145ade522e4faa01a78eca82f4ad4660745a05ab763007c402b6ee8a9e73a30f3e4dc893d23caf4fc757ebe0de6123978dea5bee1648833f6c60c413a250461d8cf808b8922b6ae123ba013b570cb4ab6fe663d1170d6859972496534965a40e5c2dfaabae417a4468039254f1107b358691045edff5154b2c88cdc99e770a0a4dda09ffc7d86bff1c6bdb1ae00a0ac582cb2c0110327ded5e85524cb9257a11825499dbc673b3d771b00a33480190425999ca32f3d8dd40c950ab81f6dc662a51907294f6687dcc481c02cf15914cd073eeba34113a52f2e04dccc79e6b401d485d4fff8488abd6b5eb1c7bf74a3ee86b2f7c07c1e93bd08e9ea5dc62566b2078fec5aea206f3dc10b9e7afdf448e0089d47006beb576b244aa692b961dde236f7ab501573043b9ae540c63bd80688ade75b29939f0b58145e0c6171da4dc29f6e6bc99aab9e2a2c95d2049a5081a7e1f617ab947f89a6d7e242bd546dfa50ebb5a4c63e3d88ba029db0a8f43f88e55d365ed589ea83df35e0c1098b80f2d0fe7960a8b16c190c9fc70a01aa7b0fc48c1b9bf3c02d0e73f3a0a3f40c4a47b2580c46f97a5ae8d92ce9d7c04d4a3c532e0585a706121a2ff2a447026b05c9b16c0ed803fe1c901e0e92899f9ca4a4aa1207c9e94cc11647793e4df7d809eb214d54b9e5052eb2fcf087abc5e14a6fa9018bb445e622651e0202060f4d92ca22231adfacf0e4feda0dfc1c4f51c54b401b6a95a696b1796c24ab0949e3120d311ab9d6e2a30f1a20e147490b61683674cdc926e8ce8665c8c9c2dff8cd5ccfd2e96ce6ef75f0bfe0c4edbd192b0a5dcd672a4e18119f5bbeb38a542b1b8ccc111294bfa7bc3ff716b4496dfc23ebdaf113d0b29a1266fcf3b5c81fadd4a91cd1221117b444b3f63414069ff07237707db17728f39cca47506702b091ce6830e2dd956d03068cd2fba7314c65f231475288e147754408534d19eea99a58469331d0149d618165409b780bb02759a92f08372beb9764a3c1e5e517902dab8000409ddfd38080e91bb0d01d218380020d24050975a27d354bf512dd785754a486218b02373e541d2bf55ce1b77c8912c0135a2c0775686f7c6734b8627cb93f72d2950397efe6daa89cbaef859e7dd639fe91c94f422eeec53065ba6ed8f78dfa72d1105af9e61d70ecb7ecea72e275d7dbce40fce85c795e3c20ae719251abd33061ca0cc43ec1421947e6a285a1f40790386d19fed65f26875a6656b282193ef10a7a763e61584de359c71f9dceae78189ff2272024b4cf141f58a7e94ec3c121150de85e9401461b0ffd26bb373e2dd4865572dd298b5f92babc182f8e229682d454f436f48d2857b8739b904cff81f5d5f3bb3088e9d2510140753fbc59900",
"public_inputs": [
"0xe113acd03b98f0bab0ef6f577245d5d008cbcc19ef2dab3608aa4f37f72a407",
"0x18d6ab953235a811edffa4cead74ea045e7cd2085771a2269d59dca054c955b1",
Expand Down
Binary file modified zk_prover/prints/mst-inclusion-layout.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 12 additions & 8 deletions zk_prover/src/chips/merkle_sum_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub struct MerkleSumTreeConfig {
/// Chip that performs various constraints related to a Merkle Sum Tree data structure such as:
///
/// * `s * swap_bit * (1 - swap_bit) = 0` (if `bool_and_swap_selector` is toggled). It basically enforces that swap_bit is either a 0 or 1.
/// * `s * (swap_bit * 2 * (elelment_r_cur - elelment_l_cur) - (elelment_l_next - elelment_l_cur) - (elelment_r_cur - elelment_r_next)) = 0`. Enforces that if the swap_bit is equal to 1, the values will be swapped on the next row (if `bool_and_swap_selector` is toggled).
/// * `s * (swap_bit * 2 * (element_r_cur - element_l_cur) - (element_l_next - element_l_cur) - (element_r_cur - element_r_next)) = 0`. Enforces that if the swap_bit is equal to 1, the values will be swapped on the next row (if `bool_and_swap_selector` is toggled).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description is outdated

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

/// If the swap_bit is equal to 0, the values will remain the same on the next row (if `bool_and_swap_selector` is toggled).
/// * `s * (left_balance + right_balance - computed_sum)`. It constraints the computed sum to be equal to the sum of the left and right balances (if `sum_selector` is toggled).
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -59,14 +59,18 @@ impl<const N_ASSETS: usize> MerkleSumTreeChip<N_ASSETS> {
let element_l_next = meta.query_advice(col_a, Rotation::next());
let element_r_next = meta.query_advice(col_b, Rotation::next());

let swap_constraint = s
* ((swap_bit
* Expression::Constant(Fp::from(2))
* (element_r_cur.clone() - element_l_cur.clone())
- (element_l_next - element_l_cur))
- (element_r_cur - element_r_next));
// element_l_next = (element_r_cur - element_l_cur)*s + element_l_cur
let swap_constraint_1 = s.clone()
* ((element_r_cur.clone() - element_l_cur.clone()) * swap_bit.clone()
+ element_l_cur.clone()
- element_l_next);

vec![swap_constraint]
// element_r_next = (element_l_cur - element_r_cur)*s + element_r_cur
let swap_constraint_2 = s
* ((element_l_cur - element_r_cur.clone()) * swap_bit + element_r_cur
- element_r_next);

vec![swap_constraint_1, swap_constraint_2]
});

meta.create_gate("sum constraint", |meta| {
Expand Down
37 changes: 8 additions & 29 deletions zk_prover/src/chips/range/range_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,16 @@ use super::utils::decompose_fp_to_bytes;
/// # Fields
///
/// * `z`: Advice column for the value to be checked and its running sum.
/// * `range`: Fixed column for the lookup table. It contains the values from 0 to 2^8 - 1.
/// * `lookup_enable_selector`: Selector to enable the lookup check.
///
/// Patterned after [halo2_gadgets](https://github.com/privacy-scaling-explorations/halo2/blob/main/halo2_gadgets/src/utilities/decompose_running_sum.rs)
#[derive(Debug, Copy, Clone)]
pub struct RangeCheckConfig<const N_BYTES: usize> {
z: Column<Advice>,
range: Column<Fixed>,
lookup_enable_selector: Selector,
}

/// Helper chip that verfiies that the value witnessed in a given cell lies within a given range defined by N_BYTES.
/// Helper chip that verifies that the value witnessed in a given cell lies within a given range defined by N_BYTES.
/// For example, Let's say we want to constraint 0x1f2f3f4f to be within the range N_BYTES=4.
///
/// `z(0) = 0x1f2f3f4f`
Expand All @@ -47,8 +45,8 @@ pub struct RangeCheckConfig<const N_BYTES: usize> {
///
/// The column z contains the witnessed value to be checked at offset 0
/// At offset i, the column z contains the value z(i+1) = (z(i) - k(i)) / 2^8 (shift right by 8 bits) where k(i) is the i-th decomposition big-endian of `value`
/// The contraints that are enforced are:
/// - z(i) - 2^8⋅z(i+1) ∈ lookup_u8 (enabled by lookup_enable_selector at offset [0, N_BYTES - 1])
/// The constraints that are enforced are:
/// - z(i) - 2^8⋅z(i+1) ∈ lookup_u8_table (enabled by lookup_enable_selector at offset [0, N_BYTES - 1])
/// - z(N_BYTES) == 0
#[derive(Debug, Clone)]
pub struct RangeCheckChip<const N_BYTES: usize> {
Expand All @@ -61,13 +59,15 @@ impl<const N_BYTES: usize> RangeCheckChip<N_BYTES> {
}

/// Configures the Range Chip
/// Note: the lookup table should be loaded with values from `0` to `2^8 - 1` otherwise the range check will fail.
pub fn configure(
meta: &mut ConstraintSystem<Fp>,
z: Column<Advice>,
range: Column<Fixed>,
lookup_u8_table: Column<Fixed>,
lookup_enable_selector: Selector,
) -> RangeCheckConfig<N_BYTES> {
meta.annotate_lookup_any_column(range, || "LOOKUP_MAXBITS_RANGE");

meta.annotate_lookup_any_column(lookup_u8_table, || "LOOKUP_MAXBITS_RANGE");

meta.lookup_any(
"range u8 check for difference between each interstitial running sum output",
Expand All @@ -76,7 +76,7 @@ impl<const N_BYTES: usize> RangeCheckChip<N_BYTES> {
let z_next = meta.query_advice(z, Rotation::next());

let lookup_enable_selector = meta.query_selector(lookup_enable_selector);
let u8_range = meta.query_fixed(range, Rotation::cur());
let u8_range = meta.query_fixed(lookup_u8_table, Rotation::cur());

let diff = z_cur - z_next * Expression::Constant(Fp::from(1 << 8));

Expand All @@ -86,7 +86,6 @@ impl<const N_BYTES: usize> RangeCheckChip<N_BYTES> {

RangeCheckConfig {
z,
range,
lookup_enable_selector,
}
}
Expand Down Expand Up @@ -153,24 +152,4 @@ impl<const N_BYTES: usize> RangeCheckChip<N_BYTES> {
},
)
}

/// Loads the lookup table with values from `0` to `2^8 - 1`
pub fn load(&self, layouter: &mut impl Layouter<Fp>) -> Result<(), Error> {
let range = 1 << (8);

layouter.assign_region(
|| format!("load range check table of {} bits", 8),
|mut region| {
for i in 0..range {
region.assign_fixed(
|| "assign cell in fixed column",
self.config.range,
i,
|| Value::known(Fp::from(i as u64)),
)?;
}
Ok(())
},
)
}
}
Loading