mirror of
https://github.com/logos-messaging/go-zerokit-rln.git
synced 2026-01-02 13:13:11 +00:00
Compare commits
No commits in common. "master" and "v0.1.5" have entirely different histories.
20
.github/workflows/tests.yml
vendored
20
.github/workflows/tests.yml
vendored
@ -1,20 +0,0 @@
|
||||
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,7 +13,3 @@
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Tree persistence
|
||||
snap.*
|
||||
blobs/
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -0,0 +1,3 @@
|
||||
[submodule "zerokit"]
|
||||
path = zerokit
|
||||
url = git@github.com:vacp2p/zerokit.git
|
||||
12
Makefile
Normal file
12
Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
.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,81 +2,13 @@
|
||||
|
||||
Go wrappers for [zerokit's RLN](https://github.com/vacp2p/zerokit)
|
||||
|
||||
|
||||
|
||||
### 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}
|
||||
### Building this library
|
||||
```
|
||||
git clone https://github.com/status-im/go-zerokit-rln
|
||||
cd go-zerokit-rln
|
||||
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
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
To generate smaller static libraries, before `make`, edit `./zerokit/rln/Cargo.toml` and use `branch = "no-ethers-core"` for `ark-circom`
|
||||
|
||||
20
go.mod
20
go.mod
@ -1,23 +1,13 @@
|
||||
module github.com/waku-org/go-zerokit-rln
|
||||
module github.com/status-im/go-zerokit-rln
|
||||
|
||||
go 1.19
|
||||
go 1.17
|
||||
|
||||
require github.com/stretchr/testify v1.7.2
|
||||
|
||||
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
|
||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
47
go.sum
47
go.sum
@ -1,53 +1,20 @@
|
||||
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.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
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/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/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=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
BIN
libs/aarch64-apple-darwin/librln.a
Normal file
BIN
libs/aarch64-apple-darwin/librln.a
Normal file
Binary file not shown.
BIN
libs/aarch64-unknown-linux-gnu/librln.a
Normal file
BIN
libs/aarch64-unknown-linux-gnu/librln.a
Normal file
Binary file not shown.
BIN
libs/arm-unknown-linux-gnueabi/librln.a
Normal file
BIN
libs/arm-unknown-linux-gnueabi/librln.a
Normal file
Binary file not shown.
BIN
libs/arm-unknown-linux-gnueabihf/librln.a
Normal file
BIN
libs/arm-unknown-linux-gnueabihf/librln.a
Normal file
Binary file not shown.
BIN
libs/i686-unknown-linux-gnu/librln.a
Normal file
BIN
libs/i686-unknown-linux-gnu/librln.a
Normal file
Binary file not shown.
BIN
libs/x86_64-apple-darwin/librln.a
Normal file
BIN
libs/x86_64-apple-darwin/librln.a
Normal file
Binary file not shown.
BIN
libs/x86_64-pc-windows-gnu/librln.a
Normal file
BIN
libs/x86_64-pc-windows-gnu/librln.a
Normal file
Binary file not shown.
BIN
libs/x86_64-unknown-linux-gnu/librln.a
Normal file
BIN
libs/x86_64-unknown-linux-gnu/librln.a
Normal file
Binary file not shown.
BIN
libs/x86_64-unknown-linux-musl/librln.a
Normal file
BIN
libs/x86_64-unknown-linux-musl/librln.a
Normal file
Binary file not shown.
66
rln/librln.h
Normal file
66
rln/librln.h
Normal file
@ -0,0 +1,66 @@
|
||||
#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
Normal file
16
rln/link.go
Normal file
@ -0,0 +1,16 @@
|
||||
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"
|
||||
@ -1,130 +0,0 @@
|
||||
//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
129
rln/link/arm.go
@ -1,129 +0,0 @@
|
||||
//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()
|
||||
}
|
||||
@ -1,130 +0,0 @@
|
||||
//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()
|
||||
}
|
||||
345
rln/resources/bindata.go
Normal file
345
rln/resources/bindata.go
Normal file
File diff suppressed because one or more lines are too long
3
rln/resources/doc.go
Normal file
3
rln/resources/doc.go
Normal file
@ -0,0 +1,3 @@
|
||||
package resources
|
||||
|
||||
//go:generate go-bindata -pkg resources -o ./bindata.go ./...
|
||||
BIN
rln/resources/tree_height_20/rln.wasm
Normal file
BIN
rln/resources/tree_height_20/rln.wasm
Normal file
Binary file not shown.
BIN
rln/resources/tree_height_20/rln_final.zkey
Normal file
BIN
rln/resources/tree_height_20/rln_final.zkey
Normal file
Binary file not shown.
119
rln/resources/tree_height_20/verification_key.json
Normal file
119
rln/resources/tree_height_20/verification_key.json
Normal file
@ -0,0 +1,119 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
]
|
||||
}
|
||||
618
rln/rln.go
618
rln/rln.go
@ -1,163 +1,121 @@
|
||||
package rln
|
||||
|
||||
/*
|
||||
#include "./librln.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/waku-org/go-zerokit-rln/rln/link"
|
||||
"github.com/status-im/go-zerokit-rln/rln/resources"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
w *link.RLNWrapper
|
||||
}
|
||||
|
||||
func getResourcesFolder(depth TreeDepth) string {
|
||||
return fmt.Sprintf("tree_height_%d", depth)
|
||||
ptr *C.RLN
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return NewWithConfig(DefaultTreeDepth, nil)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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, treeConfig *TreeConfig) (*RLN, error) {
|
||||
func NewRLNWithParams(depth int, wasm []byte, zkey []byte, verifKey []byte) (*RLN, error) {
|
||||
r := &RLN{}
|
||||
var err error
|
||||
|
||||
treeConfigBytes := []byte{}
|
||||
if treeConfig != nil {
|
||||
treeConfigBytes, err = json.Marshal(treeConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
wasmBuffer := toCBufferPtr(wasm)
|
||||
zkeyBuffer := toCBufferPtr(zkey)
|
||||
verifKeyBuffer := toCBufferPtr(verifKey)
|
||||
|
||||
r.w, err = link.NewWithParams(depth, wasm, zkey, verifKey, treeConfigBytes)
|
||||
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")
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// 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) {
|
||||
r := &RLN{}
|
||||
var err error
|
||||
|
||||
configBytes, err := json.Marshal(config{
|
||||
ResourcesFolder: getResourcesFolder(depth),
|
||||
TreeConfig: treeConfig,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pathBuffer := toCBufferPtr([]byte(resourcesFolderPath))
|
||||
|
||||
r.w, err = link.New(int(depth), configBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if !bool(C.new(C.uintptr_t(depth), pathBuffer, &r.ptr)) {
|
||||
return nil, errors.New("failed to initialize")
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *RLN) SetTree(treeHeight uint) error {
|
||||
success := r.w.SetTree(treeHeight)
|
||||
if !success {
|
||||
return errors.New("could not set tree height")
|
||||
}
|
||||
return 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
|
||||
}
|
||||
|
||||
// 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,
|
||||
// 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")
|
||||
}
|
||||
|
||||
if len(generatedKeys) != 32*4 {
|
||||
return nil, errors.New("generated keys are of invalid length")
|
||||
key := &MembershipKeyPair{
|
||||
IDKey: [32]byte{},
|
||||
IDCommitment: [32]byte{},
|
||||
}
|
||||
|
||||
copy(key.IDTrapdoor[:], generatedKeys[:32])
|
||||
copy(key.IDNullifier[:], generatedKeys[32:64])
|
||||
copy(key.IDSecretHash[:], generatedKeys[64:96])
|
||||
copy(key.IDCommitment[:], generatedKeys[96:128])
|
||||
// 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])
|
||||
|
||||
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 {
|
||||
@ -166,40 +124,40 @@ func appendLength(input []byte) []byte {
|
||||
return append(inputLen, input...)
|
||||
}
|
||||
|
||||
// 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...)
|
||||
// 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),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RLN) Sha256(data []byte) (MerkleNode, error) {
|
||||
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
|
||||
lenPrefData := appendLength(data)
|
||||
|
||||
b, err := r.w.Hash(lenPrefData)
|
||||
if err != nil {
|
||||
return MerkleNode{}, err
|
||||
hashInputBuffer := toCBufferPtr(lenPrefData)
|
||||
|
||||
var output []byte
|
||||
out := toBuffer(output)
|
||||
|
||||
if !bool(C.hash(r.ptr, hashInputBuffer, &out)) {
|
||||
return MerkleNode{}, errors.New("failed to hash")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
b := C.GoBytes(unsafe.Pointer(out.ptr), C.int(out.len))
|
||||
|
||||
var result MerkleNode
|
||||
copy(result[:], b)
|
||||
@ -210,246 +168,97 @@ func (r *RLN) Poseidon(input ...[]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 IdentityCredential,
|
||||
index MembershipIndex,
|
||||
epoch Epoch,
|
||||
messageId uint32) (*RateLimitProof, error) {
|
||||
func (r *RLN) GenerateProof(data []byte, key MembershipKeyPair, index MembershipIndex, epoch Epoch) (*RateLimitProof, error) {
|
||||
input := serialize(key.IDKey, index, epoch, data)
|
||||
inputBuffer := toCBufferPtr(input)
|
||||
|
||||
externalNullifierInput, err := r.Poseidon(epoch[:], RLN_IDENTIFIER[:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not construct the external nullifier: %w", err)
|
||||
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")
|
||||
}
|
||||
|
||||
input := serialize(key.IDSecretHash, index, key.UserMessageLimit, messageId, externalNullifierInput, data)
|
||||
proofBytes, err := r.w.GenerateRLNProof(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
proofBytes := C.GoBytes(unsafe.Pointer(out.ptr), C.int(out.len))
|
||||
|
||||
if len(proofBytes) != 320 {
|
||||
return nil, errors.New("invalid proof generated")
|
||||
}
|
||||
|
||||
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>]
|
||||
// parse the proof as [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ]
|
||||
proofOffset := 128
|
||||
rootOffset := proofOffset + 32
|
||||
externalNullifierOffset := rootOffset + 32
|
||||
shareXOffset := externalNullifierOffset + 32
|
||||
epochOffset := rootOffset + 32
|
||||
shareXOffset := epochOffset + 32
|
||||
shareYOffset := shareXOffset + 32
|
||||
nullifierOffset := shareYOffset + 32
|
||||
rlnIdentifierOffset := nullifierOffset + 32
|
||||
|
||||
var zkproof ZKSNARK
|
||||
var proofRoot, shareX, shareY MerkleNode
|
||||
var externalNullifier Nullifier
|
||||
var epochR Epoch
|
||||
var nullifier Nullifier
|
||||
var rlnIdentifier RLNIdentifier
|
||||
|
||||
copy(zkproof[:], proofBytes[0:proofOffset])
|
||||
copy(proofRoot[:], proofBytes[proofOffset:rootOffset])
|
||||
copy(externalNullifier[:], proofBytes[rootOffset:externalNullifierOffset])
|
||||
copy(shareX[:], proofBytes[externalNullifierOffset:shareXOffset])
|
||||
copy(epochR[:], proofBytes[rootOffset:epochOffset])
|
||||
copy(shareX[:], proofBytes[epochOffset:shareXOffset])
|
||||
copy(shareY[:], proofBytes[shareXOffset:shareYOffset])
|
||||
copy(nullifier[:], proofBytes[shareYOffset:nullifierOffset])
|
||||
copy(rlnIdentifier[:], proofBytes[nullifierOffset:rlnIdentifierOffset])
|
||||
|
||||
return &RateLimitProof{
|
||||
Proof: zkproof,
|
||||
MerkleRoot: proofRoot,
|
||||
ExternalNullifier: externalNullifier,
|
||||
ShareX: shareX,
|
||||
ShareY: shareY,
|
||||
Nullifier: nullifier,
|
||||
Proof: zkproof,
|
||||
MerkleRoot: proofRoot,
|
||||
Epoch: epochR,
|
||||
ShareX: shareX,
|
||||
ShareY: shareY,
|
||||
Nullifier: nullifier,
|
||||
RLNIdentifier: rlnIdentifier,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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 (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[:]...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func serializeSlice(roots [][]byte) []byte {
|
||||
var result []byte
|
||||
for _, r := range roots {
|
||||
result = append(result, r[:]...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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> ]
|
||||
// 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
|
||||
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")
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return bool(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
|
||||
func serializeRoots(roots [][32]byte) []byte {
|
||||
var result []byte
|
||||
for _, r := range roots {
|
||||
result = append(result, r[:]...)
|
||||
}
|
||||
var result IDSecretHash
|
||||
copy(result[:], secret)
|
||||
return result, nil
|
||||
return result
|
||||
}
|
||||
|
||||
// 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)
|
||||
func (r *RLN) VerifyWithRoots(data []byte, proof RateLimitProof, roots [][32]byte) (bool, error) {
|
||||
proofBytes := proof.serialize(data)
|
||||
proofBuf := toCBufferPtr(proofBytes)
|
||||
|
||||
hashedLeaf, err := r.Poseidon(idComm[:], userMessageLimitBytes[:])
|
||||
if err != nil {
|
||||
return err
|
||||
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")
|
||||
}
|
||||
|
||||
insertionSuccess := r.w.SetNextLeaf(hashedLeaf[:])
|
||||
if !insertionSuccess {
|
||||
return errors.New("could not insert member")
|
||||
}
|
||||
return nil
|
||||
return bool(res), 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[:])
|
||||
// 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))
|
||||
if !insertionSuccess {
|
||||
return errors.New("could not insert member")
|
||||
}
|
||||
@ -460,31 +269,24 @@ func (r *RLN) InsertMemberAt(index MembershipIndex, 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 := r.w.DeleteLeaf(index)
|
||||
deletionSuccess := bool(C.delete_leaf(r.ptr, C.uintptr_t(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) {
|
||||
b, err := r.w.GetRoot()
|
||||
if err != nil {
|
||||
return MerkleNode{}, err
|
||||
var output []byte
|
||||
out := toBuffer(output)
|
||||
|
||||
if !bool(C.get_root(r.ptr, &out)) {
|
||||
return MerkleNode{}, errors.New("could not get the root")
|
||||
}
|
||||
|
||||
b := C.GoBytes(unsafe.Pointer(out.ptr), C.int(out.len))
|
||||
|
||||
if len(b) != 32 {
|
||||
return MerkleNode{}, errors.New("wrong output size")
|
||||
}
|
||||
@ -495,48 +297,10 @@ 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 []IdentityCredential) error {
|
||||
func (r *RLN) AddAll(list []IDCommitment) error {
|
||||
for _, member := range list {
|
||||
if err := r.InsertMember(member.IDCommitment, member.UserMessageLimit); err != nil {
|
||||
if err := r.InsertMember(member); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -550,8 +314,11 @@ func CalcMerkleRoot(list []IDCommitment) (MerkleNode, error) {
|
||||
return MerkleNode{}, err
|
||||
}
|
||||
|
||||
if err := rln.InsertMembers(0, list); err != nil {
|
||||
return MerkleNode{}, err
|
||||
// create a Merkle tree
|
||||
for _, c := range list {
|
||||
if err := rln.InsertMember(c); err != nil {
|
||||
return MerkleNode{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return rln.GetMerkleRoot()
|
||||
@ -560,14 +327,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) ([]IdentityCredential, MerkleNode, error) {
|
||||
func CreateMembershipList(n int) ([]MembershipKeyPair, MerkleNode, error) {
|
||||
// initialize a Merkle tree
|
||||
rln, err := NewRLN()
|
||||
if err != nil {
|
||||
return nil, MerkleNode{}, err
|
||||
}
|
||||
|
||||
var output []IdentityCredential
|
||||
var output []MembershipKeyPair
|
||||
for i := 0; i < n; i++ {
|
||||
// generate a keypair
|
||||
keypair, err := rln.MembershipKeyGen()
|
||||
@ -578,7 +345,7 @@ func CreateMembershipList(n int) ([]IdentityCredential, MerkleNode, error) {
|
||||
output = append(output, *keypair)
|
||||
|
||||
// insert the key to the Merkle tree
|
||||
if err := rln.InsertMember(keypair.IDCommitment, keypair.UserMessageLimit); err != nil {
|
||||
if err := rln.InsertMember(keypair.IDCommitment); err != nil {
|
||||
return nil, MerkleNode{}, err
|
||||
}
|
||||
}
|
||||
@ -590,42 +357,3 @@ func CreateMembershipList(n int) ([]IdentityCredential, 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()
|
||||
}
|
||||
|
||||
474
rln/rln_test.go
474
rln/rln_test.go
@ -17,41 +17,18 @@ 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.IDSecretHash, 32)
|
||||
s.Len(key.IDKey, 32)
|
||||
s.Len(key.IDCommitment, 32)
|
||||
s.Len(key.IDTrapdoor, 32)
|
||||
s.Len(key.IDNullifier, 32)
|
||||
s.NotEmpty(key.IDSecretHash)
|
||||
s.NotEmpty(key.IDKey)
|
||||
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.IDSecretHash[:], make([]byte, 32)))
|
||||
s.False(bytes.Equal(key.IDTrapdoor[:], make([]byte, 32)))
|
||||
s.False(bytes.Equal(key.IDNullifier[:], make([]byte, 32)))
|
||||
s.False(bytes.Equal(key.IDKey[:], make([]byte, 32)))
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestGetMerkleRoot() {
|
||||
@ -76,69 +53,14 @@ func (s *RLNSuite) TestInsertMember() {
|
||||
keypair, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(keypair.IDCommitment, keypair.UserMessageLimit)
|
||||
err = rln.InsertMember(keypair.IDCommitment)
|
||||
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)
|
||||
}
|
||||
@ -154,7 +76,7 @@ func (s *RLNSuite) TestMerkleTreeConsistenceBetweenDeletionAndInsertion() {
|
||||
keypair, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(keypair.IDCommitment, keypair.UserMessageLimit)
|
||||
err = rln.InsertMember(keypair.IDCommitment)
|
||||
s.NoError(err)
|
||||
|
||||
// read the Merkle Tree root after insertion
|
||||
@ -186,27 +108,13 @@ func (s *RLNSuite) TestHash() {
|
||||
|
||||
// prepare the input
|
||||
msg := []byte("Hello")
|
||||
hash, err := rln.Sha256(msg)
|
||||
hash, err := rln.Hash(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)
|
||||
@ -219,7 +127,7 @@ func (s *RLNSuite) TestCheckCorrectness() {
|
||||
groupKeys := STATIC_GROUP_KEYS
|
||||
|
||||
// create a set of MembershipKeyPair objects from groupKeys
|
||||
groupKeyPairs, err := ToIdentityCredentials(groupKeys)
|
||||
groupKeyPairs, err := toMembershipKeyPairs(groupKeys)
|
||||
s.NoError(err)
|
||||
|
||||
// extract the id commitments
|
||||
@ -238,63 +146,28 @@ 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)
|
||||
|
||||
// allowed messages per epoch of the membership
|
||||
userMessageLimit := uint32(10)
|
||||
|
||||
//peer's index in the Merkle Tree
|
||||
index := uint(5)
|
||||
|
||||
memKeys, err := rln.MembershipKeyGen(userMessageLimit)
|
||||
memKeys, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
//peer's index in the Merkle Tree
|
||||
index := 5
|
||||
|
||||
// Create a Merkle tree with random members
|
||||
for i := uint(0); i < 10; i++ {
|
||||
for i := 0; i < 10; i++ {
|
||||
if i == index {
|
||||
err = rln.InsertMember(memKeys.IDCommitment, memKeys.UserMessageLimit)
|
||||
// insert the current peer's pk
|
||||
err = rln.InsertMember(memKeys.IDCommitment)
|
||||
s.NoError(err)
|
||||
} else {
|
||||
// create a new key pair
|
||||
memberKeys, err := rln.MembershipKeyGen(userMessageLimit)
|
||||
memberKeys, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(memberKeys.IDCommitment, memberKeys.UserMessageLimit)
|
||||
err = rln.InsertMember(memberKeys.IDCommitment)
|
||||
s.NoError(err)
|
||||
}
|
||||
}
|
||||
@ -303,75 +176,24 @@ func (s *RLNSuite) TestValidProof() {
|
||||
msg := []byte("Hello")
|
||||
|
||||
// prepare the epoch
|
||||
var epoch Epoch = SerializeUint32(1000)
|
||||
var epoch 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()
|
||||
// generate proof
|
||||
proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(index), epoch)
|
||||
s.NoError(err)
|
||||
|
||||
// allowed messages per epoch of the membership
|
||||
userMessageLimit := uint32(10)
|
||||
// verify the proof
|
||||
verified, err := rln.Verify(msg, *proofRes)
|
||||
s.NoError(err)
|
||||
s.True(verified)
|
||||
|
||||
//peer's index in the Merkle Tree
|
||||
index := uint(5)
|
||||
|
||||
memKeys, err := rln.MembershipKeyGen(userMessageLimit)
|
||||
// verify with roots
|
||||
root, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
|
||||
// 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)
|
||||
}
|
||||
verified, err = rln.VerifyWithRoots(msg, *proofRes, [][32]byte{root})
|
||||
s.NoError(err)
|
||||
s.True(verified)
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestInvalidProof() {
|
||||
@ -388,21 +210,18 @@ func (s *RLNSuite) TestInvalidProof() {
|
||||
for i := 0; i < 10; i++ {
|
||||
if i == index {
|
||||
// insert the current peer's pk
|
||||
err := rln.InsertMember(memKeys.IDCommitment, memKeys.UserMessageLimit)
|
||||
err := rln.InsertMember(memKeys.IDCommitment)
|
||||
s.NoError(err)
|
||||
} else {
|
||||
// create a new key pair
|
||||
memberKeys, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
err = rln.InsertMember(memberKeys.IDCommitment, memberKeys.UserMessageLimit)
|
||||
err = rln.InsertMember(memberKeys.IDCommitment)
|
||||
s.NoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
root, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
|
||||
// prepare the message
|
||||
msg := []byte("Hello")
|
||||
|
||||
@ -411,245 +230,16 @@ 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, messageId)
|
||||
proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(badIndex), epoch)
|
||||
s.NoError(err)
|
||||
|
||||
// verify the proof (should not be verified)
|
||||
verified, err := rln.Verify(msg, *proofRes, root)
|
||||
verified, err := rln.Verify(msg, *proofRes)
|
||||
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,37 +1,20 @@
|
||||
package rln
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
import "encoding/binary"
|
||||
|
||||
// serialize converts a RateLimitProof and the data to a byte seq
|
||||
// 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 {
|
||||
// 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 {
|
||||
|
||||
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, userMessageLimitByte[:]...)
|
||||
output = append(output, messageIdByte[:]...)
|
||||
output = append(output, externalNullifier[:]...)
|
||||
output = append(output, epoch[:]...)
|
||||
output = append(output, lenPrefMsg...)
|
||||
|
||||
return output
|
||||
@ -40,111 +23,16 @@ func serialize(
|
||||
// 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> | external_nullifier<32> | x<32> | y<32> | nullifier<32> | signal_len<8> | signal<var> ]
|
||||
func (r RateLimitProof) serializeWithData(data []byte) []byte {
|
||||
// [ 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 {
|
||||
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.ExternalNullifier[:]...)
|
||||
proofBytes = append(proofBytes, r.Epoch[:]...)
|
||||
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
|
||||
}
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
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))
|
||||
}
|
||||
226
rln/types.go
226
rln/types.go
File diff suppressed because one or more lines are too long
164
rln/utils.go
164
rln/utils.go
@ -1,53 +1,26 @@
|
||||
package rln
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"hash"
|
||||
"math/big"
|
||||
"sync"
|
||||
import "encoding/hex"
|
||||
|
||||
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
func ToIdentityCredentials(groupKeys [][]string) ([]IdentityCredential, error) {
|
||||
func toMembershipKeyPairs(groupKeys [][]string) ([]MembershipKeyPair, error) {
|
||||
// groupKeys is sequence of membership key tuples in the form of (identity key, identity commitment) all in the hexadecimal format
|
||||
// the toIdentityCredentials proc populates a sequence of IdentityCredentials using the supplied groupKeys
|
||||
// Returns an error if the conversion fails
|
||||
// the toMembershipKeyPairs proc populates a sequence of MembershipKeyPairs using the supplied groupKeys
|
||||
|
||||
var groupIdCredentials []IdentityCredential
|
||||
|
||||
for _, gk := range groupKeys {
|
||||
idTrapdoor, err := ToBytes32LE(gk[0])
|
||||
groupKeyPairs := []MembershipKeyPair{}
|
||||
for _, pair := range groupKeys {
|
||||
idKey, err := hex.DecodeString(pair[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idCommitment, err := hex.DecodeString(pair[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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,
|
||||
})
|
||||
groupKeyPairs = append(groupKeyPairs, MembershipKeyPair{IDKey: IDKey(Bytes32(idKey)), IDCommitment: IDCommitment(Bytes32(idCommitment))})
|
||||
}
|
||||
|
||||
return groupIdCredentials, nil
|
||||
return groupKeyPairs, nil
|
||||
}
|
||||
|
||||
func Bytes32(b []byte) [32]byte {
|
||||
@ -61,116 +34,3 @@ 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
|
||||
}
|
||||
|
||||
@ -1,53 +0,0 @@
|
||||
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)
|
||||
}
|
||||
32
scripts/Cross.toml
Normal file
32
scripts/Cross.toml
Normal file
@ -0,0 +1,32 @@
|
||||
[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"
|
||||
53
scripts/build.sh
Executable file
53
scripts/build.sh
Executable file
@ -0,0 +1,53 @@
|
||||
#!/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
Submodule
1
zerokit
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit b95b151a1c2407c897d486dbab2c480684ae2b7e
|
||||
Loading…
x
Reference in New Issue
Block a user