mirror of https://github.com/waku-org/go-rln.git
test: rln
This commit is contained in:
parent
6458a06c62
commit
134f023897
1
go.mod
1
go.mod
|
@ -5,4 +5,5 @@ go 1.16
|
|||
require (
|
||||
github.com/ethereum/go-ethereum v1.10.20
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/stretchr/testify v1.7.2
|
||||
)
|
||||
|
|
3
go.sum
3
go.sum
|
@ -233,9 +233,11 @@ github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH6
|
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
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/kylelemons/godebug v0.0.0-20170224010052-a616ab194758/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
|
@ -592,6 +594,7 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
|||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
|
|
18
rln/rln.go
18
rln/rln.go
|
@ -142,11 +142,14 @@ func (r *RLN) Hash(data []byte) (MerkleNode, error) {
|
|||
func (r *RLN) GenerateProof(data []byte, key MembershipKeyPair, index MembershipIndex, epoch Epoch) (*RateLimitProof, error) {
|
||||
input := serialize(key.IDKey, index, epoch, data)
|
||||
inputBuf := toBuffer(input)
|
||||
size := int(unsafe.Sizeof(inputBuf))
|
||||
in := (*C.Buffer)(C.malloc(C.size_t(size)))
|
||||
*in = inputBuf
|
||||
|
||||
var output []byte
|
||||
out := toBuffer(output)
|
||||
|
||||
if !bool(C.generate_proof(r.ptr, &inputBuf, &out)) {
|
||||
if !bool(C.generate_proof(r.ptr, in, &out)) {
|
||||
return nil, errors.New("could not generate the proof")
|
||||
}
|
||||
|
||||
|
@ -192,10 +195,13 @@ func (r *RLN) GenerateProof(data []byte, key MembershipKeyPair, index Membership
|
|||
func (r *RLN) Verify(data []byte, proof RateLimitProof) bool {
|
||||
proofBytes := proof.serialize(data)
|
||||
proofBuf := toBuffer(proofBytes)
|
||||
size := int(unsafe.Sizeof(proofBuf))
|
||||
in := (*C.Buffer)(C.malloc(C.size_t(size)))
|
||||
*in = proofBuf
|
||||
|
||||
result := uint32(0)
|
||||
res := C.uint(result)
|
||||
if !bool(C.verify(r.ptr, &proofBuf, &res)) {
|
||||
if !bool(C.verify(r.ptr, in, &res)) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -205,7 +211,13 @@ func (r *RLN) Verify(data []byte, proof RateLimitProof) bool {
|
|||
// InsertMember adds the member to the tree
|
||||
func (r *RLN) InsertMember(idComm IDCommitment) bool {
|
||||
buf := toBuffer(idComm[:])
|
||||
return bool(C.update_next_member(r.ptr, &buf))
|
||||
|
||||
size := int(unsafe.Sizeof(buf))
|
||||
in := (*C.Buffer)(C.malloc(C.size_t(size)))
|
||||
*in = buf
|
||||
|
||||
res := C.update_next_member(r.ptr, in)
|
||||
return bool(res)
|
||||
}
|
||||
|
||||
// index is the position of the id commitment key to be deleted from the tree
|
||||
|
|
319
rln/rln_test.go
319
rln/rln_test.go
|
@ -1,93 +1,264 @@
|
|||
package rln_test
|
||||
package rln
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"reflect"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/decanus/go-rln/rln"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
|
||||
_, err := rln.NewRLNWithDepth(32)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
func TestWakuRLNRelaySuite(t *testing.T) {
|
||||
suite.Run(t, new(WakuRLNRelaySuite))
|
||||
}
|
||||
|
||||
func TestGenerateKey(t *testing.T) {
|
||||
r, err := rln.NewRLNWithDepth(32)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
k, err := r.MembershipKeyGen()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(k.IDKey, [32]byte{}) {
|
||||
t.Fatal("k.IDKey was empty")
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(k.IDCommitment, [32]byte{}) {
|
||||
t.Fatal("k.IDCommitment was empty")
|
||||
}
|
||||
type WakuRLNRelaySuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func TestRLN_Hash(t *testing.T) {
|
||||
// This test is based on tests from:
|
||||
// https://github.com/status-im/nim-waku/blob/b7998de09d1ef04599a699938da69aecfa63cc6f/tests/v2/test_waku_rln_relay.nim#L527
|
||||
|
||||
r, err := rln.NewRLNWithDepth(32)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
input := byteArray(32, 1)
|
||||
|
||||
output, err := r.Hash(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := "9b581442bb7fe1bc29b5cfbc29377c0b080549bcd902d1290288d93fc773bb20"
|
||||
if expected != hex.EncodeToString(output[:]) {
|
||||
t.Fatalf("value %x did not match expected %s", output, expected)
|
||||
}
|
||||
// SetupTest is used here for reinitializing the mock before every
|
||||
// test function to avoid faulty execution.
|
||||
func (s *WakuRLNRelaySuite) SetupTest() {
|
||||
}
|
||||
|
||||
func TestRLN_GetRoot(t *testing.T) {
|
||||
// This test is based on tests from:
|
||||
// https://github.com/status-im/nim-waku/blob/b7998de09d1ef04599a699938da69aecfa63cc6f/tests/v2/test_waku_rln_relay.nim#L320
|
||||
|
||||
r, err := rln.NewRLNWithDepth(32)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
root1, err := r.GetMerkleRoot()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
root2, err := r.GetMerkleRoot()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if hex.EncodeToString(root1[:]) != hex.EncodeToString(root2[:]) {
|
||||
t.Fatalf("value %x did not match expected %x", root1, root2)
|
||||
}
|
||||
func (s *WakuRLNRelaySuite) TearDownTest() {
|
||||
//
|
||||
}
|
||||
|
||||
func byteArray(length int, value byte) []byte {
|
||||
arr := make([]byte, length)
|
||||
func (s *WakuRLNRelaySuite) TestMembershipKeyGen() {
|
||||
rln, err := NewRLNWithDepth(32)
|
||||
s.NoError(err)
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
arr[i] = value
|
||||
key, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
s.Len(key.IDKey, 32)
|
||||
s.Len(key.IDCommitment, 32)
|
||||
s.NotEmpty(key.IDKey)
|
||||
s.NotEmpty(key.IDCommitment)
|
||||
s.False(bytes.Equal(key.IDCommitment[:], make([]byte, 32)))
|
||||
s.False(bytes.Equal(key.IDKey[:], make([]byte, 32)))
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelaySuite) TestGetMerkleRoot() {
|
||||
rln, err := NewRLNWithDepth(32)
|
||||
s.NoError(err)
|
||||
|
||||
root1, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
s.Len(root1, 32)
|
||||
|
||||
root2, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
s.Len(root2, 32)
|
||||
|
||||
s.Equal(root1, root2)
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelaySuite) TestInsertMember() {
|
||||
rln, err := NewRLNWithDepth(32)
|
||||
s.NoError(err)
|
||||
|
||||
keypair, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
inserted := rln.InsertMember(keypair.IDCommitment)
|
||||
s.True(inserted)
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelaySuite) TestRemoveMember() {
|
||||
rln, err := NewRLNWithDepth(32)
|
||||
s.NoError(err)
|
||||
|
||||
deleted := rln.DeleteMember(MembershipIndex(0))
|
||||
s.True(deleted)
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelaySuite) TestMerkleTreeConsistenceBetweenDeletionAndInsertion() {
|
||||
rln, err := NewRLNWithDepth(32)
|
||||
s.NoError(err)
|
||||
|
||||
root1, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
s.Len(root1, 32)
|
||||
|
||||
keypair, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
inserted := rln.InsertMember(keypair.IDCommitment)
|
||||
s.True(inserted)
|
||||
|
||||
// read the Merkle Tree root after insertion
|
||||
root2, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
s.Len(root2, 32)
|
||||
|
||||
// delete the first member
|
||||
deleted_member_index := MembershipIndex(0)
|
||||
deleted := rln.DeleteMember(deleted_member_index)
|
||||
s.True(deleted)
|
||||
|
||||
// read the Merkle Tree root after the deletion
|
||||
root3, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
s.Len(root3, 32)
|
||||
|
||||
// the root must change after the insertion
|
||||
s.NotEqual(root1, root2)
|
||||
|
||||
// The initial root of the tree (empty tree) must be identical to
|
||||
// the root of the tree after one insertion followed by a deletion
|
||||
s.Equal(root1, root3)
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelaySuite) TestHash() {
|
||||
rln, err := NewRLNWithDepth(32)
|
||||
s.NoError(err)
|
||||
|
||||
// prepare the input
|
||||
msg := []byte("Hello")
|
||||
|
||||
hash, err := rln.Hash(msg)
|
||||
s.NoError(err)
|
||||
|
||||
expectedHash, _ := hex.DecodeString("efb8ac39dc22eaf377fe85b405b99ba78dbc2f3f32494add4501741df946bd1d")
|
||||
s.Equal(expectedHash, hash[:])
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelaySuite) TestCreateListMembershipKeysAndCreateMerkleTreeFromList() {
|
||||
groupSize := 100
|
||||
list, root, err := createMembershipList(groupSize)
|
||||
s.NoError(err)
|
||||
s.Len(list, groupSize)
|
||||
s.Len(root, HASH_HEX_SIZE) // check the size of the calculated tree root
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelaySuite) TestCheckCorrectness() {
|
||||
groupKeys := STATIC_GROUP_KEYS
|
||||
|
||||
// create a set of MembershipKeyPair objects from groupKeys
|
||||
groupKeyPairs, err := toMembershipKeyPairs(groupKeys)
|
||||
s.NoError(err)
|
||||
|
||||
// extract the id commitments
|
||||
var groupIDCommitments []IDCommitment
|
||||
for _, c := range groupKeyPairs {
|
||||
groupIDCommitments = append(groupIDCommitments, c.IDCommitment)
|
||||
}
|
||||
|
||||
return arr
|
||||
// calculate the Merkle tree root out of the extracted id commitments
|
||||
root, err := CalcMerkleRoot(groupIDCommitments)
|
||||
s.NoError(err)
|
||||
|
||||
expectedRoot, _ := hex.DecodeString(STATIC_GROUP_MERKLE_ROOT)
|
||||
|
||||
s.Len(groupKeyPairs, STATIC_GROUP_SIZE)
|
||||
s.Equal(expectedRoot, root[:])
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelaySuite) TestValidProof() {
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
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 := 0; i < 10; i++ {
|
||||
memberIsAdded := false
|
||||
if i == index {
|
||||
// insert the current peer's pk
|
||||
memberIsAdded = rln.InsertMember(memKeys.IDCommitment)
|
||||
} else {
|
||||
// create a new key pair
|
||||
memberKeys, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
memberIsAdded = rln.InsertMember(memberKeys.IDCommitment)
|
||||
}
|
||||
s.True(memberIsAdded)
|
||||
}
|
||||
|
||||
// prepare the message
|
||||
msg := []byte("Hello")
|
||||
|
||||
// prepare the epoch
|
||||
var epoch Epoch
|
||||
|
||||
// generate proof
|
||||
proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(index), epoch)
|
||||
s.NoError(err)
|
||||
|
||||
// verify the proof
|
||||
verified := rln.Verify(msg, *proofRes)
|
||||
|
||||
s.True(verified)
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelaySuite) TestInvalidProof() {
|
||||
rln, err := NewRLN()
|
||||
s.NoError(err)
|
||||
|
||||
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 := 0; i < 10; i++ {
|
||||
memberIsAdded := false
|
||||
if i == index {
|
||||
// insert the current peer's pk
|
||||
memberIsAdded = rln.InsertMember(memKeys.IDCommitment)
|
||||
} else {
|
||||
// create a new key pair
|
||||
memberKeys, err := rln.MembershipKeyGen()
|
||||
s.NoError(err)
|
||||
|
||||
memberIsAdded = rln.InsertMember(memberKeys.IDCommitment)
|
||||
}
|
||||
s.True(memberIsAdded)
|
||||
}
|
||||
|
||||
// prepare the message
|
||||
msg := []byte("Hello")
|
||||
|
||||
// prepare the epoch
|
||||
var epoch Epoch
|
||||
|
||||
badIndex := 4
|
||||
|
||||
// generate proof
|
||||
proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(badIndex), epoch)
|
||||
s.NoError(err)
|
||||
|
||||
// verify the proof (should not be verified)
|
||||
verified := rln.Verify(msg, *proofRes)
|
||||
|
||||
s.False(verified)
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelaySuite) TestEpochConsistency() {
|
||||
// check edge cases
|
||||
var epoch uint64 = math.MaxUint64
|
||||
epochBytes := ToEpoch(epoch)
|
||||
decodedEpoch := epochBytes.Uint64()
|
||||
|
||||
s.Equal(epoch, decodedEpoch)
|
||||
}
|
||||
|
||||
func (s *WakuRLNRelaySuite) TestEpochComparison() {
|
||||
// check edge cases
|
||||
var time1 uint64 = math.MaxUint64
|
||||
var time2 uint64 = math.MaxUint64 - 1
|
||||
|
||||
epoch1 := ToEpoch(time1)
|
||||
epoch2 := ToEpoch(time2)
|
||||
|
||||
s.Equal(int64(1), Diff(epoch1, epoch2))
|
||||
s.Equal(int64(-1), Diff(epoch2, epoch1))
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ func serialize(idKey IDKey, memIndex MembershipIndex, epoch Epoch, msg []byte) [
|
|||
output := append(idKey[:], memIndexBytes...)
|
||||
output = append(output, epoch[:]...)
|
||||
output = append(output, lenPrefMsg...)
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
|
|
|
@ -32,28 +32,22 @@ type WakuRLNRelay struct {
|
|||
NullifierLog map[Epoch][]ProofMetadata
|
||||
}
|
||||
|
||||
func CalcMerkleRoot(list []IDCommitment) (string, error) {
|
||||
func CalcMerkleRoot(list []IDCommitment) (MerkleNode, error) {
|
||||
// returns the root of the Merkle tree that is computed from the supplied list
|
||||
// the root is in hexadecimal format
|
||||
|
||||
rln, err := NewRLN()
|
||||
if err != nil {
|
||||
return "", err
|
||||
return MerkleNode{}, err
|
||||
}
|
||||
|
||||
// create a Merkle tree
|
||||
for _, c := range list {
|
||||
if !rln.InsertMember(c) {
|
||||
return "", errors.New("could not add member")
|
||||
return MerkleNode{}, errors.New("could not add member")
|
||||
}
|
||||
}
|
||||
|
||||
root, err := rln.GetMerkleRoot()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return hex.EncodeToString(root[:]), nil
|
||||
return rln.GetMerkleRoot()
|
||||
}
|
||||
|
||||
func createMembershipList(n int) ([][]string, string, error) {
|
||||
|
|
Loading…
Reference in New Issue