{"id":13638858,"url":"https://github.com/socathie/circomlib-ml","last_synced_at":"2025-04-19T21:35:01.291Z","repository":{"id":46923189,"uuid":"491221993","full_name":"socathie/circomlib-ml","owner":"socathie","description":"Circom Circuits Library for Machine Learning","archived":false,"fork":false,"pushed_at":"2024-06-19T09:02:15.000Z","size":1016,"stargazers_count":175,"open_issues_count":3,"forks_count":21,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-15T16:26:20.125Z","etag":null,"topics":["blockchain","circom","circomlib","machine-learning","zero-knowledge-proof"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/circomlib-ml","language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/socathie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-11T18:05:27.000Z","updated_at":"2025-04-15T14:09:31.000Z","dependencies_parsed_at":"2024-05-02T06:30:52.209Z","dependency_job_id":"6fa474a2-9c67-4ab3-9553-1128e6605398","html_url":"https://github.com/socathie/circomlib-ml","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/socathie%2Fcircomlib-ml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/socathie%2Fcircomlib-ml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/socathie%2Fcircomlib-ml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/socathie%2Fcircomlib-ml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/socathie","download_url":"https://codeload.github.com/socathie/circomlib-ml/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249811121,"owners_count":21328747,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","circom","circomlib","machine-learning","zero-knowledge-proof"],"created_at":"2024-08-02T01:00:54.656Z","updated_at":"2025-04-19T21:35:00.943Z","avatar_url":"https://github.com/socathie.png","language":"Jupyter Notebook","funding_links":[],"categories":["Codebases"],"sub_categories":["Articles and podcasts"],"readme":"\u003e [!WARNING]\n\u003e README outdated and will be updated soon, see test folder for latest examples.\n\n# Circom Circuits Library for Machine Learning\n\nRun `npm run test` to test all `circomlib-ml` circuit templates.\n\n_Disclaimer: This package is not affiliated with circom, circomlib, or iden3._\n\n## Description\n\n- This repository contains a library of circuit templates.\n- You can read more about the circom language in [the circom documentation webpage](https://docs.circom.io/).\n\n## Organisation\n\nThis respository contains 2 main folders:\n- `circuits`: all circom files containing ML templates and relevant util templates\n```bash\ncircuits/\n├── ArgMax.circom\n├── AveragePooling2D.circom\n├── BatchNormalization2D.circom\n├── Conv1D.circom\n├── Conv2D.circom\n├── Dense.circom\n├── Flatten2D.circom\n├── MaxPooling2D.circom\n├── Poly.circom\n├── ReLU.circom\n├── SumPooling2D.circom\n├── circomlib\n│   ├── aliascheck.circom\n│   ├── babyjub.circom\n│   ├── binsum.circom\n│   ├── bitify.circom\n│   ├── comparators.circom\n│   ├── compconstant.circom\n│   ├── escalarmulany.circom\n│   ├── escalarmulfix.circom\n│   ├── mimc.circom\n│   ├── montgomery.circom\n│   ├── mux3.circom\n│   ├── sign.circom\n│   └── switcher.circom\n├── circomlib-matrix\n│   ├── matElemMul.circom\n│   ├── matElemSum.circom\n│   └── matMul.circom\n├── crypto\n│   ├── ecdh.circom\n│   ├── encrypt.circom\n│   └── publickey_derivation.circom\n└── util.circom\n```\n- `test`: containing all test circuits and unit tests\n```bash\ntest/\n├── AveragePooling2D.js\n├── BatchNormalization.js\n├── Conv1D.js\n├── Conv2D.js\n├── Dense.js\n├── Flatten2D.js\n├── IsNegative.js\n├── IsPositive.js\n├── Max.js\n├── MaxPooling2D.js\n├── ReLU.js\n├── SumPooling2D.js\n├── circuits\n│   ├── AveragePooling2D_stride_test.circom\n│   ├── AveragePooling2D_test.circom\n│   ├── BatchNormalization_test.circom\n│   ├── Conv1D_test.circom\n│   ├── Conv2D_stride_test.circom\n│   ├── Conv2D_test.circom\n│   ├── Dense_test.circom\n│   ├── Flatten2D_test.circom\n│   ├── IsNegative_test.circom\n│   ├── IsPositive_test.circom\n│   ├── MaxPooling2D_stride_test.circom\n│   ├── MaxPooling2D_test.circom\n│   ├── Max_test.circom\n│   ├── ReLU_test.circom\n│   ├── SumPooling2D_stride_test.circom\n│   ├── SumPooling2D_test.circom\n│   ├── decryptMultiple_test.circom\n│   ├── decrypt_test.circom\n│   ├── ecdh_test.circom\n│   ├── encryptDecrypt_test.circom\n│   ├── encryptMultiple_test.circom\n│   ├── encrypt_test.circom\n│   ├── encrypted_mnist_latest_test.circom\n│   ├── mnist_convnet_test.circom\n│   ├── mnist_latest_precision_test.circom\n│   ├── mnist_latest_test.circom\n│   ├── mnist_poly_test.circom\n│   ├── mnist_test.circom\n│   ├── model1_test.circom\n│   └── publicKey_test.circom\n├── encryption.js\n├── mnist.js\n├── mnist_convnet.js\n├── mnist_latest.js\n├── mnist_latest_precision.js\n├── mnist_poly.js\n└── model1.js\n```\n\n## Template descriptions:\n- `ArgMax.circom`\n\n    `ArgMax(n)` takes an input array of length `n` and returns an output signal correponds to the 0-based position index of the maximum element in the input.\n\n- `AveragePooling2D.circom`\n\n    `AveragePooling2D (nRows, nCols, nChannels, poolSize, strides, scaledInvPoolSize)` takes an `nRow`-by-`nCol`-by-`nChannels` input array and performs average pooling on patches of `poolSize`-by-`poolSize` with step size `strides`. `scaleInvPoolSize` must be computed separately and supplied to the template. For example, a `poolSize` of 2, should have an scale factor of `1/(2*2) = 0.25 --\u003e 25`.\n\n- `BatchNormalization2D.circom`\n\n    `BatchNormalization2D(nRows, nCols, nChannels)` performs Batch Normalization on a 2D input array. To avoid division, parameters in the layer is parametrized into a multiplying factor `a` and constant addition `b`, i.e. `ax+b`, where\n\n    ```python\n    a = gamma/(moving_var+epsilon)**.5\n    b = beta-gamma*moving_mean/(moving_var+epsilon)**.5\n    ```\n\n- `Conv1D.circom`\n\n    1D version of `Conv2D`\n\n- `Conv2D.circom`\n\n    `Conv2D (nRows, nCols, nChannels, nFilters, kernelSize, strides)` performs 2D convolution on an `nRow`-by-`nCol`-by-`nChannels` input array with filters of `kernelSize`-by-`kernelSize` and step size of `strides`. Currently it works only for \"valid\" padding setting.\n\n- `Dense.circom`\n\n    `Dense (nInputs, nOutputs)` performs simple matrix multiplication on the 1D input array of length `nInputs` and weights then adds biases to the output.\n\n- `Flatten2D.circom`\n\n    `Flatten2D (nRows, nCols, nChannels)` flattens an `nRow`-by-`nCol`-by-`nChannels` input array.\n\n- `MaxPooling2D.circom`\n\n    `MaxPooling2D (nRows, nCols, nChannels, poolSize, strides)`\n\n- `Poly.circom`\n\n    Inspired by [Ali, R. E., So, J., \u0026 Avestimehr, A. S. (2020)](https://arxiv.org/abs/2011.05530), the `Poly()` template has been addded as a template to implement `f(x)=x**2+x` as an alternative activation layer to ReLU. The non-polynomial nature of ReLU activation results in a large number of constraints per layer. By replacing ReLU with the polynomial activation `f(n,x)=x**2+n*x`, the number of constraints drastically decrease with a slight performance tradeoff. A parameter `n` is required when declaring the component to adjust for the scaling of floating-point weights and biases into integers. See below for more information.\n\n- `ReLU.circom`\n\n    `ReLU()` takes a single input and performs ReLU activation, i.e. `max(0,x)`. This computation is much more expensive than `Poly()`. It's recommended to adapt your activation layers into polynomial activation to reduce the size of the final circuit.\n\n- `SumPooling2D.circom`\n\n    Essentially `AveragePooling2D` with a constant scaling of `poolSize*poolSize`. This is preferred in circom to preserve precision and reduce computation.\n\n- `util.circom`\n\n    `IsPositive()` treats zero as a positive number for better performance. If you want to use `IsPositive()` to check if a number is strictly positive, you can use the version in the in-code comments.\n\n## Weights and biases scaling:\n- Circom only accepts integers as signals, but Tensorflow weights and biases are floating-point numbers.\n- In order to simulate a neural network in Circom, weights must be scaled up by `10**m` times. The larger `m` is, the higher the precision.\n- Subsequently, biases (if any) must be scaled up by `10**2m` times or even more to maintain the correct output of the network.\n\nAn example is provided below.\n\n## Scaling example: `mnist_poly`\nIn `models/mnist_poly.ipynb`, a sample model of Conv2d-Poly-Dense layers was trained on the [MNIST](https://paperswithcode.com/dataset/mnist) dataset. After training, the weights and biases must be properly scaled before inputting into the circuit:\n- Pixel values ranged from 0 to 255. In order for the polynomial activation approximation to work, these input values were scaled to 0.000 to 0.255 during model training. But the original integer values were scaled by `10**6` times as input to the circuit\n    - Overall scaled by `10**9` times\n- Weights in the `Conv2d` layer were scaled by `10**9` times for higher precision. Subsequently, biases in the same layer must be scaled by `(10**9)*(10**9)=10**18` times.\n- The linear term in the polynomial activation layer would also need to be adjusted by `10**18` times in order to match the scaling of the quadratic term. Hence we performed the acitvation with `f(x)=x**2+(10**18)*x`.\n- Weights in the `Dense` layer were scaled by `10**9` time for precision again.\n- Biases in the `Dense` layer had been omitted for simplcity, since `ArgMax` layer is not affected by the biases. However, if the biases were to be included (for example in a deeper network as an intermediate layer), they would have to be scaled by `(10**9)**5=10**45` times to adjust correctly.\n\nWe can easily see that a deeper network would have to sacrifice precision, due to the limitation that Circom works under a finite field of modulo `p` which is around 254 bits. As `log(2**254)~76`, we need to make sure total scaling do not aggregate to exceed `10**76` (or even less) times. On average, a network with `l` layers should be scaled by less than or equal to `10**(76//l)` times.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsocathie%2Fcircomlib-ml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsocathie%2Fcircomlib-ml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsocathie%2Fcircomlib-ml/lists"}