-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Add new functions and improve tests (#2)
- Loading branch information
Showing
17 changed files
with
565 additions
and
817 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,70 @@ | ||
# 🔎 solcdf | ||
# 🔎 solgauss | ||
|
||
Approximation of the cumulative distribution function (cdf) for arbitrary 18 decimal fixed point parameters `x`, `μ`, `σ` and a target absolute error of 1e-8. | ||
[![CI][ci-badge]][ci-url] | ||
|
||
## 🧪 Methodology | ||
Solidity library for statistical functions rationally approximated with an error of less than 1 × 10<sup>-8</sup>, including `erfc`, `erfinv`, `erfcinv`, `ppf`, and `cdf`. | ||
|
||
The complementary error function (`erfc`) is approximated rationally using a variant from the algorithm presented in [this](https://eprint.iacr.org/2020/552.pdf) paper. The rational polynomial is composed of a polynomial of degree 11 as numerator, and a polynomial of degree 4 as denominator. | ||
## ⚙️ Installation | ||
|
||
The coefficients of the rational polynomial are scaled by a factor of 2^96 and then codified as part of the `erfc` function. This scaling allows for the use of cheaper `sar` (shift arithmetic right) operations instead of more expensive `sdiv` (signed division) operations (former costs 3 gas, while latter 5). Additionally, this function always returns 0 when the input is more than `4.0523` as the maximum absolute error would not surpass the target error. | ||
To install with [**Foundry**](https://github.com/foundry-rs/foundry): | ||
|
||
The `erfc` and `cdf` functions are differentially fuzzed against Python and Javascript implementations to ensure that they provide an absolute error of less than 1e-8. These functions are also benchmarked against [`solstat`](https://github.com/primitivefinance/solstat), [`gud-cdf`](https://github.com/Philogy/gud-cdf), and [`solidity-cdf`](https://github.com/fiveoutofnine/solidity-cdf). It's important to note that the benchmark does not verify the precision of these external libraries, such as `solidity-cdf`, which has an error of more than 1e-8. | ||
```sh | ||
forge install cairoeth/solcdf | ||
``` | ||
|
||
## ⛽ Gas Benchmarks | ||
|
||
| Function | min | avg | median | max | calls | | ||
|----------------------|------|------|--------|------|-------| | ||
| cdf (solcdf) | 562 | 657 | 562 | 876 | 256 | | ||
| cdf (solidity-cdf) | 540 | 671 | 540 | 962 | 256 | | ||
| cdf (gud-cdf) | 781 | 815 | 781 | 917 | 256 | | ||
| cdf (solstat) | 938 | 4279 | 5159 | 5159 | 256 | | ||
To run the gas benchmark: `forge t --gas-report --fuzz-seed 0x123` | ||
|
||
To run the gas benchmark: `forge t --gas-report` | ||
### `cdf` | ||
|
||
| Function | min | avg | median | max | | ||
|--------------------|------|------|--------|------| | ||
| cdf (solcdf) | 519 | 610 | 519 | 833 | | ||
| cdf (solidity-cdf) | 492 | 617 | 492 | 914 | | ||
| cdf (gud-cdf) | 704 | 736 | 704 | 841 | | ||
| cdf (solstat) | 916 | 4258 | 5137 | 5137 | | ||
|
||
### `erfc` | ||
|
||
| Function | min | avg | median | max | | ||
|-----------------|------|------|--------|------| | ||
| erfc (solcdf) | 687 | 688 | 687 | 693 | | ||
| erfc (gud-cdf) | 569 | 570 | 569 | 603 | | ||
| erfc (solstat) | 4436 | 4453 | 4436 | 4543 | | ||
|
||
### `erfcinv` | ||
|
||
| Function | min | avg | median | max | | ||
|----------|------|------|--------|------| | ||
| erfcinv | 669 | 828 | 783 | 1847 | | ||
|
||
### `erfinv` | ||
|
||
| Function | min | avg | median | max | | ||
|----------|------|------|--------|------| | ||
| erfinv | 604 | 749 | 718 | 1796 | | ||
|
||
### `ppf` | ||
|
||
| Function | min | avg | median | max | | ||
|----------|------|------|--------|------| | ||
| ppf | 856 | 1687 | 2034 | 2034 | | ||
|
||
## ✅ Tests | ||
|
||
Run the following for the dependencies used in the (differential) tests: | ||
|
||
### Python | ||
1. `python -m venv venv && source venv/bin/activate` | ||
2. `pip install mpmath` | ||
|
||
### Javascript | ||
1. `(cd differential && yarn)` | ||
|
||
To run the tests: `forge t` | ||
|
||
## 👇 Acknowledgements | ||
|
||
This repository is inspired by or directly modified from many sources, primarily: | ||
|
||
- [High-Precision Bootstrapping of RNS-CKKS Homomorphic Encryption Using Optimal Minimax Polynomial Approximation and Inverse Sine Function](https://eprint.iacr.org/2020/552): paper for algorithm variant | ||
- [gud-cdf](https://github.com/Philogy/gud-cdf): codification script | ||
- [gaussian](https://github.com/errcw/gaussian): javascript differential scripts | ||
|
||
[ci-badge]: https://github.com/cairoeth/solgauss/actions/workflows/test.yml/badge.svg | ||
[ci-url]: https://github.com/cairoeth/solgauss/actions/workflows/test.yml |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from mpmath import floor, erfinv | ||
import sys | ||
|
||
|
||
if __name__ == "__main__": | ||
x = int(sys.argv[1]) / 10**18 | ||
try: | ||
_erfcinv = int(floor(erfinv(1 - x) * 10**18)) | ||
except: | ||
_erfcinv = 0 | ||
if _erfcinv < 0: | ||
# For negative values, use two's complement representation | ||
_erfcinv = (1 << 256) + _erfcinv | ||
print(f'0x{_erfcinv:064x}') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from mpmath import erfinv, mpf, floor | ||
import sys | ||
|
||
|
||
if __name__ == "__main__": | ||
x = mpf(sys.argv[1]) / 10**18 | ||
try: | ||
_erfinv = int(floor(erfinv(x) * 10**18)) | ||
except: | ||
_erfinv = 0 | ||
if _erfinv < 0: | ||
# For negative values, use two's complement representation | ||
_erfinv = (1 << 256) + _erfinv | ||
print(f'0x{_erfinv:064x}') |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from mpmath import floor, sqrt, erfinv | ||
import sys | ||
|
||
|
||
if __name__ == "__main__": | ||
x = int(sys.argv[1]) / 10**18 | ||
u = int(sys.argv[2]) / 10**18 | ||
o = int(sys.argv[3]) / 10**18 | ||
|
||
try: | ||
_ppf = int(floor((u-o*sqrt(2)*erfinv(1-(2*x)))*10**18)) | ||
except: | ||
_ppf = 0 | ||
if _ppf < 0: | ||
# For negative values, use two's complement representation | ||
_ppf = (1 << 256) + _ppf | ||
print(f'0x{_ppf:064x}') |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.