test: rln

This commit is contained in:
Richard Ramos 2022-07-02 10:38:11 -04:00
parent 6458a06c62
commit 134f023897
No known key found for this signature in database
GPG Key ID: BD36D48BC9FFC88C
6 changed files with 269 additions and 87 deletions

1
go.mod
View File

@ -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
View File

@ -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=

View File

@ -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

View File

@ -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))
}

View File

@ -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
}

View File

@ -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) {