mirror of
https://github.com/logos-messaging/go-zerokit-rln.git
synced 2026-01-02 13:13:11 +00:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8e8aab76c | ||
|
|
88462cf654 | ||
|
|
84d12e61d9 | ||
|
|
54bb48f178 | ||
|
|
14960f3aff | ||
|
|
7e086e8f89 | ||
|
|
06e6fa3fd1 | ||
|
|
fa738c0bdf | ||
|
|
e0f344a581 | ||
|
|
4b71a4fcf1 | ||
|
|
d284a3d8f2 | ||
|
|
e0ebce7c29 | ||
|
|
ca686a02e8 | ||
|
|
a706089284 | ||
|
|
8167006b94 | ||
|
|
1ccba817b5 | ||
|
|
3b5c0bbefb | ||
|
|
47b8b17401 | ||
|
|
fd3fa1222b | ||
|
|
655973b243 | ||
|
|
ea89e5d7ee | ||
|
|
0cefd63734 | ||
|
|
75151c168b | ||
|
|
df71229905 | ||
|
|
86b06ba440 | ||
|
|
33aab2e6e4 | ||
|
|
810b73f03c | ||
|
|
deaab0718c | ||
|
|
f3f2c16093 | ||
|
|
eaf62c1713 | ||
|
|
e1bed5294a | ||
|
|
d338ed9d40 |
20
.github/workflows/tests.yml
vendored
Normal file
20
.github/workflows/tests.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
on: [push, pull_request]
|
||||
name: Tests
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.19.x]
|
||||
# Disabled: windows-latest
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Run tests
|
||||
run: |
|
||||
go test ./... -v
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@ -13,3 +13,7 @@
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Tree persistence
|
||||
snap.*
|
||||
blobs/
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "zerokit"]
|
||||
path = zerokit
|
||||
url = git@github.com:vacp2p/zerokit.git
|
||||
12
Makefile
12
Makefile
@ -1,12 +0,0 @@
|
||||
.PHONY: rlnlib
|
||||
|
||||
SHELL := bash # the shell used internally by Make
|
||||
|
||||
GOBIN ?= $(shell which go)
|
||||
|
||||
rlnlib:
|
||||
scripts/build.sh
|
||||
cd zerokit/rln && cbindgen --config ../../cbindgen.toml --crate rln --output ../../rln/librln.h --lang c
|
||||
|
||||
test:
|
||||
go test ./... -count 1 -v
|
||||
78
README.md
78
README.md
@ -2,13 +2,81 @@
|
||||
|
||||
Go wrappers for [zerokit's RLN](https://github.com/vacp2p/zerokit)
|
||||
|
||||
### Building this library
|
||||
```
|
||||
git clone https://github.com/status-im/go-zerokit-rln
|
||||
cd go-zerokit-rln
|
||||
|
||||
|
||||
### Updating vacp2p/zerokit
|
||||
|
||||
To overcome the limit of 500mb github has for repositories, go-zerokit-rln depends on 3 projects:
|
||||
- https://github.com/waku-org/go-zerokit-rln-apple
|
||||
- https://github.com/waku-org/go-zerokit-rln-arm
|
||||
- https://github.com/waku-org/go-zerokit-rln-x86_64
|
||||
|
||||
Zerokit must be updated in these 3 repositories. The instructions are the same for each of the architectures,
|
||||
except for `-apple` which require macos to be executed. You need to have docker and rust installed.
|
||||
|
||||
```bash
|
||||
export GO_RLN_ARCH=x86_64 # Replace this for x86_64, arm or apple
|
||||
export ZEROKIT_COMMIT=master # Use a commit, branch or tag
|
||||
|
||||
git clone https://github.com/waku-org/go-zerokit-rln_${GO_RLN_ARCH}
|
||||
cd go-zerokit-rln-${GO_RLN_ARCH}
|
||||
git submodule init
|
||||
git submodule update --recursive
|
||||
cd zerokit
|
||||
git pull
|
||||
git checkout ${ZEROKIT_COMMIT}
|
||||
cd ..
|
||||
make
|
||||
git add zerokit
|
||||
git add libs/*/librln.a
|
||||
git commit -m "chore: bump zerokit"
|
||||
git push
|
||||
```
|
||||
|
||||
To generate smaller static libraries, before `make`, edit `./zerokit/rln/Cargo.toml` and use `branch = "no-ethers-core"` for `ark-circom`
|
||||
Once you execute the previous commands for each one of the architectures, update go.mod:
|
||||
```bash
|
||||
cd /path/to/go-zerokit-rln
|
||||
go get github.com/waku-org/go-zerokit-rln-apple@latest
|
||||
go get github.com/waku-org/go-zerokit-rln-arm@latest
|
||||
go get github.com/waku-org/go-zerokit-rln-x86_64@latest
|
||||
git checkout master
|
||||
git add go.mod
|
||||
git add go.sum
|
||||
git commit -m "chore: bump zerokit"
|
||||
git push
|
||||
```
|
||||
|
||||
And later in go-waku, update the go-zerokit-rln dependency with
|
||||
```
|
||||
cd /path/to/go-waku
|
||||
git fetch
|
||||
git checkout -b `date +"%Y%m%d%H%M%S"-bump-zerokit` origin/master
|
||||
go get github.com/waku-org/go-zerokit-rln@latest
|
||||
git add go.mod
|
||||
git add go.sum
|
||||
git commit -m "chore: bump go-zerokit-rln"
|
||||
git push
|
||||
````
|
||||
And create a PR
|
||||
|
||||
|
||||
# Adding a new architecture
|
||||
|
||||
1. Depending on the architecture/platform you want to add, clone one of these repositories.
|
||||
- https://github.com/waku-org/go-zerokit-rln-apple
|
||||
- https://github.com/waku-org/go-zerokit-rln-arm
|
||||
- https://github.com/waku-org/go-zerokit-rln-x86_64
|
||||
2. Edit `./scripts/build.sh` to add the new architecture. Refer to this list of [supported targets](https://github.com/cross-rs/cross#supported-targets)
|
||||
3. Edit `./rln/link.go` to add a **cgo** build tag for the new architecture
|
||||
4. Commit the changes and then execute
|
||||
```bash
|
||||
export GO_RLN_ARCH=x86_64 # Replace this for the platform you just updated: x86_64, arm or apple
|
||||
cd /path/to/go-zerokit-rln
|
||||
git checkout master
|
||||
git pull
|
||||
go get github.com/waku-org/go-zerokit-rln-${GO_RLN_ARCH}@latest
|
||||
git add go.mod
|
||||
git add go.sum
|
||||
git commit -m "chore: bump go-zerokit-rln-${GO_RLN_ARCH}"
|
||||
git push
|
||||
```
|
||||
|
||||
20
go.mod
20
go.mod
@ -1,13 +1,23 @@
|
||||
module github.com/status-im/go-zerokit-rln
|
||||
module github.com/waku-org/go-zerokit-rln
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/stretchr/testify v1.7.2
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/consensys/gnark-crypto v0.12.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240529153423-5df5db48b69f
|
||||
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240529153432-be2c8ac0a840
|
||||
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240529153442-f5fb416605f5
|
||||
golang.org/x/crypto v0.18.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bits-and-blooms/bitset v1.10.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
47
go.sum
47
go.sum
@ -1,20 +1,53 @@
|
||||
github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88=
|
||||
github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
|
||||
github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240522110429-626138029176 h1:ezeAofaW3B6tfqS06FwKAKKXpNkimWnIwKjDU0dDPKE=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240522110429-626138029176/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240523161310-d005fe7ba59c h1:/eGH8EAt5/zGfNRBQ0nJMrfZDeXRSJrm8E8uCPlsC3A=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240523161310-d005fe7ba59c/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240528140707-ed6b40a98d7b h1:LEa2s1p+Z8SN475dVr3XDmvmGyKzIDKPcAQ+6hTyVwA=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240528140707-ed6b40a98d7b/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240529153423-5df5db48b69f h1:CEBW4vu8I60OakKExZUE7G4oY7Z/glQXxPYedpZ4Sq8=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240529153423-5df5db48b69f/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
|
||||
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240124081101-5e4387508113 h1:dPwc4LAWLXb4Pssej/NtGA9A0UMQwi+JafQPdnhjRWM=
|
||||
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240124081101-5e4387508113/go.mod h1:7cSGUoGVIla1IpnChrLbkVjkYgdOcr7rcifEfh4ReR4=
|
||||
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240523161300-8203361a01d0 h1:IvtkZOcApOkEmHkT/drDmMtY6fdYpF7x4sesWyIURpI=
|
||||
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240523161300-8203361a01d0/go.mod h1:7cSGUoGVIla1IpnChrLbkVjkYgdOcr7rcifEfh4ReR4=
|
||||
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240529153432-be2c8ac0a840 h1:DKub+sG+vfKqwOCaKrthhJA/bP7gTZWxbdrFV86Q5Ms=
|
||||
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240529153432-be2c8ac0a840/go.mod h1:7cSGUoGVIla1IpnChrLbkVjkYgdOcr7rcifEfh4ReR4=
|
||||
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240124081123-f90cfc88a1dc h1:GUZlr25hXLu/PeASqm8P5dPOyD4CdfvkzyEtXEBLbr8=
|
||||
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240124081123-f90cfc88a1dc/go.mod h1:+LeEYoW5/uBUTVjtBGLEVCUe9mOYAlu5ZPkIxLOSr5Y=
|
||||
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240523161247-6f16d12c5a86 h1:PN1WSt3u/DEIn4hX5Oqrm9bm5nf5VBfenfXmbX4mg60=
|
||||
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240523161247-6f16d12c5a86/go.mod h1:+LeEYoW5/uBUTVjtBGLEVCUe9mOYAlu5ZPkIxLOSr5Y=
|
||||
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240529153442-f5fb416605f5 h1:ZhrzpAjIUZHD6gSKPA8zwHjIys9/GTGN3hPKtwMORSA=
|
||||
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240529153442-f5fb416605f5/go.mod h1:+LeEYoW5/uBUTVjtBGLEVCUe9mOYAlu5ZPkIxLOSr5Y=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
66
rln/librln.h
66
rln/librln.h
@ -1,66 +0,0 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TEST_PARAMETERS_INDEX 2
|
||||
|
||||
typedef struct RLN RLN;
|
||||
|
||||
/**
|
||||
* Buffer struct is taken from
|
||||
* https://github.com/celo-org/celo-threshold-bls-rs/blob/master/crates/threshold-bls-ffi/src/ffi.rs
|
||||
*
|
||||
* Also heavily inspired by https://github.com/kilic/rln/blob/master/src/ffi.rs
|
||||
*/
|
||||
typedef struct Buffer {
|
||||
const uint8_t *ptr;
|
||||
uintptr_t len;
|
||||
} Buffer;
|
||||
|
||||
bool new(uintptr_t tree_height, const struct Buffer *input_buffer, struct RLN **ctx);
|
||||
|
||||
bool new_with_params(uintptr_t tree_height,
|
||||
const struct Buffer *circom_buffer,
|
||||
const struct Buffer *zkey_buffer,
|
||||
const struct Buffer *vk_buffer,
|
||||
struct RLN **ctx);
|
||||
|
||||
bool set_tree(struct RLN *ctx, uintptr_t tree_height);
|
||||
|
||||
bool delete_leaf(struct RLN *ctx, uintptr_t index);
|
||||
|
||||
bool set_leaf(struct RLN *ctx, uintptr_t index, const struct Buffer *input_buffer);
|
||||
|
||||
bool set_next_leaf(struct RLN *ctx, const struct Buffer *input_buffer);
|
||||
|
||||
bool set_leaves(struct RLN *ctx, const struct Buffer *input_buffer);
|
||||
|
||||
bool get_root(const struct RLN *ctx, struct Buffer *output_buffer);
|
||||
|
||||
bool get_proof(const struct RLN *ctx, uintptr_t index, struct Buffer *output_buffer);
|
||||
|
||||
bool prove(struct RLN *ctx, const struct Buffer *input_buffer, struct Buffer *output_buffer);
|
||||
|
||||
bool verify(const struct RLN *ctx, const struct Buffer *proof_buffer, bool *proof_is_valid_ptr);
|
||||
|
||||
bool generate_rln_proof(struct RLN *ctx,
|
||||
const struct Buffer *input_buffer,
|
||||
struct Buffer *output_buffer);
|
||||
|
||||
bool verify_rln_proof(const struct RLN *ctx,
|
||||
const struct Buffer *proof_buffer,
|
||||
bool *proof_is_valid_ptr);
|
||||
|
||||
bool verify_with_roots(const struct RLN *ctx,
|
||||
const struct Buffer *proof_buffer,
|
||||
const struct Buffer *roots_buffer,
|
||||
bool *proof_is_valid_ptr);
|
||||
|
||||
bool key_gen(const struct RLN *ctx, struct Buffer *output_buffer);
|
||||
|
||||
bool seeded_key_gen(const struct RLN *ctx,
|
||||
const struct Buffer *input_buffer,
|
||||
struct Buffer *output_buffer);
|
||||
|
||||
bool hash(struct RLN *ctx, const struct Buffer *input_buffer, struct Buffer *output_buffer);
|
||||
16
rln/link.go
16
rln/link.go
@ -1,16 +0,0 @@
|
||||
package rln
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS:-lrln -ldl -lm
|
||||
#cgo linux,arm LDFLAGS:-L${SRCDIR}/../libs/armv7-linux-androideabi
|
||||
#cgo linux,arm64 LDFLAGS:-L${SRCDIR}/../libs/aarch64-unknown-linux-gnu
|
||||
#cgo linux,amd64,musl,!android LDFLAGS:-L${SRCDIR}/../libs/x86_64-unknown-linux-musl
|
||||
#cgo linux,amd64,!musl,!android LDFLAGS:-L${SRCDIR}/../libs/x86_64-unknown-linux-gnu
|
||||
#cgo linux,386 LDFLAGS:-L${SRCDIR}/../libs/i686-unknown-linux-gnu
|
||||
#cgo windows,386 LDFLAGS:-L${SRCDIR}/../libs/i686-pc-windows-gnu -lrln -lm -lws2_32 -luserenv
|
||||
#cgo windows,amd64 LDFLAGS:-L${SRCDIR}/../libs/x86_64-pc-windows-gnu -lrln -lm -lws2_32 -luserenv
|
||||
#cgo darwin,386,!ios LDFLAGS:-L${SRCDIR}/../libs/i686-apple-darwin
|
||||
#cgo darwin,arm64,!ios LDFLAGS:-L${SRCDIR}/../libs/aarch64-apple-darwin
|
||||
#cgo darwin,amd64,!ios LDFLAGS:-L${SRCDIR}/../libs/x86_64-apple-darwin
|
||||
*/
|
||||
import "C"
|
||||
130
rln/link/apple.go
Normal file
130
rln/link/apple.go
Normal file
@ -0,0 +1,130 @@
|
||||
//go:build (386 || arm64 || amd64) && darwin && !ios
|
||||
// +build 386 arm64 amd64
|
||||
// +build darwin
|
||||
// +build !ios
|
||||
|
||||
package link
|
||||
|
||||
import (
|
||||
r "github.com/waku-org/go-zerokit-rln-apple/rln"
|
||||
)
|
||||
|
||||
type RLNWrapper struct {
|
||||
ffi *r.RLN
|
||||
}
|
||||
|
||||
func NewWithParams(depth int, wasm []byte, zkey []byte, verifKey []byte, treeConfig []byte) (*RLNWrapper, error) {
|
||||
rln, err := r.NewWithParams(depth, wasm, zkey, verifKey, treeConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RLNWrapper{ffi: rln}, nil
|
||||
}
|
||||
|
||||
func New(depth int, config []byte) (*RLNWrapper, error) {
|
||||
rln, err := r.New(uint(depth), config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RLNWrapper{ffi: rln}, nil
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetTree(treeHeight uint) bool {
|
||||
return i.ffi.SetTree(treeHeight)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) InitTreeWithLeaves(idcommitments []byte) bool {
|
||||
return i.ffi.InitTreeWithLeaves(idcommitments)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) KeyGen() []byte {
|
||||
return i.ffi.KeyGen()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SeededKeyGen(seed []byte) []byte {
|
||||
return i.ffi.SeededKeyGen(seed)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) ExtendedKeyGen() []byte {
|
||||
return i.ffi.ExtendedKeyGen()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) ExtendedSeededKeyGen(seed []byte) []byte {
|
||||
return i.ffi.ExtendedSeededKeyGen(seed)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) Hash(input []byte) ([]byte, error) {
|
||||
return i.ffi.Hash(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) PoseidonHash(input []byte) ([]byte, error) {
|
||||
return i.ffi.PoseidonHash(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetLeaf(index uint, idcommitment []byte) bool {
|
||||
return i.ffi.SetLeaf(index, idcommitment)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetNextLeaf(idcommitment []byte) bool {
|
||||
return i.ffi.SetNextLeaf(idcommitment)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetLeavesFrom(index uint, idcommitments []byte) bool {
|
||||
return i.ffi.SetLeavesFrom(index, idcommitments)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) DeleteLeaf(index uint) bool {
|
||||
return i.ffi.DeleteLeaf(index)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetRoot() ([]byte, error) {
|
||||
return i.ffi.GetRoot()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetLeaf(index uint) ([]byte, error) {
|
||||
return i.ffi.GetLeaf(index)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetMerkleProof(index uint) ([]byte, error) {
|
||||
return i.ffi.GetMerkleProof(index)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GenerateRLNProof(input []byte) ([]byte, error) {
|
||||
return i.ffi.GenerateRLNProof(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GenerateRLNProofWithWitness(input []byte) ([]byte, error) {
|
||||
return i.ffi.GenerateRLNProofWithWitness(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) VerifyWithRoots(input []byte, roots []byte) (bool, error) {
|
||||
return i.ffi.VerifyWithRoots(input, roots)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) AtomicOperation(index uint, leaves []byte, indices []byte) bool {
|
||||
return i.ffi.AtomicOperation(index, leaves, indices)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SeqAtomicOperation(leaves []byte, indices []byte) bool {
|
||||
return i.ffi.SeqAtomicOperation(leaves, indices)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) RecoverIDSecret(proof1 []byte, proof2 []byte) ([]byte, error) {
|
||||
return i.ffi.RecoverIDSecret(proof1, proof2)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetMetadata(metadata []byte) bool {
|
||||
return i.ffi.SetMetadata(metadata)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetMetadata() ([]byte, error) {
|
||||
return i.ffi.GetMetadata()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) Flush() bool {
|
||||
return i.ffi.Flush()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) LeavesSet() uint {
|
||||
return i.ffi.LeavesSet()
|
||||
}
|
||||
129
rln/link/arm.go
Normal file
129
rln/link/arm.go
Normal file
@ -0,0 +1,129 @@
|
||||
//go:build (arm || arm64) && linux
|
||||
// +build arm arm64
|
||||
// +build linux
|
||||
|
||||
package link
|
||||
|
||||
import (
|
||||
r "github.com/waku-org/go-zerokit-rln-arm/rln"
|
||||
)
|
||||
|
||||
type RLNWrapper struct {
|
||||
ffi *r.RLN
|
||||
}
|
||||
|
||||
func NewWithParams(depth int, wasm []byte, zkey []byte, verifKey []byte, treeConfig []byte) (*RLNWrapper, error) {
|
||||
rln, err := r.NewWithParams(depth, wasm, zkey, verifKey, treeConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RLNWrapper{ffi: rln}, nil
|
||||
}
|
||||
|
||||
func New(depth int, config []byte) (*RLNWrapper, error) {
|
||||
rln, err := r.New(uint(depth), config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RLNWrapper{ffi: rln}, nil
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetTree(treeHeight uint) bool {
|
||||
return i.ffi.SetTree(treeHeight)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) InitTreeWithLeaves(idcommitments []byte) bool {
|
||||
return i.ffi.InitTreeWithLeaves(idcommitments)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) KeyGen() []byte {
|
||||
return i.ffi.KeyGen()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SeededKeyGen(seed []byte) []byte {
|
||||
return i.ffi.SeededKeyGen(seed)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) ExtendedKeyGen() []byte {
|
||||
return i.ffi.ExtendedKeyGen()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) ExtendedSeededKeyGen(seed []byte) []byte {
|
||||
return i.ffi.ExtendedSeededKeyGen(seed)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) Hash(input []byte) ([]byte, error) {
|
||||
return i.ffi.Hash(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) PoseidonHash(input []byte) ([]byte, error) {
|
||||
return i.ffi.PoseidonHash(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetLeaf(index uint, idcommitment []byte) bool {
|
||||
return i.ffi.SetLeaf(index, idcommitment)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetNextLeaf(idcommitment []byte) bool {
|
||||
return i.ffi.SetNextLeaf(idcommitment)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetLeavesFrom(index uint, idcommitments []byte) bool {
|
||||
return i.ffi.SetLeavesFrom(index, idcommitments)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) DeleteLeaf(index uint) bool {
|
||||
return i.ffi.DeleteLeaf(index)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetRoot() ([]byte, error) {
|
||||
return i.ffi.GetRoot()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetLeaf(index uint) ([]byte, error) {
|
||||
return i.ffi.GetLeaf(index)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetMerkleProof(index uint) ([]byte, error) {
|
||||
return i.ffi.GetMerkleProof(index)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GenerateRLNProof(input []byte) ([]byte, error) {
|
||||
return i.ffi.GenerateRLNProof(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GenerateRLNProofWithWitness(input []byte) ([]byte, error) {
|
||||
return i.ffi.GenerateRLNProofWithWitness(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) VerifyWithRoots(input []byte, roots []byte) (bool, error) {
|
||||
return i.ffi.VerifyWithRoots(input, roots)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) AtomicOperation(index uint, leaves []byte, indices []byte) bool {
|
||||
return i.ffi.AtomicOperation(index, leaves, indices)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SeqAtomicOperation(leaves []byte, indices []byte) bool {
|
||||
return i.ffi.SeqAtomicOperation(leaves, indices)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) RecoverIDSecret(proof1 []byte, proof2 []byte) ([]byte, error) {
|
||||
return i.ffi.RecoverIDSecret(proof1, proof2)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetMetadata(metadata []byte) bool {
|
||||
return i.ffi.SetMetadata(metadata)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetMetadata() ([]byte, error) {
|
||||
return i.ffi.GetMetadata()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) Flush() bool {
|
||||
return i.ffi.Flush()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) LeavesSet() uint {
|
||||
return i.ffi.LeavesSet()
|
||||
}
|
||||
130
rln/link/x86_64.go
Normal file
130
rln/link/x86_64.go
Normal file
@ -0,0 +1,130 @@
|
||||
//go:build (linux || windows) && amd64 && !android
|
||||
// +build linux windows
|
||||
// +build amd64
|
||||
// +build !android
|
||||
|
||||
package link
|
||||
|
||||
import (
|
||||
r "github.com/waku-org/go-zerokit-rln-x86_64/rln"
|
||||
)
|
||||
|
||||
type RLNWrapper struct {
|
||||
ffi *r.RLN
|
||||
}
|
||||
|
||||
func NewWithParams(depth int, wasm []byte, zkey []byte, verifKey []byte, treeConfig []byte) (*RLNWrapper, error) {
|
||||
rln, err := r.NewWithParams(depth, wasm, zkey, verifKey, treeConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RLNWrapper{ffi: rln}, nil
|
||||
}
|
||||
|
||||
func New(depth int, config []byte) (*RLNWrapper, error) {
|
||||
rln, err := r.New(uint(depth), config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RLNWrapper{ffi: rln}, nil
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetTree(treeHeight uint) bool {
|
||||
return i.ffi.SetTree(treeHeight)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) InitTreeWithLeaves(idcommitments []byte) bool {
|
||||
return i.ffi.InitTreeWithLeaves(idcommitments)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) KeyGen() []byte {
|
||||
return i.ffi.KeyGen()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SeededKeyGen(seed []byte) []byte {
|
||||
return i.ffi.SeededKeyGen(seed)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) ExtendedKeyGen() []byte {
|
||||
return i.ffi.ExtendedKeyGen()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) ExtendedSeededKeyGen(seed []byte) []byte {
|
||||
return i.ffi.ExtendedSeededKeyGen(seed)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) Hash(input []byte) ([]byte, error) {
|
||||
return i.ffi.Hash(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) PoseidonHash(input []byte) ([]byte, error) {
|
||||
return i.ffi.PoseidonHash(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetLeaf(index uint, idcommitment []byte) bool {
|
||||
return i.ffi.SetLeaf(index, idcommitment)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetNextLeaf(idcommitment []byte) bool {
|
||||
return i.ffi.SetNextLeaf(idcommitment)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetLeavesFrom(index uint, idcommitments []byte) bool {
|
||||
return i.ffi.SetLeavesFrom(index, idcommitments)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) DeleteLeaf(index uint) bool {
|
||||
return i.ffi.DeleteLeaf(index)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetRoot() ([]byte, error) {
|
||||
return i.ffi.GetRoot()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetLeaf(index uint) ([]byte, error) {
|
||||
return i.ffi.GetLeaf(index)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetMerkleProof(index uint) ([]byte, error) {
|
||||
return i.ffi.GetMerkleProof(index)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GenerateRLNProof(input []byte) ([]byte, error) {
|
||||
return i.ffi.GenerateRLNProof(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GenerateRLNProofWithWitness(input []byte) ([]byte, error) {
|
||||
return i.ffi.GenerateRLNProofWithWitness(input)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) VerifyWithRoots(input []byte, roots []byte) (bool, error) {
|
||||
return i.ffi.VerifyWithRoots(input, roots)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) AtomicOperation(index uint, leaves []byte, indices []byte) bool {
|
||||
return i.ffi.AtomicOperation(index, leaves, indices)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SeqAtomicOperation(leaves []byte, indices []byte) bool {
|
||||
return i.ffi.SeqAtomicOperation(leaves, indices)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) RecoverIDSecret(proof1 []byte, proof2 []byte) ([]byte, error) {
|
||||
return i.ffi.RecoverIDSecret(proof1, proof2)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) SetMetadata(metadata []byte) bool {
|
||||
return i.ffi.SetMetadata(metadata)
|
||||
}
|
||||
|
||||
func (i RLNWrapper) GetMetadata() ([]byte, error) {
|
||||
return i.ffi.GetMetadata()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) Flush() bool {
|
||||
return i.ffi.Flush()
|
||||
}
|
||||
|
||||
func (i RLNWrapper) LeavesSet() uint {
|
||||
return i.ffi.LeavesSet()
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -1,3 +0,0 @@
|
||||
package resources
|
||||
|
||||
//go:generate go-bindata -pkg resources -o ./bindata.go ./...
|
||||
Binary file not shown.
Binary file not shown.
@ -1,119 +0,0 @@
|
||||
{
|
||||
"protocol": "groth16",
|
||||
"curve": "bn128",
|
||||
"nPublic": 6,
|
||||
"vk_alpha_1": [
|
||||
"1805378556360488226980822394597799963030511477964155500103132920745199284516",
|
||||
"11990395240534218699464972016456017378439762088320057798320175886595281336136",
|
||||
"1"
|
||||
],
|
||||
"vk_beta_2": [
|
||||
[
|
||||
"11031529986141021025408838211017932346992429731488270384177563837022796743627",
|
||||
"16042159910707312759082561183373181639420894978640710177581040523252926273854"
|
||||
],
|
||||
[
|
||||
"20112698439519222240302944148895052359035104222313380895334495118294612255131",
|
||||
"19441583024670359810872018179190533814486480928824742448673677460151702019379"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_gamma_2": [
|
||||
[
|
||||
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
||||
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
|
||||
],
|
||||
[
|
||||
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
||||
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_delta_2": [
|
||||
[
|
||||
"1948496782571164085469528023647105317580208688174386157591917599801657832035",
|
||||
"20445814069256658101339037520922621162739470138213615104905368409238414511981"
|
||||
],
|
||||
[
|
||||
"10024680869920840984813249386422727863826862577760330492647062850849851925340",
|
||||
"10512156247842686783409460795717734694774542185222602679117887145206209285142"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"0"
|
||||
]
|
||||
],
|
||||
"vk_alphabeta_12": [
|
||||
[
|
||||
[
|
||||
"5151991366823434428398919091000210787450832786814248297320989361921939794156",
|
||||
"15735191313289001022885148627913534790382722933676436876510746491415970766821"
|
||||
],
|
||||
[
|
||||
"3387907257437913904447588318761906430938415556102110876587455322225272831272",
|
||||
"1998779853452712881084781956683721603875246565720647583735935725110674288056"
|
||||
],
|
||||
[
|
||||
"14280074182991498185075387990446437410077692353432005297922275464876153151820",
|
||||
"17092408446352310039633488224969232803092763095456307462247653153107223117633"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"4359046709531668109201634396816565829237358165496082832279660960675584351266",
|
||||
"4511888308846208349307186938266411423935335853916317436093178288331845821336"
|
||||
],
|
||||
[
|
||||
"11429499807090785857812316277335883295048773373068683863667725283965356423273",
|
||||
"16232274853200678548795010078253506586114563833318973594428907292096178657392"
|
||||
],
|
||||
[
|
||||
"18068999605870933925311275504102553573815570223888590384919752303726860800970",
|
||||
"17309569111965782732372130116757295842160193489132771344011460471298173784984"
|
||||
]
|
||||
]
|
||||
],
|
||||
"IC": [
|
||||
[
|
||||
"18693301901828818437917730940595978397160482710354161265484535387752523310572",
|
||||
"17985273354976640088538673802000794244421192643855111089693820179790551470769",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"21164641723988537620541455173278629777250883365474191521194244273980931825942",
|
||||
"998385854410718613441067082771678946155853656328717326195057262123686425518",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"21666968581672145768705229094968410656430989593283335488162701230986314747515",
|
||||
"17996457608540683483506630273632100555125353447506062045735279661096094677264",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"20137761979695192602424300886442379728165712610493092740175904438282083668117",
|
||||
"19184814924890679891263780109959113289320127263583260218200636509492157834679",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"10943171273393803842589314082509655332154393332394322726077270895078286354146",
|
||||
"10872472035685319847811233167729172672344935625121511932198535224727331126439",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"13049169779481227658517545034348883391527506091990880778783387628208561946597",
|
||||
"10083689369261379027228809473568899816311684698866922944902456565434209079955",
|
||||
"1"
|
||||
],
|
||||
[
|
||||
"19633516378466409167014413361365552102431118630694133723053441455184566611083",
|
||||
"8059525100726933978719058611146131904598011633549012007359165766216730722269",
|
||||
"1"
|
||||
]
|
||||
]
|
||||
}
|
||||
616
rln/rln.go
616
rln/rln.go
@ -1,121 +1,163 @@
|
||||
package rln
|
||||
|
||||
/*
|
||||
#include "./librln.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"unsafe"
|
||||
"fmt"
|
||||
|
||||
"github.com/status-im/go-zerokit-rln/rln/resources"
|
||||
"github.com/waku-org/go-zerokit-rln/rln/link"
|
||||
)
|
||||
|
||||
// Same as: https://github.com/vacp2p/zerokit/blob/v0.3.5/rln/src/public.rs#L35
|
||||
// Prevents a RLN ZK proof generated for one application to be re-used in another one.
|
||||
var RLN_IDENTIFIER = [32]byte{166, 140, 43, 8, 8, 22, 206, 113, 151, 128, 118, 40, 119, 197, 218, 174, 11, 117, 84, 228, 96, 211, 212, 140, 145, 104, 146, 99, 24, 192, 217, 4}
|
||||
|
||||
var DEFAULT_USER_MESSAGE_LIMIT = uint32(10)
|
||||
|
||||
// RLN represents the context used for rln.
|
||||
type RLN struct {
|
||||
ptr *C.RLN
|
||||
w *link.RLNWrapper
|
||||
}
|
||||
|
||||
func getResourcesFolder(depth TreeDepth) string {
|
||||
return fmt.Sprintf("tree_height_%d", depth)
|
||||
}
|
||||
|
||||
// NewRLN generates an instance of RLN. An instance supports both zkSNARKs logics
|
||||
// and Merkle tree data structure and operations. It uses a depth of 20 by default
|
||||
func NewRLN() (*RLN, error) {
|
||||
|
||||
wasm, err := resources.Asset("tree_height_20/rln.wasm")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zkey, err := resources.Asset("tree_height_20/rln_final.zkey")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
verifKey, err := resources.Asset("tree_height_20/verification_key.json")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := &RLN{}
|
||||
|
||||
depth := 20
|
||||
|
||||
wasmBuffer := toCBufferPtr(wasm)
|
||||
zkeyBuffer := toCBufferPtr(zkey)
|
||||
verifKeyBuffer := toCBufferPtr(verifKey)
|
||||
|
||||
if !bool(C.new_with_params(C.uintptr_t(depth), wasmBuffer, zkeyBuffer, verifKeyBuffer, &r.ptr)) {
|
||||
return nil, errors.New("failed to initialize")
|
||||
}
|
||||
|
||||
return r, nil
|
||||
return NewWithConfig(DefaultTreeDepth, nil)
|
||||
}
|
||||
|
||||
// NewRLNWithParams generates an instance of RLN. An instance supports both zkSNARKs logics
|
||||
// and Merkle tree data structure and operations. The parameter `depth“ indicates the depth of Merkle tree
|
||||
func NewRLNWithParams(depth int, wasm []byte, zkey []byte, verifKey []byte) (*RLN, error) {
|
||||
func NewRLNWithParams(depth int, wasm []byte, zkey []byte, verifKey []byte, treeConfig *TreeConfig) (*RLN, error) {
|
||||
r := &RLN{}
|
||||
var err error
|
||||
|
||||
wasmBuffer := toCBufferPtr(wasm)
|
||||
zkeyBuffer := toCBufferPtr(zkey)
|
||||
verifKeyBuffer := toCBufferPtr(verifKey)
|
||||
treeConfigBytes := []byte{}
|
||||
if treeConfig != nil {
|
||||
treeConfigBytes, err = json.Marshal(treeConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if !bool(C.new_with_params(C.uintptr_t(depth), wasmBuffer, zkeyBuffer, verifKeyBuffer, &r.ptr)) {
|
||||
return nil, errors.New("failed to initialize")
|
||||
r.w, err = link.NewWithParams(depth, wasm, zkey, verifKey, treeConfigBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// NewRLNWithFolder generates an instance of RLN. An instance supports both zkSNARKs logics
|
||||
// and Merkle tree data structure and operations. The parameter `deptk` indicates the depth of Merkle tree
|
||||
// The parameter “
|
||||
func NewRLNWithFolder(depth int, resourcesFolderPath string) (*RLN, error) {
|
||||
// NewWithConfig generates an instance of RLN. An instance supports both zkSNARKs logics
|
||||
// and Merkle tree data structure and operations. The parameter `depth` indicates the depth of Merkle tree
|
||||
func NewWithConfig(depth TreeDepth, treeConfig *TreeConfig) (*RLN, error) {
|
||||
r := &RLN{}
|
||||
var err error
|
||||
|
||||
pathBuffer := toCBufferPtr([]byte(resourcesFolderPath))
|
||||
configBytes, err := json.Marshal(config{
|
||||
ResourcesFolder: getResourcesFolder(depth),
|
||||
TreeConfig: treeConfig,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !bool(C.new(C.uintptr_t(depth), pathBuffer, &r.ptr)) {
|
||||
return nil, errors.New("failed to initialize")
|
||||
r.w, err = link.New(int(depth), configBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func toCBufferPtr(input []byte) *C.Buffer {
|
||||
buf := toBuffer(input)
|
||||
|
||||
size := int(unsafe.Sizeof(buf))
|
||||
in := (*C.Buffer)(C.malloc(C.size_t(size)))
|
||||
*in = buf
|
||||
|
||||
return in
|
||||
func (r *RLN) SetTree(treeHeight uint) error {
|
||||
success := r.w.SetTree(treeHeight)
|
||||
if !success {
|
||||
return errors.New("could not set tree height")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MembershipKeyGen generates a MembershipKeyPair that can be used for the registration into the rln membership contract
|
||||
func (r *RLN) MembershipKeyGen() (*MembershipKeyPair, error) {
|
||||
buffer := toBuffer([]byte{})
|
||||
if !bool(C.key_gen(r.ptr, &buffer)) {
|
||||
return nil, errors.New("error in key generation")
|
||||
// Initialize merkle tree with a list of IDCommitments
|
||||
func (r *RLN) InitTreeWithMembers(idComms []IDCommitment) error {
|
||||
idCommBytes := serializeCommitments(idComms)
|
||||
initSuccess := r.w.InitTreeWithLeaves(idCommBytes)
|
||||
if !initSuccess {
|
||||
return errors.New("could not init tree")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toIdentityCredential(generatedKeys []byte, userMessageLimit uint32) (*IdentityCredential, error) {
|
||||
// add user message limit
|
||||
key := &IdentityCredential{
|
||||
IDTrapdoor: [32]byte{},
|
||||
IDNullifier: [32]byte{},
|
||||
IDSecretHash: [32]byte{},
|
||||
IDCommitment: [32]byte{},
|
||||
UserMessageLimit: userMessageLimit,
|
||||
}
|
||||
|
||||
key := &MembershipKeyPair{
|
||||
IDKey: [32]byte{},
|
||||
IDCommitment: [32]byte{},
|
||||
if len(generatedKeys) != 32*4 {
|
||||
return nil, errors.New("generated keys are of invalid length")
|
||||
}
|
||||
|
||||
// the public and secret keys together are 64 bytes
|
||||
generatedKeys := C.GoBytes(unsafe.Pointer(buffer.ptr), C.int(buffer.len))
|
||||
if len(generatedKeys) != 64 {
|
||||
return nil, errors.New("the generated keys are invalid")
|
||||
}
|
||||
|
||||
copy(key.IDKey[:], generatedKeys[:32])
|
||||
copy(key.IDCommitment[:], generatedKeys[32:64])
|
||||
copy(key.IDTrapdoor[:], generatedKeys[:32])
|
||||
copy(key.IDNullifier[:], generatedKeys[32:64])
|
||||
copy(key.IDSecretHash[:], generatedKeys[64:96])
|
||||
copy(key.IDCommitment[:], generatedKeys[96:128])
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// MembershipKeyGen generates a IdentityCredential that can be used for the
|
||||
// registration into the rln membership contract. Returns an error if the key generation fails
|
||||
// Accepts an optional parameter that sets the user message limit which defaults
|
||||
// to DEFAULT_USER_MESSAGE_LIMIT
|
||||
func (r *RLN) MembershipKeyGen(userMessageLimitParam ...uint32) (*IdentityCredential, error) {
|
||||
var userMessageLimit uint32
|
||||
if len(userMessageLimitParam) == 1 {
|
||||
userMessageLimit = userMessageLimitParam[0]
|
||||
} else if len(userMessageLimitParam) == 0 {
|
||||
userMessageLimit = DEFAULT_USER_MESSAGE_LIMIT
|
||||
} else {
|
||||
return nil, errors.New("just one user message limit is allowed")
|
||||
}
|
||||
|
||||
generatedKeys := r.w.ExtendedKeyGen()
|
||||
if generatedKeys == nil {
|
||||
return nil, errors.New("error in key generation")
|
||||
}
|
||||
return toIdentityCredential(generatedKeys, userMessageLimit)
|
||||
}
|
||||
|
||||
// SeededMembershipKeyGen generates a deterministic IdentityCredential using a seed
|
||||
// that can be used for the registration into the rln membership contract.
|
||||
// Returns an error if the key generation fails
|
||||
// Accepts an optional parameter that sets the user message limit which defaults
|
||||
// to DEFAULT_USER_MESSAGE_LIMIT
|
||||
func (r *RLN) SeededMembershipKeyGen(seed []byte, userMessageLimitParam ...uint32) (*IdentityCredential, error) {
|
||||
var userMessageLimit uint32
|
||||
if len(userMessageLimitParam) == 1 {
|
||||
userMessageLimit = userMessageLimitParam[0]
|
||||
} else if len(userMessageLimitParam) == 0 {
|
||||
userMessageLimit = DEFAULT_USER_MESSAGE_LIMIT
|
||||
} else {
|
||||
return nil, errors.New("just one user message limit is allowed")
|
||||
}
|
||||
|
||||
generatedKeys := r.w.ExtendedSeededKeyGen(seed)
|
||||
if generatedKeys == nil {
|
||||
return nil, errors.New("error in key generation")
|
||||
}
|
||||
return toIdentityCredential(generatedKeys, userMessageLimit)
|
||||
}
|
||||
|
||||
// appendLength returns length prefixed version of the input with the following format
|
||||
// [len<8>|input<var>], the len is a 8 byte value serialized in little endian
|
||||
func appendLength(input []byte) []byte {
|
||||
@ -124,40 +166,40 @@ func appendLength(input []byte) []byte {
|
||||
return append(inputLen, input...)
|
||||
}
|
||||
|
||||
// toBuffer converts the input to a buffer object that is used to communicate data with the rln lib
|
||||
func toBuffer(data []byte) C.Buffer {
|
||||
dataPtr, dataLen := sliceToPtr(data)
|
||||
return C.Buffer{
|
||||
ptr: dataPtr,
|
||||
len: C.uintptr_t(dataLen),
|
||||
}
|
||||
// Similar to appendLength but for 32 byte values. The length that is prepended is
|
||||
// the length of elements that are 32 bytes long each
|
||||
func appendLength32(input []byte) []byte {
|
||||
inputLen := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(inputLen, uint64(len(input)/32))
|
||||
return append(inputLen, input...)
|
||||
}
|
||||
|
||||
func sliceToPtr(slice []byte) (*C.uchar, C.int) {
|
||||
if len(slice) == 0 {
|
||||
return nil, 0
|
||||
} else {
|
||||
return (*C.uchar)(unsafe.Pointer(&slice[0])), C.int(len(slice))
|
||||
}
|
||||
}
|
||||
|
||||
// Hash hashes the plain text supplied in inputs_buffer and then maps it to a field element
|
||||
// this proc is used to map arbitrary signals to field element for the sake of proof generation
|
||||
// inputs holds the hash input as a byte slice, the output slice will contain a 32 byte slice
|
||||
func (r *RLN) Hash(data []byte) (MerkleNode, error) {
|
||||
// a thin layer on top of the Nim wrapper of the Poseidon hasher
|
||||
func (r *RLN) Sha256(data []byte) (MerkleNode, error) {
|
||||
lenPrefData := appendLength(data)
|
||||
|
||||
hashInputBuffer := toCBufferPtr(lenPrefData)
|
||||
|
||||
var output []byte
|
||||
out := toBuffer(output)
|
||||
|
||||
if !bool(C.hash(r.ptr, hashInputBuffer, &out)) {
|
||||
return MerkleNode{}, errors.New("failed to hash")
|
||||
b, err := r.w.Hash(lenPrefData)
|
||||
if err != nil {
|
||||
return MerkleNode{}, err
|
||||
}
|
||||
|
||||
b := C.GoBytes(unsafe.Pointer(out.ptr), C.int(out.len))
|
||||
var result MerkleNode
|
||||
copy(result[:], b)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *RLN) Poseidon(input ...[]byte) (MerkleNode, error) {
|
||||
data := serializeSlice(input)
|
||||
|
||||
inputLen := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(inputLen, uint64(len(input)))
|
||||
|
||||
lenPrefData := append(inputLen, data...)
|
||||
|
||||
b, err := r.w.PoseidonHash(lenPrefData)
|
||||
if err != nil {
|
||||
return MerkleNode{}, err
|
||||
}
|
||||
|
||||
var result MerkleNode
|
||||
copy(result[:], b)
|
||||
@ -168,71 +210,132 @@ func (r *RLN) Hash(data []byte) (MerkleNode, error) {
|
||||
// GenerateProof generates a proof for the RLN given a KeyPair and the index in a merkle tree.
|
||||
// The output will containt the proof data and should be parsed as |proof<128>|root<32>|epoch<32>|share_x<32>|share_y<32>|nullifier<32>|
|
||||
// integers wrapped in <> indicate value sizes in bytes
|
||||
func (r *RLN) GenerateProof(data []byte, key MembershipKeyPair, index MembershipIndex, epoch Epoch) (*RateLimitProof, error) {
|
||||
input := serialize(key.IDKey, index, epoch, data)
|
||||
inputBuffer := toCBufferPtr(input)
|
||||
func (r *RLN) GenerateProof(
|
||||
data []byte,
|
||||
key IdentityCredential,
|
||||
index MembershipIndex,
|
||||
epoch Epoch,
|
||||
messageId uint32) (*RateLimitProof, error) {
|
||||
|
||||
var output []byte
|
||||
out := toBuffer(output)
|
||||
|
||||
if !bool(C.generate_rln_proof(r.ptr, inputBuffer, &out)) {
|
||||
return nil, errors.New("could not generate the proof")
|
||||
externalNullifierInput, err := r.Poseidon(epoch[:], RLN_IDENTIFIER[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not construct the external nullifier: %w", err)
|
||||
}
|
||||
|
||||
proofBytes := C.GoBytes(unsafe.Pointer(out.ptr), C.int(out.len))
|
||||
|
||||
if len(proofBytes) != 320 {
|
||||
return nil, errors.New("invalid proof generated")
|
||||
input := serialize(key.IDSecretHash, index, key.UserMessageLimit, messageId, externalNullifierInput, data)
|
||||
proofBytes, err := r.w.GenerateRLNProof(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// parse the proof as [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ]
|
||||
expectedBytes := 288
|
||||
if len(proofBytes) != expectedBytes {
|
||||
return nil, fmt.Errorf("invalid proof generated. size: %d expected: %d",
|
||||
len(proofBytes), expectedBytes)
|
||||
}
|
||||
|
||||
// parse proof taken from: https://github.com/vacp2p/zerokit/blob/v0.5.0/rln/src/public.rs#L750
|
||||
// [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32>]
|
||||
proofOffset := 128
|
||||
rootOffset := proofOffset + 32
|
||||
epochOffset := rootOffset + 32
|
||||
shareXOffset := epochOffset + 32
|
||||
externalNullifierOffset := rootOffset + 32
|
||||
shareXOffset := externalNullifierOffset + 32
|
||||
shareYOffset := shareXOffset + 32
|
||||
nullifierOffset := shareYOffset + 32
|
||||
rlnIdentifierOffset := nullifierOffset + 32
|
||||
|
||||
var zkproof ZKSNARK
|
||||
var proofRoot, shareX, shareY MerkleNode
|
||||
var epochR Epoch
|
||||
var externalNullifier Nullifier
|
||||
var nullifier Nullifier
|
||||
var rlnIdentifier RLNIdentifier
|
||||
|
||||
copy(zkproof[:], proofBytes[0:proofOffset])
|
||||
copy(proofRoot[:], proofBytes[proofOffset:rootOffset])
|
||||
copy(epochR[:], proofBytes[rootOffset:epochOffset])
|
||||
copy(shareX[:], proofBytes[epochOffset:shareXOffset])
|
||||
copy(externalNullifier[:], proofBytes[rootOffset:externalNullifierOffset])
|
||||
copy(shareX[:], proofBytes[externalNullifierOffset:shareXOffset])
|
||||
copy(shareY[:], proofBytes[shareXOffset:shareYOffset])
|
||||
copy(nullifier[:], proofBytes[shareYOffset:nullifierOffset])
|
||||
copy(rlnIdentifier[:], proofBytes[nullifierOffset:rlnIdentifierOffset])
|
||||
|
||||
return &RateLimitProof{
|
||||
Proof: zkproof,
|
||||
MerkleRoot: proofRoot,
|
||||
Epoch: epochR,
|
||||
ShareX: shareX,
|
||||
ShareY: shareY,
|
||||
Nullifier: nullifier,
|
||||
RLNIdentifier: rlnIdentifier,
|
||||
Proof: zkproof,
|
||||
MerkleRoot: proofRoot,
|
||||
ExternalNullifier: externalNullifier,
|
||||
ShareX: shareX,
|
||||
ShareY: shareY,
|
||||
Nullifier: nullifier,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Verify verifies a proof generated for the RLN.
|
||||
// proof [ proof<128>| root<32>| epoch<32>| share_x<32>| share_y<32>| nullifier<32> | signal_len<8> | signal<var> ]
|
||||
func (r *RLN) Verify(data []byte, proof RateLimitProof) (bool, error) {
|
||||
proofBytes := proof.serialize(data)
|
||||
proofBuf := toCBufferPtr(proofBytes)
|
||||
res := C.bool(false)
|
||||
if !bool(C.verify_rln_proof(r.ptr, proofBuf, &res)) {
|
||||
return false, errors.New("could not verify rln proof")
|
||||
// Returns a RLN proof with a custom witness, so no tree is required in the RLN instance
|
||||
// to calculate such proof. The witness can be created with GetMerkleProof data.
|
||||
func (r *RLN) GenerateRLNProofWithWitness(witness RLNWitnessInput) (*RateLimitProof, error) {
|
||||
// serialized as: https://github.com/vacp2p/zerokit/blob/v0.5.0/rln/src/protocol.rs#L127
|
||||
// input [ id_secret_hash<32> | user_message_limit<32> | message_id<32> | num_elements<8> | path_elements<var1> | num_indexes<8> | path_indexes<var2> | external_nullifier<32> ]
|
||||
proofBytes, err := r.w.GenerateRLNProofWithWitness(witness.serialize())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bool(res), nil
|
||||
expectedBytes := 288
|
||||
if len(proofBytes) != expectedBytes {
|
||||
return nil, fmt.Errorf("invalid proof generated. size: %d expected: %d",
|
||||
len(proofBytes), expectedBytes)
|
||||
}
|
||||
|
||||
// parse proof taken from: https://github.com/vacp2p/zerokit/blob/v0.5.0/rln/src/public.rs#L750
|
||||
// [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32>]
|
||||
proofOffset := 128
|
||||
rootOffset := proofOffset + 32
|
||||
externalNullifierOffset := rootOffset + 32
|
||||
shareXOffset := externalNullifierOffset + 32
|
||||
shareYOffset := shareXOffset + 32
|
||||
nullifierOffset := shareYOffset + 32
|
||||
|
||||
var zkproof ZKSNARK
|
||||
var proofRoot, shareX, shareY MerkleNode
|
||||
var externalNullifier Nullifier
|
||||
var nullifier Nullifier
|
||||
|
||||
copy(zkproof[:], proofBytes[0:proofOffset])
|
||||
copy(proofRoot[:], proofBytes[proofOffset:rootOffset])
|
||||
copy(externalNullifier[:], proofBytes[rootOffset:externalNullifierOffset])
|
||||
copy(shareX[:], proofBytes[externalNullifierOffset:shareXOffset])
|
||||
copy(shareY[:], proofBytes[shareXOffset:shareYOffset])
|
||||
copy(nullifier[:], proofBytes[shareYOffset:nullifierOffset])
|
||||
|
||||
return &RateLimitProof{
|
||||
Proof: zkproof,
|
||||
MerkleRoot: proofRoot,
|
||||
ExternalNullifier: externalNullifier,
|
||||
ShareX: shareX,
|
||||
ShareY: shareY,
|
||||
Nullifier: nullifier,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func serializeRoots(roots [][32]byte) []byte {
|
||||
func (r *RLN) CreateWitness(
|
||||
idSecretHash IDSecretHash,
|
||||
userMessageLimit uint32,
|
||||
messageId uint32,
|
||||
data []byte,
|
||||
epoch [32]byte,
|
||||
merkleProof MerkleProof) (RLNWitnessInput, error) {
|
||||
|
||||
externalNullifier, err := r.Poseidon(epoch[:], RLN_IDENTIFIER[:])
|
||||
if err != nil {
|
||||
return RLNWitnessInput{}, fmt.Errorf("could not construct the external nullifier: %w", err)
|
||||
}
|
||||
|
||||
return RLNWitnessInput{
|
||||
IDSecretHash: idSecretHash,
|
||||
UserMessageLimit: userMessageLimit,
|
||||
MessageId: messageId,
|
||||
MerkleProof: merkleProof,
|
||||
X: HashToBN255(data),
|
||||
ExternalNullifier: externalNullifier,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func serialize32(roots [][32]byte) []byte {
|
||||
var result []byte
|
||||
for _, r := range roots {
|
||||
result = append(result, r[:]...)
|
||||
@ -240,25 +343,113 @@ func serializeRoots(roots [][32]byte) []byte {
|
||||
return result
|
||||
}
|
||||
|
||||
func (r *RLN) VerifyWithRoots(data []byte, proof RateLimitProof, roots [][32]byte) (bool, error) {
|
||||
proofBytes := proof.serialize(data)
|
||||
proofBuf := toCBufferPtr(proofBytes)
|
||||
|
||||
rootBytes := serializeRoots(roots)
|
||||
rootBuf := toCBufferPtr(rootBytes)
|
||||
|
||||
res := C.bool(false)
|
||||
if !bool(C.verify_with_roots(r.ptr, proofBuf, rootBuf, &res)) {
|
||||
return false, errors.New("could not verify with roots")
|
||||
func serializeSlice(roots [][]byte) []byte {
|
||||
var result []byte
|
||||
for _, r := range roots {
|
||||
result = append(result, r[:]...)
|
||||
}
|
||||
|
||||
return bool(res), nil
|
||||
return result
|
||||
}
|
||||
|
||||
// InsertMember adds the member to the tree
|
||||
func (r *RLN) InsertMember(idComm IDCommitment) error {
|
||||
idCommBuffer := toCBufferPtr(idComm[:])
|
||||
insertionSuccess := bool(C.set_next_leaf(r.ptr, idCommBuffer))
|
||||
func serializeCommitments(commitments []IDCommitment) []byte {
|
||||
// serializes a seq of IDCommitments to a byte seq
|
||||
// the serialization is based on https://github.com/status-im/nwaku/blob/37bd29fbc37ce5cf636734e7dd410b1ed27b88c8/waku/v2/protocol/waku_rln_relay/rln.nim#L142
|
||||
// the order of serialization is |id_commitment_len<8>|id_commitment<var>|
|
||||
var result []byte
|
||||
|
||||
inputLen := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(inputLen, uint64(len(commitments)))
|
||||
result = append(result, inputLen...)
|
||||
|
||||
for _, idComm := range commitments {
|
||||
result = append(result, idComm[:]...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func serializeIndices(indices []MembershipIndex) []byte {
|
||||
var result []byte
|
||||
|
||||
inputLen := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(inputLen, uint64(len(indices)))
|
||||
result = append(result, inputLen...)
|
||||
|
||||
for _, index := range indices {
|
||||
result = binary.LittleEndian.AppendUint64(result, uint64(index))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// proof [ proof<128>| root<32>| epoch<32>| share_x<32>| share_y<32>| nullifier<32> | signal_len<8> | signal<var> ]
|
||||
// validRoots should contain a sequence of roots in the acceptable windows.
|
||||
// As default, it is set to an empty sequence of roots. This implies that the validity check for the proof's root is skipped
|
||||
func (r *RLN) Verify(data []byte, proof RateLimitProof, roots ...[32]byte) (bool, error) {
|
||||
proofBytes := proof.serializeWithData(data)
|
||||
rootBytes := serialize32(roots)
|
||||
|
||||
res, err := r.w.VerifyWithRoots(proofBytes, rootBytes)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// RecoverIDSecret returns an IDSecret having obtained before two proofs
|
||||
func (r *RLN) RecoverIDSecret(proof1 RateLimitProof, proof2 RateLimitProof) (IDSecretHash, error) {
|
||||
proof1Bytes := proof1.serialize()
|
||||
proof2Bytes := proof2.serialize()
|
||||
secret, err := r.w.RecoverIDSecret(proof1Bytes, proof2Bytes)
|
||||
if err != nil {
|
||||
return IDSecretHash{}, err
|
||||
}
|
||||
var result IDSecretHash
|
||||
copy(result[:], secret)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// InsertMember adds the member to the tree. The leaf is made of
|
||||
// the id commitment and the user message limit
|
||||
func (r *RLN) InsertMember(idComm IDCommitment, userMessageLimit uint32) error {
|
||||
userMessageLimitBytes := SerializeUint32(userMessageLimit)
|
||||
|
||||
hashedLeaf, err := r.Poseidon(idComm[:], userMessageLimitBytes[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
insertionSuccess := r.w.SetNextLeaf(hashedLeaf[:])
|
||||
if !insertionSuccess {
|
||||
return errors.New("could not insert member")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RLN) InsertRawLeaf(rawLeaf MerkleNode) error {
|
||||
insertionSuccess := r.w.SetNextLeaf(rawLeaf[:])
|
||||
if !insertionSuccess {
|
||||
return errors.New("could not insert raw leaf")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Insert multiple members i.e., identity commitments starting from index
|
||||
// This proc is atomic, i.e., if any of the insertions fails, all the previous insertions are rolled back
|
||||
func (r *RLN) InsertMembers(index MembershipIndex, idComms []IDCommitment) error {
|
||||
idCommBytes := serializeCommitments(idComms)
|
||||
indicesBytes := serializeIndices(nil)
|
||||
insertionSuccess := r.w.AtomicOperation(index, idCommBytes, indicesBytes)
|
||||
if !insertionSuccess {
|
||||
return errors.New("could not insert members")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Insert a member in the tree at specified index
|
||||
func (r *RLN) InsertMemberAt(index MembershipIndex, idComm IDCommitment) error {
|
||||
insertionSuccess := r.w.SetLeaf(index, idComm[:])
|
||||
if !insertionSuccess {
|
||||
return errors.New("could not insert member")
|
||||
}
|
||||
@ -269,24 +460,31 @@ func (r *RLN) InsertMember(idComm IDCommitment) error {
|
||||
// parameter is the position of the id commitment key to be deleted from the tree.
|
||||
// The deleted id commitment key is replaced with a zero leaf
|
||||
func (r *RLN) DeleteMember(index MembershipIndex) error {
|
||||
deletionSuccess := bool(C.delete_leaf(r.ptr, C.uintptr_t(index)))
|
||||
deletionSuccess := r.w.DeleteLeaf(index)
|
||||
if !deletionSuccess {
|
||||
return errors.New("could not delete member")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete multiple members
|
||||
func (r *RLN) DeleteMembers(indices []MembershipIndex) error {
|
||||
idCommBytes := serializeCommitments(nil)
|
||||
indicesBytes := serializeIndices(indices)
|
||||
insertionSuccess := r.w.AtomicOperation(0, idCommBytes, indicesBytes)
|
||||
if !insertionSuccess {
|
||||
return errors.New("could not insert members")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMerkleRoot reads the Merkle Tree root after insertion
|
||||
func (r *RLN) GetMerkleRoot() (MerkleNode, error) {
|
||||
var output []byte
|
||||
out := toBuffer(output)
|
||||
|
||||
if !bool(C.get_root(r.ptr, &out)) {
|
||||
return MerkleNode{}, errors.New("could not get the root")
|
||||
b, err := r.w.GetRoot()
|
||||
if err != nil {
|
||||
return MerkleNode{}, err
|
||||
}
|
||||
|
||||
b := C.GoBytes(unsafe.Pointer(out.ptr), C.int(out.len))
|
||||
|
||||
if len(b) != 32 {
|
||||
return MerkleNode{}, errors.New("wrong output size")
|
||||
}
|
||||
@ -297,10 +495,48 @@ func (r *RLN) GetMerkleRoot() (MerkleNode, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetLeaf reads the value stored at some index in the Merkle Tree
|
||||
func (r *RLN) GetLeaf(index MembershipIndex) (IDCommitment, error) {
|
||||
b, err := r.w.GetLeaf(index)
|
||||
if err != nil {
|
||||
return IDCommitment{}, err
|
||||
}
|
||||
|
||||
if len(b) != 32 {
|
||||
return IDCommitment{}, errors.New("wrong output size")
|
||||
}
|
||||
|
||||
var result IDCommitment
|
||||
copy(result[:], b)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetMerkleProof returns the Merkle proof for the element at the specified index
|
||||
// The output should be parsed as: num_elements<8>|path_elements<var1>|num_indexes<8>|path_indexes<var2>
|
||||
// where num_elements indicate var1 array size and num_indexes indicate var2 array size.
|
||||
// Both num_elements and num_indexes shall be equal and match the tree depth.
|
||||
// A tree with depth 20 has 676 bytes = 8 + 32 * 20 + 8 + 20 * 1
|
||||
// Proof elements are stored as little endian
|
||||
func (r *RLN) GetMerkleProof(index MembershipIndex) (MerkleProof, error) {
|
||||
proofBytes, err := r.w.GetMerkleProof(index)
|
||||
if err != nil {
|
||||
return MerkleProof{}, err
|
||||
}
|
||||
|
||||
var result MerkleProof
|
||||
err = result.deserialize(proofBytes)
|
||||
if err != nil {
|
||||
return MerkleProof{}, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// AddAll adds members to the Merkle tree
|
||||
func (r *RLN) AddAll(list []IDCommitment) error {
|
||||
func (r *RLN) AddAll(list []IdentityCredential) error {
|
||||
for _, member := range list {
|
||||
if err := r.InsertMember(member); err != nil {
|
||||
if err := r.InsertMember(member.IDCommitment, member.UserMessageLimit); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -314,11 +550,8 @@ func CalcMerkleRoot(list []IDCommitment) (MerkleNode, error) {
|
||||
return MerkleNode{}, err
|
||||
}
|
||||
|
||||
// create a Merkle tree
|
||||
for _, c := range list {
|
||||
if err := rln.InsertMember(c); err != nil {
|
||||
return MerkleNode{}, err
|
||||
}
|
||||
if err := rln.InsertMembers(0, list); err != nil {
|
||||
return MerkleNode{}, err
|
||||
}
|
||||
|
||||
return rln.GetMerkleRoot()
|
||||
@ -327,14 +560,14 @@ func CalcMerkleRoot(list []IDCommitment) (MerkleNode, error) {
|
||||
// CreateMembershipList produces a list of membership key pairs and also returns the root of a Merkle tree constructed
|
||||
// out of the identity commitment keys of the generated list. The output of this function is used to initialize a static
|
||||
// group keys (to test waku-rln-relay in the off-chain mode)
|
||||
func CreateMembershipList(n int) ([]MembershipKeyPair, MerkleNode, error) {
|
||||
func CreateMembershipList(n int) ([]IdentityCredential, MerkleNode, error) {
|
||||
// initialize a Merkle tree
|
||||
rln, err := NewRLN()
|
||||
if err != nil {
|
||||
return nil, MerkleNode{}, err
|
||||
}
|
||||
|
||||
var output []MembershipKeyPair
|
||||
var output []IdentityCredential
|
||||
for i := 0; i < n; i++ {
|
||||
// generate a keypair
|
||||
keypair, err := rln.MembershipKeyGen()
|
||||
@ -345,7 +578,7 @@ func CreateMembershipList(n int) ([]MembershipKeyPair, MerkleNode, error) {
|
||||
output = append(output, *keypair)
|
||||
|
||||
// insert the key to the Merkle tree
|
||||
if err := rln.InsertMember(keypair.IDCommitment); err != nil {
|
||||
if err := rln.InsertMember(keypair.IDCommitment, keypair.UserMessageLimit); err != nil {
|
||||
return nil, MerkleNode{}, err
|
||||
}
|
||||
}
|
||||
@ -357,3 +590,42 @@ func CreateMembershipList(n int) ([]MembershipKeyPair, MerkleNode, error) {
|
||||
|
||||
return output, root, nil
|
||||
}
|
||||
|
||||
// SetMetadata stores serialized data
|
||||
func (r *RLN) SetMetadata(metadata []byte) error {
|
||||
success := r.w.SetMetadata(metadata)
|
||||
if !success {
|
||||
return errors.New("could not set metadata")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMetadata returns the stored serialized metadata
|
||||
func (r *RLN) GetMetadata() ([]byte, error) {
|
||||
return r.w.GetMetadata()
|
||||
}
|
||||
|
||||
// AtomicOperation can be used to insert and remove elements into the merkle tree
|
||||
func (r *RLN) AtomicOperation(index MembershipIndex, idCommsToInsert []IDCommitment, indicesToRemove []MembershipIndex) error {
|
||||
idCommBytes := serializeCommitments(idCommsToInsert)
|
||||
indicesBytes := serializeIndices(indicesToRemove)
|
||||
execSuccess := r.w.AtomicOperation(index, idCommBytes, indicesBytes)
|
||||
if !execSuccess {
|
||||
return errors.New("could not execute atomic_operation")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flush
|
||||
func (r *RLN) Flush() error {
|
||||
success := r.w.Flush()
|
||||
if !success {
|
||||
return errors.New("cannot flush db")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LeavesSet indicates how many elements have been inserted in the merkle tree
|
||||
func (r *RLN) LeavesSet() uint {
|
||||
return r.w.LeavesSet()
|
||||
}
|
||||
|
||||
472
rln/rln_test.go
472
rln/rln_test.go
@ -17,18 +17,41 @@ type RLNSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestNew() {
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
root1, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
s.Len(root1, 32)
|
||||
|
||||
rln2, err := NewWithConfig(DefaultTreeDepth, nil)
|
||||
s.NoError(err)
|
||||
|
||||
root2, err := rln2.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
s.Len(root2, 32)
|
||||
s.Equal(root1, root2)
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestMembershipKeyGen() {
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
key, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
s.Len(key.IDKey, 32)
|
||||
s.Len(key.IDSecretHash, 32)
|
||||
s.Len(key.IDCommitment, 32)
|
||||
s.NotEmpty(key.IDKey)
|
||||
s.Len(key.IDTrapdoor, 32)
|
||||
s.Len(key.IDNullifier, 32)
|
||||
s.NotEmpty(key.IDSecretHash)
|
||||
s.NotEmpty(key.IDCommitment)
|
||||
s.NotEmpty(key.IDTrapdoor)
|
||||
s.NotEmpty(key.IDNullifier)
|
||||
s.False(bytes.Equal(key.IDCommitment[:], make([]byte, 32)))
|
||||
s.False(bytes.Equal(key.IDKey[:], make([]byte, 32)))
|
||||
s.False(bytes.Equal(key.IDSecretHash[:], make([]byte, 32)))
|
||||
s.False(bytes.Equal(key.IDTrapdoor[:], make([]byte, 32)))
|
||||
s.False(bytes.Equal(key.IDNullifier[:], make([]byte, 32)))
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestGetMerkleRoot() {
|
||||
@ -53,14 +76,69 @@ func (s *RLNSuite) TestInsertMember() {
|
||||
keypair, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(keypair.IDCommitment)
|
||||
err = rln.InsertMember(keypair.IDCommitment, keypair.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestInsertRawLeaf() {
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
// Generate a membership
|
||||
memKeys, err := rln.MembershipKeyGen(10)
|
||||
s.NoError(err)
|
||||
|
||||
// Calculate the leaf ourselves
|
||||
userMessageLimitBytes := SerializeUint32(memKeys.UserMessageLimit)
|
||||
hashedLeaf, err := rln.Poseidon(memKeys.IDCommitment[:], userMessageLimitBytes[:])
|
||||
s.NoError(err)
|
||||
|
||||
// Insert the leaf as it is
|
||||
err = rln.InsertRawLeaf(hashedLeaf)
|
||||
s.NoError(err)
|
||||
|
||||
// Get it from the tree
|
||||
retrievedLeaf, err := rln.GetLeaf(uint(i))
|
||||
s.NoError(err)
|
||||
|
||||
// Check the retrieved matches the one we added
|
||||
s.Equal(hashedLeaf, retrievedLeaf)
|
||||
|
||||
// Check tree size matches
|
||||
numLeaves := rln.LeavesSet()
|
||||
s.Equal(uint(i+1), numLeaves)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestInsertMembers() {
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
var commitments []IDCommitment
|
||||
for i := 0; i < 10; i++ {
|
||||
keypair, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
commitments = append(commitments, keypair.IDCommitment)
|
||||
}
|
||||
|
||||
err = rln.InsertMembers(0, commitments)
|
||||
s.NoError(err)
|
||||
|
||||
numLeaves := rln.LeavesSet()
|
||||
s.Equal(uint(10), numLeaves)
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestRemoveMember() {
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
keypair, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(keypair.IDCommitment, keypair.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.DeleteMember(MembershipIndex(0))
|
||||
s.NoError(err)
|
||||
}
|
||||
@ -76,7 +154,7 @@ func (s *RLNSuite) TestMerkleTreeConsistenceBetweenDeletionAndInsertion() {
|
||||
keypair, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(keypair.IDCommitment)
|
||||
err = rln.InsertMember(keypair.IDCommitment, keypair.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
|
||||
// read the Merkle Tree root after insertion
|
||||
@ -108,13 +186,27 @@ func (s *RLNSuite) TestHash() {
|
||||
|
||||
// prepare the input
|
||||
msg := []byte("Hello")
|
||||
hash, err := rln.Hash(msg)
|
||||
hash, err := rln.Sha256(msg)
|
||||
s.NoError(err)
|
||||
|
||||
expectedHash, _ := hex.DecodeString("4c6ea217404bd5f10e243bac29dc4f1ec36bf4a41caba7b4c8075c54abb3321e")
|
||||
s.Equal(expectedHash, hash[:])
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestPoseidon() {
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
// prepare the input
|
||||
msg1, _ := hex.DecodeString("126f4c026cd731979365f79bd345a46d673c5a3f6f588bdc718e6356d02b6fdc")
|
||||
msg2, _ := hex.DecodeString("1f0e5db2b69d599166ab16219a97b82b662085c93220382b39f9f911d3b943b1")
|
||||
hash, err := rln.Poseidon(msg1, msg2)
|
||||
s.NoError(err)
|
||||
|
||||
expectedHash, _ := hex.DecodeString("83e4a6b2dea68aad26f04f32f37ac1e018188a0056b158b2aa026d34266d1f30")
|
||||
s.Equal(expectedHash, hash[:])
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestCreateListMembershipKeysAndCreateMerkleTreeFromList() {
|
||||
groupSize := 100
|
||||
list, root, err := CreateMembershipList(groupSize)
|
||||
@ -127,7 +219,7 @@ func (s *RLNSuite) TestCheckCorrectness() {
|
||||
groupKeys := STATIC_GROUP_KEYS
|
||||
|
||||
// create a set of MembershipKeyPair objects from groupKeys
|
||||
groupKeyPairs, err := toMembershipKeyPairs(groupKeys)
|
||||
groupKeyPairs, err := ToIdentityCredentials(groupKeys)
|
||||
s.NoError(err)
|
||||
|
||||
// extract the id commitments
|
||||
@ -146,28 +238,63 @@ func (s *RLNSuite) TestCheckCorrectness() {
|
||||
s.Equal(expectedRoot, root[:])
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestGetLeaf() {
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
amountLeafs := int(31)
|
||||
|
||||
for i := 0; i < amountLeafs; i++ {
|
||||
// allowed messages per epoch of the membership
|
||||
// using different values between 1 and 7
|
||||
userMessageLimit := uint32(amountLeafs%7 + 1)
|
||||
|
||||
// generate membership
|
||||
memKeys, err := rln.MembershipKeyGen(userMessageLimit)
|
||||
s.NoError(err)
|
||||
|
||||
// insert membership
|
||||
err = rln.InsertMember(memKeys.IDCommitment, memKeys.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
|
||||
// retrieve the leaf
|
||||
retrievedLeaf, err := rln.GetLeaf(uint(i))
|
||||
s.NoError(err)
|
||||
|
||||
// calculate the leaf we would expect
|
||||
userMessageLimitBytes := SerializeUint32(userMessageLimit)
|
||||
hashedLeaf, err := rln.Poseidon(memKeys.IDCommitment[:], userMessageLimitBytes[:])
|
||||
s.NoError(err)
|
||||
|
||||
// assert it matches
|
||||
s.Equal(hashedLeaf, retrievedLeaf)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestValidProof() {
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
memKeys, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
// allowed messages per epoch of the membership
|
||||
userMessageLimit := uint32(10)
|
||||
|
||||
//peer's index in the Merkle Tree
|
||||
index := 5
|
||||
index := uint(5)
|
||||
|
||||
memKeys, err := rln.MembershipKeyGen(userMessageLimit)
|
||||
s.NoError(err)
|
||||
|
||||
// Create a Merkle tree with random members
|
||||
for i := 0; i < 10; i++ {
|
||||
for i := uint(0); i < 10; i++ {
|
||||
if i == index {
|
||||
// insert the current peer's pk
|
||||
err = rln.InsertMember(memKeys.IDCommitment)
|
||||
err = rln.InsertMember(memKeys.IDCommitment, memKeys.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
} else {
|
||||
// create a new key pair
|
||||
memberKeys, err := rln.MembershipKeyGen()
|
||||
memberKeys, err := rln.MembershipKeyGen(userMessageLimit)
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(memberKeys.IDCommitment)
|
||||
err = rln.InsertMember(memberKeys.IDCommitment, memberKeys.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
}
|
||||
}
|
||||
@ -176,24 +303,75 @@ func (s *RLNSuite) TestValidProof() {
|
||||
msg := []byte("Hello")
|
||||
|
||||
// prepare the epoch
|
||||
var epoch Epoch
|
||||
var epoch Epoch = SerializeUint32(1000)
|
||||
|
||||
// generate proof
|
||||
proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(index), epoch)
|
||||
// generate multiple valid proofs for the same epoch
|
||||
for i := uint32(0); i < userMessageLimit; i++ {
|
||||
// message sequence within the epoch
|
||||
messageId := uint32(i)
|
||||
|
||||
// generate proof
|
||||
proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(index), epoch, messageId)
|
||||
s.NoError(err)
|
||||
|
||||
// verify the proof
|
||||
verified, err := rln.Verify(msg, *proofRes)
|
||||
s.NoError(err)
|
||||
s.True(verified)
|
||||
|
||||
// verify with roots
|
||||
root, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
|
||||
verified, err = rln.Verify(msg, *proofRes, root)
|
||||
s.NoError(err)
|
||||
s.True(verified)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestProofBeyondLimit() {
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
// verify the proof
|
||||
verified, err := rln.Verify(msg, *proofRes)
|
||||
s.NoError(err)
|
||||
s.True(verified)
|
||||
// allowed messages per epoch of the membership
|
||||
userMessageLimit := uint32(10)
|
||||
|
||||
// verify with roots
|
||||
root, err := rln.GetMerkleRoot()
|
||||
//peer's index in the Merkle Tree
|
||||
index := uint(5)
|
||||
|
||||
memKeys, err := rln.MembershipKeyGen(userMessageLimit)
|
||||
s.NoError(err)
|
||||
|
||||
verified, err = rln.VerifyWithRoots(msg, *proofRes, [][32]byte{root})
|
||||
s.NoError(err)
|
||||
s.True(verified)
|
||||
// Create a Merkle tree with random members
|
||||
for i := uint(0); i < 10; i++ {
|
||||
if i == index {
|
||||
err = rln.InsertMember(memKeys.IDCommitment, memKeys.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
} else {
|
||||
// create a new key pair
|
||||
memberKeys, err := rln.MembershipKeyGen(userMessageLimit)
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(memberKeys.IDCommitment, memberKeys.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// prepare the message
|
||||
msg := []byte("Hello")
|
||||
|
||||
// prepare the epoch
|
||||
var epoch Epoch = SerializeUint32(876543456)
|
||||
|
||||
// TODO;:
|
||||
for i := uint32(userMessageLimit + 1); i < (userMessageLimit + 10); i++ {
|
||||
// message sequence within the epoch
|
||||
messageId := uint32(i)
|
||||
|
||||
// generate proof TODO:Errors!
|
||||
_, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(index), epoch, messageId)
|
||||
s.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestInvalidProof() {
|
||||
@ -210,18 +388,21 @@ func (s *RLNSuite) TestInvalidProof() {
|
||||
for i := 0; i < 10; i++ {
|
||||
if i == index {
|
||||
// insert the current peer's pk
|
||||
err := rln.InsertMember(memKeys.IDCommitment)
|
||||
err := rln.InsertMember(memKeys.IDCommitment, memKeys.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
} else {
|
||||
// create a new key pair
|
||||
memberKeys, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(memberKeys.IDCommitment)
|
||||
err = rln.InsertMember(memberKeys.IDCommitment, memberKeys.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
root, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
|
||||
// prepare the message
|
||||
msg := []byte("Hello")
|
||||
|
||||
@ -230,16 +411,245 @@ func (s *RLNSuite) TestInvalidProof() {
|
||||
|
||||
badIndex := 4
|
||||
|
||||
// message sequence within the epoch
|
||||
messageId := uint32(1)
|
||||
|
||||
// generate proof
|
||||
proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(badIndex), epoch)
|
||||
proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(badIndex), epoch, messageId)
|
||||
s.NoError(err)
|
||||
|
||||
// verify the proof (should not be verified)
|
||||
verified, err := rln.Verify(msg, *proofRes)
|
||||
verified, err := rln.Verify(msg, *proofRes, root)
|
||||
s.NoError(err)
|
||||
s.False(verified)
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestGetMerkleProof() {
|
||||
for _, treeDepth := range []TreeDepth{TreeDepth15, TreeDepth19, TreeDepth20} {
|
||||
treeDepthInt := int(treeDepth)
|
||||
|
||||
rln, err := NewWithConfig(treeDepth, nil)
|
||||
s.NoError(err)
|
||||
|
||||
leaf0 := [32]byte{0x00}
|
||||
leaf1 := [32]byte{0x01}
|
||||
leaf5 := [32]byte{0x05}
|
||||
|
||||
rln.InsertMemberAt(0, leaf0)
|
||||
rln.InsertMemberAt(1, leaf1)
|
||||
rln.InsertMemberAt(5, leaf5)
|
||||
|
||||
b1, err := rln.GetMerkleProof(0)
|
||||
s.NoError(err)
|
||||
s.Equal(treeDepthInt, len(b1.PathElements))
|
||||
s.Equal(treeDepthInt, len(b1.PathIndexes))
|
||||
// First path is right leaf [0, 1]
|
||||
s.EqualValues(leaf1, b1.PathElements[0])
|
||||
|
||||
b2, err := rln.GetMerkleProof(4)
|
||||
s.NoError(err)
|
||||
s.Equal(treeDepthInt, len(b2.PathElements))
|
||||
s.Equal(treeDepthInt, len(b2.PathIndexes))
|
||||
// First path is right leaf [4, 5]
|
||||
s.EqualValues(leaf5, b2.PathElements[0])
|
||||
|
||||
b3, err := rln.GetMerkleProof(10)
|
||||
s.NoError(err)
|
||||
s.Equal(treeDepthInt, len(b3.PathElements))
|
||||
s.Equal(treeDepthInt, len(b3.PathIndexes))
|
||||
// First path is right leaf. But its empty
|
||||
s.EqualValues([32]byte{0x00}, b3.PathElements[0])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestGenerateRLNProofWithWitness_VerifiesOK() {
|
||||
treeSize := 20
|
||||
userMessageLimit := uint32(100)
|
||||
message := []byte("some rln protected message")
|
||||
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
treeElements := make([]IdentityCredential, 0)
|
||||
|
||||
// Create a Merkle tree with random members
|
||||
for i := 0; i < treeSize; i++ {
|
||||
memberKeys, err := rln.MembershipKeyGen(userMessageLimit)
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(memberKeys.IDCommitment, memberKeys.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
treeElements = append(treeElements, *memberKeys)
|
||||
}
|
||||
|
||||
// For different leafs (with a custom witness)
|
||||
for _, memberIndex := range []uint{0, 10, 13} {
|
||||
root, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
|
||||
// We provide out custom witness
|
||||
merkleProof, err := rln.GetMerkleProof(memberIndex)
|
||||
s.NoError(err)
|
||||
|
||||
// For different epochs
|
||||
for _, epoch := range []Epoch{ToEpoch(1), ToEpoch(9998765)} {
|
||||
|
||||
// For some possible message ids
|
||||
for _, messageId := range []uint32{0, 50, 99} {
|
||||
|
||||
rlnWitness, err := rln.CreateWitness(
|
||||
treeElements[memberIndex].IDSecretHash,
|
||||
userMessageLimit,
|
||||
messageId,
|
||||
message,
|
||||
epoch,
|
||||
merkleProof)
|
||||
s.NoError(err)
|
||||
|
||||
// Generate a proof with our custom witness (Merkle Path of the memberIndex)
|
||||
proofRes1, err := rln.GenerateRLNProofWithWitness(rlnWitness)
|
||||
s.NoError(err)
|
||||
verified1, err := rln.Verify(message, *proofRes1, root)
|
||||
s.NoError(err)
|
||||
s.True(verified1)
|
||||
|
||||
// Generate a proof without our custom witness, to ensure they match
|
||||
proofRes2, err := rln.GenerateProof(message, treeElements[memberIndex], MembershipIndex(memberIndex), epoch, messageId)
|
||||
s.NoError(err)
|
||||
|
||||
// Ensure we have the same root
|
||||
s.Equal(root, proofRes1.MerkleRoot)
|
||||
|
||||
// Proof generate with custom witness match the proof generate with the witness
|
||||
// from zerokit. Proof itself is not asserted, can be different.
|
||||
s.Equal(proofRes1.MerkleRoot, proofRes2.MerkleRoot)
|
||||
s.Equal(proofRes1.ExternalNullifier, proofRes2.ExternalNullifier)
|
||||
s.Equal(proofRes1.ShareX, proofRes2.ShareX)
|
||||
s.Equal(proofRes1.ShareY, proofRes2.ShareY)
|
||||
s.Equal(proofRes1.Nullifier, proofRes2.Nullifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestGenerateRLNProofWithWitness_VerifiesNOK() {
|
||||
|
||||
treeSize := 20
|
||||
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
treeElements := make([]IdentityCredential, 0)
|
||||
|
||||
// Create a Merkle tree with random members
|
||||
for i := 0; i < treeSize; i++ {
|
||||
memberKeys, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(memberKeys.IDCommitment, memberKeys.UserMessageLimit)
|
||||
s.NoError(err)
|
||||
treeElements = append(treeElements, *memberKeys)
|
||||
}
|
||||
|
||||
// We generate proofs with a custom witness aquired outside zerokit for diferent indexes
|
||||
for _, memberIndex := range []uint{0, 10, 13, 15} {
|
||||
root, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
|
||||
// We provide out custom witness
|
||||
merkleProof, err := rln.GetMerkleProof(memberIndex)
|
||||
s.NoError(err)
|
||||
|
||||
message := []byte("some rln protected message")
|
||||
epoch := ToEpoch(1000)
|
||||
|
||||
userMessageLimit := uint32(10)
|
||||
messageId := uint32(1)
|
||||
|
||||
rlnWitness1, err := rln.CreateWitness(
|
||||
treeElements[memberIndex].IDSecretHash,
|
||||
userMessageLimit,
|
||||
messageId,
|
||||
message,
|
||||
epoch,
|
||||
merkleProof)
|
||||
s.NoError(err)
|
||||
|
||||
// Generate a proof with our custom witness (Merkle Path of the memberIndex)
|
||||
proofRes1, err := rln.GenerateRLNProofWithWitness(rlnWitness1)
|
||||
s.NoError(err)
|
||||
|
||||
// 1) Message changed, does not verify
|
||||
verified1, err := rln.Verify([]byte("different message"), *proofRes1, root)
|
||||
s.NoError(err)
|
||||
s.False(verified1)
|
||||
|
||||
// 2) Different nullifier (epoch or rln id), does not verify
|
||||
proofRes1.ExternalNullifier = [32]byte{0x11}
|
||||
verified2, err := rln.Verify(message, *proofRes1, root)
|
||||
s.NoError(err)
|
||||
s.False(verified2)
|
||||
|
||||
// 3) Merkle proof in provided witness is wrong, does not verify
|
||||
merkleProof.PathElements[0] = [32]byte{0x11}
|
||||
|
||||
rlnWitness2, err := rln.CreateWitness(
|
||||
treeElements[memberIndex].IDSecretHash,
|
||||
userMessageLimit,
|
||||
messageId,
|
||||
message,
|
||||
epoch,
|
||||
merkleProof)
|
||||
s.NoError(err)
|
||||
|
||||
proofRes3, err := rln.GenerateRLNProofWithWitness(rlnWitness2)
|
||||
s.NoError(err)
|
||||
|
||||
verified3, err := rln.Verify(message, *proofRes3, root)
|
||||
s.NoError(err)
|
||||
s.False(verified3)
|
||||
|
||||
// 4) Membership does not match the index (and not part of tree), does not verify
|
||||
merkleProof4, err := rln.GetMerkleProof(memberIndex)
|
||||
s.NoError(err)
|
||||
|
||||
// Membership that does not match the index
|
||||
memberKeys, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
// Proof proves memberIndex inclusion, but provided membership is different
|
||||
rlnWitness4, err := rln.CreateWitness(
|
||||
memberKeys.IDSecretHash,
|
||||
userMessageLimit,
|
||||
messageId,
|
||||
[]byte("some rln protected message"),
|
||||
ToEpoch(999),
|
||||
merkleProof4)
|
||||
s.NoError(err)
|
||||
|
||||
proofRes4, err := rln.GenerateRLNProofWithWitness(rlnWitness4)
|
||||
s.NoError(err)
|
||||
|
||||
verified4, err := rln.Verify(message, *proofRes4, root)
|
||||
s.NoError(err)
|
||||
s.False(verified4)
|
||||
|
||||
// 5) Message id goes beyond the userMessageLimit, does not generate
|
||||
wrongMessageId := uint32(1000)
|
||||
rlnWitness5, err := rln.CreateWitness(
|
||||
treeElements[memberIndex].IDSecretHash,
|
||||
userMessageLimit,
|
||||
wrongMessageId,
|
||||
message,
|
||||
epoch,
|
||||
merkleProof)
|
||||
s.NoError(err)
|
||||
|
||||
_, err = rln.GenerateRLNProofWithWitness(rlnWitness5)
|
||||
s.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestEpochConsistency() {
|
||||
// check edge cases
|
||||
var epoch uint64 = math.MaxUint64
|
||||
|
||||
136
rln/serialize.go
136
rln/serialize.go
@ -1,20 +1,37 @@
|
||||
package rln
|
||||
|
||||
import "encoding/binary"
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// serialize converts a RateLimitProof and the data to a byte seq
|
||||
// this conversion is used in the proofGen function
|
||||
// the serialization is done as instructed in https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L146
|
||||
// [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||
func serialize(idKey IDKey, memIndex MembershipIndex, epoch Epoch, msg []byte) []byte {
|
||||
// format taken from: https://github.com/vacp2p/zerokit/blob/v0.5.0/rln/src/public.rs#L747
|
||||
// [identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
|
||||
func serialize(
|
||||
idKey IDSecretHash,
|
||||
memIndex MembershipIndex,
|
||||
userMessageLimit uint32,
|
||||
messageId uint32,
|
||||
externalNullifier [32]byte,
|
||||
msg []byte) []byte {
|
||||
|
||||
memIndexBytes := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(memIndexBytes, uint64(memIndex))
|
||||
|
||||
lenPrefMsg := appendLength(msg)
|
||||
|
||||
var userMessageLimitByte [32]byte
|
||||
var messageIdByte [32]byte
|
||||
binary.LittleEndian.PutUint32(userMessageLimitByte[0:], userMessageLimit)
|
||||
binary.LittleEndian.PutUint32(messageIdByte[0:], messageId)
|
||||
|
||||
output := append(idKey[:], memIndexBytes...)
|
||||
output = append(output, epoch[:]...)
|
||||
output = append(output, userMessageLimitByte[:]...)
|
||||
output = append(output, messageIdByte[:]...)
|
||||
output = append(output, externalNullifier[:]...)
|
||||
output = append(output, lenPrefMsg...)
|
||||
|
||||
return output
|
||||
@ -23,16 +40,111 @@ func serialize(idKey IDKey, memIndex MembershipIndex, epoch Epoch, msg []byte) [
|
||||
// serialize converts a RateLimitProof and data to a byte seq
|
||||
// this conversion is used in the proof verification proc
|
||||
// the order of serialization is based on https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L205
|
||||
// [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal<var> ]
|
||||
func (r RateLimitProof) serialize(data []byte) []byte {
|
||||
// [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
func (r RateLimitProof) serializeWithData(data []byte) []byte {
|
||||
lenPrefMsg := appendLength(data)
|
||||
proofBytes := r.serialize()
|
||||
proofBytes = append(proofBytes, lenPrefMsg...)
|
||||
return proofBytes
|
||||
}
|
||||
|
||||
// serialize converts a RateLimitProof to a byte seq
|
||||
// [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32>]
|
||||
func (r RateLimitProof) serialize() []byte {
|
||||
proofBytes := append(r.Proof[:], r.MerkleRoot[:]...)
|
||||
proofBytes = append(proofBytes, r.Epoch[:]...)
|
||||
proofBytes = append(proofBytes, r.ExternalNullifier[:]...)
|
||||
proofBytes = append(proofBytes, r.ShareX[:]...)
|
||||
proofBytes = append(proofBytes, r.ShareY[:]...)
|
||||
proofBytes = append(proofBytes, r.Nullifier[:]...)
|
||||
proofBytes = append(proofBytes, r.RLNIdentifier[:]...)
|
||||
proofBytes = append(proofBytes, lenPrefMsg...)
|
||||
|
||||
return proofBytes
|
||||
}
|
||||
|
||||
// serialize converts a RLNWitnessInput to a byte seq
|
||||
// [ id_secret_hash<32> | user_message_limit<32> | message_id<32> | num_elements<8> | path_elements<var1> | num_indexes<8> | path_indexes<var2> | external_nullifier<32> ]
|
||||
func (r *RLNWitnessInput) serialize() []byte {
|
||||
output := make([]byte, 0)
|
||||
|
||||
var userMessageLimitByte [32]byte
|
||||
var messageIdByte [32]byte
|
||||
binary.LittleEndian.PutUint32(userMessageLimitByte[0:], r.UserMessageLimit)
|
||||
binary.LittleEndian.PutUint32(messageIdByte[0:], r.MessageId)
|
||||
|
||||
output = append(output, r.IDSecretHash[:]...)
|
||||
output = append(output, userMessageLimitByte[:]...)
|
||||
output = append(output, messageIdByte[:]...)
|
||||
output = append(output, r.MerkleProof.serialize()...)
|
||||
output = append(output, r.X[:]...)
|
||||
output = append(output, r.ExternalNullifier[:]...)
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func (r *RLNWitnessInput) deserialize(b []byte) error {
|
||||
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (r *MerkleProof) serialize() []byte {
|
||||
output := make([]byte, 0)
|
||||
|
||||
output = append(output, appendLength32(Flatten(r.PathElements))...)
|
||||
output = append(output, appendLength(r.PathIndexes)...)
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func (r *MerkleProof) deserialize(b []byte) error {
|
||||
|
||||
// Check if we can read the first byte
|
||||
if len(b) < 8 {
|
||||
return errors.New(fmt.Sprintf("wrong input size: %d", len(b)))
|
||||
}
|
||||
|
||||
var numElements big.Int
|
||||
var numIndexes big.Int
|
||||
|
||||
offset := 0
|
||||
|
||||
// Get amounf of elements in the proof
|
||||
numElements.SetBytes(revert(b[offset : offset+8]))
|
||||
offset += 8
|
||||
|
||||
// With numElements we can determine the expected length of the proof.
|
||||
expectedLen := 8 + int(32*numElements.Uint64()) + 8 + int(numElements.Uint64())
|
||||
if len(b) != expectedLen {
|
||||
return errors.New(fmt.Sprintf("wrong input size expected: %d, current: %d",
|
||||
expectedLen,
|
||||
len(b)))
|
||||
}
|
||||
|
||||
r.PathElements = make([]MerkleNode, numElements.Uint64())
|
||||
|
||||
for i := uint64(0); i < numElements.Uint64(); i++ {
|
||||
copy(r.PathElements[i][:], b[offset:offset+32])
|
||||
offset += 32
|
||||
}
|
||||
|
||||
// Get amount of indexes in the path
|
||||
numIndexes.SetBytes(revert(b[offset : offset+8]))
|
||||
offset += 8
|
||||
|
||||
// Both numElements and numIndexes shall be equal and match the tree depth.
|
||||
if numIndexes.Uint64() != numElements.Uint64() {
|
||||
return errors.New(fmt.Sprintf("amount of values in path and indexes do not match: %s vs %s",
|
||||
numElements.String(), numIndexes.String()))
|
||||
}
|
||||
|
||||
r.PathIndexes = make([]uint8, numIndexes.Uint64())
|
||||
|
||||
for i := uint64(0); i < numIndexes.Uint64(); i++ {
|
||||
r.PathIndexes[i] = b[offset]
|
||||
offset += 1
|
||||
}
|
||||
|
||||
if offset != len(b) {
|
||||
return errors.New(
|
||||
fmt.Sprintf("error parsing proof read: %d, length; %d", offset, len(b)))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
65
rln/serialize_test.go
Normal file
65
rln/serialize_test.go
Normal file
@ -0,0 +1,65 @@
|
||||
package rln
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func random32() [32]byte {
|
||||
var randomBytes [32]byte
|
||||
_, _ = rand.Read(randomBytes[:])
|
||||
return randomBytes
|
||||
}
|
||||
|
||||
func TestMerkleProofSerDe(t *testing.T) {
|
||||
|
||||
for _, testSize := range []int{0, 1, 8, 16, 20} {
|
||||
mProof := MerkleProof{
|
||||
PathElements: []MerkleNode{},
|
||||
PathIndexes: []uint8{},
|
||||
}
|
||||
|
||||
for i := 0; i < testSize; i++ {
|
||||
mProof.PathElements = append(mProof.PathElements, random32())
|
||||
mProof.PathIndexes = append(mProof.PathIndexes, uint8(i%2))
|
||||
}
|
||||
|
||||
// Check the size is the expected
|
||||
ser := mProof.serialize()
|
||||
require.Equal(t, 8+testSize*32+testSize+8, len(ser))
|
||||
|
||||
// Deserialize and check its matches the original
|
||||
desProof := MerkleProof{}
|
||||
err := desProof.deserialize(ser)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, mProof, desProof)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRLNWitnessInputSerDe(t *testing.T) {
|
||||
depth := 20
|
||||
|
||||
mProof := MerkleProof{
|
||||
PathElements: []MerkleNode{},
|
||||
PathIndexes: []uint8{},
|
||||
}
|
||||
|
||||
for i := 0; i < depth; i++ {
|
||||
mProof.PathElements = append(mProof.PathElements, random32())
|
||||
mProof.PathIndexes = append(mProof.PathIndexes, uint8(i%2))
|
||||
}
|
||||
|
||||
witness := RLNWitnessInput{
|
||||
IDSecretHash: random32(),
|
||||
UserMessageLimit: 8,
|
||||
MessageId: 7,
|
||||
MerkleProof: mProof,
|
||||
X: [32]byte{0x00},
|
||||
ExternalNullifier: [32]byte{0x00},
|
||||
}
|
||||
|
||||
ser := witness.serialize()
|
||||
require.Equal(t, 32+32+32+8+depth*32+depth+8+32+32, len(ser))
|
||||
}
|
||||
247
rln/types.go
247
rln/types.go
File diff suppressed because one or more lines are too long
164
rln/utils.go
164
rln/utils.go
@ -1,26 +1,53 @@
|
||||
package rln
|
||||
|
||||
import "encoding/hex"
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"hash"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
func toMembershipKeyPairs(groupKeys [][]string) ([]MembershipKeyPair, error) {
|
||||
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
func ToIdentityCredentials(groupKeys [][]string) ([]IdentityCredential, error) {
|
||||
// groupKeys is sequence of membership key tuples in the form of (identity key, identity commitment) all in the hexadecimal format
|
||||
// the toMembershipKeyPairs proc populates a sequence of MembershipKeyPairs using the supplied groupKeys
|
||||
// the toIdentityCredentials proc populates a sequence of IdentityCredentials using the supplied groupKeys
|
||||
// Returns an error if the conversion fails
|
||||
|
||||
groupKeyPairs := []MembershipKeyPair{}
|
||||
for _, pair := range groupKeys {
|
||||
idKey, err := hex.DecodeString(pair[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idCommitment, err := hex.DecodeString(pair[1])
|
||||
var groupIdCredentials []IdentityCredential
|
||||
|
||||
for _, gk := range groupKeys {
|
||||
idTrapdoor, err := ToBytes32LE(gk[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groupKeyPairs = append(groupKeyPairs, MembershipKeyPair{IDKey: IDKey(Bytes32(idKey)), IDCommitment: IDCommitment(Bytes32(idCommitment))})
|
||||
idNullifier, err := ToBytes32LE(gk[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idSecretHash, err := ToBytes32LE(gk[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idCommitment, err := ToBytes32LE(gk[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groupIdCredentials = append(groupIdCredentials, IdentityCredential{
|
||||
IDTrapdoor: idTrapdoor,
|
||||
IDNullifier: idNullifier,
|
||||
IDSecretHash: idSecretHash,
|
||||
IDCommitment: idCommitment,
|
||||
})
|
||||
}
|
||||
|
||||
return groupKeyPairs, nil
|
||||
return groupIdCredentials, nil
|
||||
}
|
||||
|
||||
func Bytes32(b []byte) [32]byte {
|
||||
@ -34,3 +61,116 @@ func Bytes128(b []byte) [128]byte {
|
||||
copy(result[128-len(b):], b)
|
||||
return result
|
||||
}
|
||||
|
||||
func Flatten(b [][32]byte) []byte {
|
||||
result := make([]byte, len(b)*32)
|
||||
for i, v := range b {
|
||||
copy(result[i*32:(i+1)*32], v[:])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func ToBytes32LE(hexStr string) ([32]byte, error) {
|
||||
|
||||
b, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
|
||||
bLen := len(b)
|
||||
for i := 0; i < bLen/2; i++ {
|
||||
b[i], b[bLen-i-1] = b[bLen-i-1], b[i]
|
||||
}
|
||||
|
||||
return Bytes32(b), nil
|
||||
}
|
||||
|
||||
func revert(b []byte) []byte {
|
||||
bLen := len(b)
|
||||
for i := 0; i < bLen/2; i++ {
|
||||
b[i], b[bLen-i-1] = b[bLen-i-1], b[i]
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// BigIntToBytes32 takes a *big.Int (which uses big endian) and converts it into a little endian 32 byte array
|
||||
// Notice that is the *big.Int value contains an integer <= 2^248 - 1 (a 7 bytes value with all bits on), it will right-pad the result with 0s until
|
||||
// the result has 32 bytes, i.e.:
|
||||
// for a some bigInt whose `Bytes()` are {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}, using this function will return
|
||||
// {0xEF, 0xCD, 0xAB, 0x90, 0x78, 0x56, 0x34, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
|
||||
func BigIntToBytes32(value *big.Int) [32]byte {
|
||||
b := revert(value.Bytes())
|
||||
tmp := make([]byte, 32)
|
||||
copy(tmp[0:len(b)], b)
|
||||
return Bytes32(tmp)
|
||||
}
|
||||
|
||||
// Bytes32ToBigInt takes a little endian 32 byte array and returns a *big.Int (which uses big endian)
|
||||
func Bytes32ToBigInt(value [32]byte) *big.Int {
|
||||
b := revert(value[:])
|
||||
result := new(big.Int)
|
||||
result.SetBytes(b)
|
||||
return result
|
||||
}
|
||||
|
||||
// Keccak functions take from here. To avoid unnecessary dependency to go-ethereum.
|
||||
// https://github.com/ethereum/go-ethereum/blob/v1.13.11/crypto/crypto.go#L62-L84
|
||||
|
||||
// KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports
|
||||
// Read to get a variable amount of data from the hash state. Read is faster than Sum
|
||||
// because it doesn't copy the internal state, but also modifies the internal state.
|
||||
type KeccakState interface {
|
||||
hash.Hash
|
||||
Read([]byte) (int, error)
|
||||
}
|
||||
|
||||
// Avoids multiple allocations if used frequently
|
||||
var keccak256Pool = sync.Pool{New: func() interface{} {
|
||||
return NewKeccakState()
|
||||
}}
|
||||
|
||||
// NewKeccakState creates a new KeccakState
|
||||
func NewKeccakState() KeccakState {
|
||||
return sha3.NewLegacyKeccak256().(KeccakState)
|
||||
}
|
||||
|
||||
// Keccak256 calculates and returns the Keccak256 hash of the input data.
|
||||
func Keccak256(data ...[]byte) []byte {
|
||||
b := make([]byte, 32)
|
||||
h, ok := keccak256Pool.Get().(KeccakState)
|
||||
if !ok {
|
||||
h = NewKeccakState()
|
||||
}
|
||||
defer keccak256Pool.Put(h)
|
||||
h.Reset()
|
||||
for _, b := range data {
|
||||
h.Write(b)
|
||||
}
|
||||
|
||||
h.Read(b)
|
||||
return b
|
||||
}
|
||||
|
||||
// Hashes a byte array to a field element in BN254, as used by zerokit.
|
||||
// Equivalent to: https://github.com/vacp2p/zerokit/blob/v0.3.4/rln/src/hashers.rs
|
||||
func HashToBN255(data []byte) [32]byte {
|
||||
// Hash is fixed to 32 bytes
|
||||
hashed := Keccak256(data[:])
|
||||
|
||||
// Convert to field element
|
||||
var frBN254 fr.Element
|
||||
frBN254.Unmarshal(revert(hashed))
|
||||
frBN254Bytes := frBN254.Bytes()
|
||||
|
||||
// Return fixed size
|
||||
fixexLen := [32]byte{}
|
||||
copy(fixexLen[:], revert(frBN254Bytes[:]))
|
||||
return fixexLen
|
||||
}
|
||||
|
||||
func SerializeUint32(input uint32) [32]byte {
|
||||
var byte32Type [32]byte
|
||||
binary.LittleEndian.PutUint32(byte32Type[0:], input)
|
||||
|
||||
return byte32Type
|
||||
}
|
||||
|
||||
53
rln/utils_test.go
Normal file
53
rln/utils_test.go
Normal file
@ -0,0 +1,53 @@
|
||||
package rln
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBigInt(t *testing.T) {
|
||||
base := big.NewInt(2)
|
||||
value := base.Exp(base, big.NewInt(248), nil)
|
||||
value = value.Sub(value, big.NewInt(1)) // 2^248 - 1
|
||||
|
||||
b32Value := BigIntToBytes32(value)
|
||||
require.True(t, bytes.Equal(b32Value[:], []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0}))
|
||||
|
||||
newValue := Bytes32ToBigInt(b32Value)
|
||||
require.True(t, bytes.Equal(newValue.Bytes(), value.Bytes()))
|
||||
}
|
||||
|
||||
func TestFlatten(t *testing.T) {
|
||||
in1 := [][32]byte{[32]byte{}}
|
||||
in2 := [][32]byte{[32]byte{0x00}, [32]byte{0x01}}
|
||||
in3 := [][32]byte{[32]byte{0x01, 0x02, 0x03}, [32]byte{0x04, 0x05, 0x06}}
|
||||
|
||||
expected1 := []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
|
||||
expected2 := []byte{
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
|
||||
expected3 := []byte{
|
||||
0x1, 0x2, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x4, 0x5, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
|
||||
|
||||
out1 := Flatten(in1)
|
||||
require.Equal(t, expected1, out1)
|
||||
|
||||
out2 := Flatten(in2)
|
||||
require.Equal(t, expected2, out2)
|
||||
|
||||
out3 := Flatten(in3)
|
||||
require.Equal(t, expected3, out3)
|
||||
}
|
||||
func TestHashToBN255(t *testing.T) {
|
||||
// Inputs for proof generation
|
||||
msg := []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
out := HashToBN255(msg)
|
||||
require.Equal(t,
|
||||
[32]byte{69, 7, 140, 46, 26, 131, 147, 30, 161, 68, 2, 5, 234, 195, 227, 223, 119, 187, 116, 97, 153, 70, 71, 254, 60, 149, 54, 109, 77, 79, 105, 20},
|
||||
out)
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
[target.x86_64-pc-windows-gnu]
|
||||
image = "ghcr.io/cross-rs/x86_64-pc-windows-gnu:local"
|
||||
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
image = "ghcr.io/cross-rs/aarch64-unknown-linux-gnu:local"
|
||||
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
image = "ghcr.io/cross-rs/x86_64-unknown-linux-gnu:local"
|
||||
|
||||
[target.arm-unknown-linux-gnueabi]
|
||||
image = "ghcr.io/cross-rs/arm-unknown-linux-gnueabi:local"
|
||||
|
||||
[target.i686-pc-windows-gnu]
|
||||
image = "ghcr.io/cross-rs/i686-pc-windows-gnu:local"
|
||||
|
||||
[target.i686-unknown-linux-gnu]
|
||||
image = "ghcr.io/cross-rs/i686-unknown-linux-gnu:local"
|
||||
|
||||
[target.arm-unknown-linux-gnueabihf]
|
||||
image = "ghcr.io/cross-rs/arm-unknown-linux-gnueabihf:local"
|
||||
|
||||
[target.mips-unknown-linux-gnu]
|
||||
image = "ghcr.io/cross-rs/mips-unknown-linux-gnu:local"
|
||||
|
||||
[target.mips64-unknown-linux-gnuabi64]
|
||||
image = "ghcr.io/cross-rs/mips64-unknown-linux-gnuabi64:local"
|
||||
|
||||
[target.mips64el-unknown-linux-gnuabi64]
|
||||
image = "ghcr.io/cross-rs/mips64el-unknown-linux-gnuabi64:local"
|
||||
|
||||
[target.mipsel-unknown-linux-gnu]
|
||||
image = "ghcr.io/cross-rs/mipsel-unknown-linux-gnu:local"
|
||||
@ -1,53 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
DIRECTORY=./libs
|
||||
if [[ -d "$DIRECTORY" ]]
|
||||
then
|
||||
echo "$DIRECTORY exists on your filesystem. Delete it and run the script again."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
export RUSTFLAGS="-Ccodegen-units=1"
|
||||
|
||||
rustup default stable
|
||||
|
||||
cargo install cross --git https://github.com/cross-rs/cross --branch main
|
||||
|
||||
pushd zerokit/rln
|
||||
|
||||
cargo clean
|
||||
|
||||
|
||||
cross build --release --lib --target=aarch64-unknown-linux-gnu
|
||||
cross build --release --lib --target=arm-unknown-linux-gnueabi
|
||||
cross build --release --lib --target=arm-unknown-linux-gnueabihf
|
||||
cross build --release --lib --target=i686-pc-windows-gnu
|
||||
cross build --release --lib --target=i686-unknown-linux-gnu
|
||||
cross build --release --lib --target=x86_64-pc-windows-gnu
|
||||
cross build --release --lib --target=x86_64-unknown-linux-gnu
|
||||
cross build --release --lib --target=x86_64-unknown-linux-musl
|
||||
#cross build --release --lib --target=aarch64-linux-android
|
||||
#cross build --release --lib --target=armv7-linux-androideabi
|
||||
#cross build --release --lib --target=i686-linux-android
|
||||
#cross build --release --lib --target=x86_64-linux-android
|
||||
|
||||
# TODO: these work only on iOS
|
||||
cargo install cargo-lipo
|
||||
rustup target add aarch64-apple-ios x86_64-apple-ios x86_64-apple-darwin aarch64-apple-darwin
|
||||
cargo build --release --target=x86_64-apple-darwin --lib
|
||||
cargo build --release --target=aarch64-apple-darwin --lib
|
||||
#cargo build --release --target=x86_64-apple-ios --lib
|
||||
#cargo build --release --target=aarch64-apple-ios --lib
|
||||
cargo lipo --release
|
||||
|
||||
popd
|
||||
|
||||
TOOLS_DIR=`dirname $0`
|
||||
COMPILE_DIR=${TOOLS_DIR}/../zerokit/target
|
||||
rm -rf $COMPILE_DIR/x86_64-apple-ios $COMPILE_DIR/aarch64-apple-ios
|
||||
for platform in `ls ${COMPILE_DIR} | grep -v release | grep -v debug`
|
||||
do
|
||||
PLATFORM_DIR=${DIRECTORY}/$platform
|
||||
mkdir -p ${PLATFORM_DIR}
|
||||
cp ${COMPILE_DIR}/$platform/release/librln.a ${PLATFORM_DIR}
|
||||
done
|
||||
1
zerokit
1
zerokit
@ -1 +0,0 @@
|
||||
Subproject commit b95b151a1c2407c897d486dbab2c480684ae2b7e
|
||||
Loading…
x
Reference in New Issue
Block a user