Update to RLN v2 (#21)

This commit is contained in:
Alvaro Revuelta 2024-05-24 10:17:29 +02:00 committed by GitHub
parent 14960f3aff
commit 54bb48f178
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 289 additions and 118 deletions

7
go.mod
View File

@ -4,10 +4,11 @@ go 1.19
require ( require (
github.com/consensys/gnark-crypto v0.12.1 github.com/consensys/gnark-crypto v0.12.1
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240124080743-37fbb869c330 github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240523161310-d005fe7ba59c
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240124081101-5e4387508113 github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240523161300-8203361a01d0
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240124081123-f90cfc88a1dc github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240523161247-6f16d12c5a86
golang.org/x/crypto v0.18.0 golang.org/x/crypto v0.18.0
) )

18
go.sum
View File

@ -3,6 +3,7 @@ github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6
github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= 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/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/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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -13,19 +14,32 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 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 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240124080743-37fbb869c330 h1:TJmn6GQ5HpxdZraZn6DjUqWy8UV+8pB4yWcsWFAngqE= 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-20240124080743-37fbb869c330/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48= 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-arm v0.0.0-20240124081101-5e4387508113 h1:dPwc4LAWLXb4Pssej/NtGA9A0UMQwi+JafQPdnhjRWM= 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-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-x86_64 v0.0.0-20240124081123-f90cfc88a1dc h1:GUZlr25hXLu/PeASqm8P5dPOyD4CdfvkzyEtXEBLbr8= 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-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=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= 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/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 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -5,7 +5,11 @@
package link package link
import r "github.com/waku-org/go-zerokit-rln-apple/rln" import (
"errors"
r "github.com/waku-org/go-zerokit-rln-apple/rln"
)
type RLNWrapper struct { type RLNWrapper struct {
ffi *r.RLN ffi *r.RLN
@ -92,7 +96,8 @@ func (i RLNWrapper) GenerateRLNProof(input []byte) ([]byte, error) {
} }
func (i RLNWrapper) GenerateRLNProofWithWitness(input []byte) ([]byte, error) { func (i RLNWrapper) GenerateRLNProofWithWitness(input []byte) ([]byte, error) {
return i.ffi.GenerateRLNProofWithWitness(input) return nil, errors.New("not implemented")
//return i.ffi.GenerateRLNProofWithWitness(input)
} }
func (i RLNWrapper) VerifyWithRoots(input []byte, roots []byte) (bool, error) { func (i RLNWrapper) VerifyWithRoots(input []byte, roots []byte) (bool, error) {

View File

@ -4,7 +4,11 @@
package link package link
import r "github.com/waku-org/go-zerokit-rln-arm/rln" import (
"errors"
r "github.com/waku-org/go-zerokit-rln-arm/rln"
)
type RLNWrapper struct { type RLNWrapper struct {
ffi *r.RLN ffi *r.RLN
@ -91,7 +95,8 @@ func (i RLNWrapper) GenerateRLNProof(input []byte) ([]byte, error) {
} }
func (i RLNWrapper) GenerateRLNProofWithWitness(input []byte) ([]byte, error) { func (i RLNWrapper) GenerateRLNProofWithWitness(input []byte) ([]byte, error) {
return i.ffi.GenerateRLNProofWithWitness(input) return nil, errors.New("not implemented")
//return i.ffi.GenerateRLNProofWithWitness(input)
} }
func (i RLNWrapper) VerifyWithRoots(input []byte, roots []byte) (bool, error) { func (i RLNWrapper) VerifyWithRoots(input []byte, roots []byte) (bool, error) {

View File

@ -5,7 +5,11 @@
package link package link
import r "github.com/waku-org/go-zerokit-rln-x86_64/rln" import (
"errors"
r "github.com/waku-org/go-zerokit-rln-x86_64/rln"
)
type RLNWrapper struct { type RLNWrapper struct {
ffi *r.RLN ffi *r.RLN
@ -92,7 +96,8 @@ func (i RLNWrapper) GenerateRLNProof(input []byte) ([]byte, error) {
} }
func (i RLNWrapper) GenerateRLNProofWithWitness(input []byte) ([]byte, error) { func (i RLNWrapper) GenerateRLNProofWithWitness(input []byte) ([]byte, error) {
return i.ffi.GenerateRLNProofWithWitness(input) return nil, errors.New("not implemented")
//return i.ffi.GenerateRLNProofWithWitness(input)
} }
func (i RLNWrapper) VerifyWithRoots(input []byte, roots []byte) (bool, error) { func (i RLNWrapper) VerifyWithRoots(input []byte, roots []byte) (bool, error) {

View File

@ -14,6 +14,8 @@ import (
// Prevents a RLN ZK proof generated for one application to be re-used in another one. // 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 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. // RLN represents the context used for rln.
type RLN struct { type RLN struct {
w *link.RLNWrapper w *link.RLNWrapper
@ -91,12 +93,14 @@ func (r *RLN) InitTreeWithMembers(idComms []IDCommitment) error {
return nil return nil
} }
func toIdentityCredential(generatedKeys []byte) (*IdentityCredential, error) { func toIdentityCredential(generatedKeys []byte, userMessageLimit uint32) (*IdentityCredential, error) {
// add user message limit
key := &IdentityCredential{ key := &IdentityCredential{
IDTrapdoor: [32]byte{}, IDTrapdoor: [32]byte{},
IDNullifier: [32]byte{}, IDNullifier: [32]byte{},
IDSecretHash: [32]byte{}, IDSecretHash: [32]byte{},
IDCommitment: [32]byte{}, IDCommitment: [32]byte{},
UserMessageLimit: userMessageLimit,
} }
if len(generatedKeys) != 32*4 { if len(generatedKeys) != 32*4 {
@ -113,23 +117,45 @@ func toIdentityCredential(generatedKeys []byte) (*IdentityCredential, error) {
// MembershipKeyGen generates a IdentityCredential that can be used for the // MembershipKeyGen generates a IdentityCredential that can be used for the
// registration into the rln membership contract. Returns an error if the key generation fails // registration into the rln membership contract. Returns an error if the key generation fails
func (r *RLN) MembershipKeyGen() (*IdentityCredential, error) { // 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() generatedKeys := r.w.ExtendedKeyGen()
if generatedKeys == nil { if generatedKeys == nil {
return nil, errors.New("error in key generation") return nil, errors.New("error in key generation")
} }
return toIdentityCredential(generatedKeys) return toIdentityCredential(generatedKeys, userMessageLimit)
} }
// SeededMembershipKeyGen generates a deterministic IdentityCredential using a seed // SeededMembershipKeyGen generates a deterministic IdentityCredential using a seed
// that can be used for the registration into the rln membership contract. // that can be used for the registration into the rln membership contract.
// Returns an error if the key generation fails // Returns an error if the key generation fails
func (r *RLN) SeededMembershipKeyGen(seed []byte) (*IdentityCredential, error) { // 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) generatedKeys := r.w.ExtendedSeededKeyGen(seed)
if generatedKeys == nil { if generatedKeys == nil {
return nil, errors.New("error in key generation") return nil, errors.New("error in key generation")
} }
return toIdentityCredential(generatedKeys) return toIdentityCredential(generatedKeys, userMessageLimit)
} }
// appendLength returns length prefixed version of the input with the following format // appendLength returns length prefixed version of the input with the following format
@ -181,65 +207,61 @@ func (r *RLN) Poseidon(input ...[]byte) (MerkleNode, error) {
return result, nil return result, nil
} }
func (r *RLN) ExtractMetadata(proof RateLimitProof) (ProofMetadata, error) {
externalNullifierRes, err := r.Poseidon(proof.Epoch[:], proof.RLNIdentifier[:])
if err != nil {
return ProofMetadata{}, fmt.Errorf("could not construct the external nullifier: %w", err)
}
return ProofMetadata{
Nullifier: proof.Nullifier,
ShareX: proof.ShareX,
ShareY: proof.ShareY,
ExternalNullifier: externalNullifierRes,
}, nil
}
// GenerateProof generates a proof for the RLN given a KeyPair and the index in a merkle tree. // 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>| // 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 // integers wrapped in <> indicate value sizes in bytes
func (r *RLN) GenerateProof(data []byte, key IdentityCredential, index MembershipIndex, epoch Epoch) (*RateLimitProof, error) { func (r *RLN) GenerateProof(
input := serialize(key.IDSecretHash, index, epoch, data) data []byte,
key IdentityCredential,
index MembershipIndex,
epoch Epoch,
messageId uint32) (*RateLimitProof, error) {
externalNullifierInput, err := r.Poseidon(epoch[:], RLN_IDENTIFIER[:])
if err != nil {
return nil, fmt.Errorf("could not construct the external nullifier: %w", err)
}
input := serialize(key.IDSecretHash, index, key.UserMessageLimit, messageId, externalNullifierInput, data)
proofBytes, err := r.w.GenerateRLNProof(input) proofBytes, err := r.w.GenerateRLNProof(input)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(proofBytes) != 320 { expectedBytes := 288
return nil, errors.New("invalid proof generated") if len(proofBytes) != expectedBytes {
return nil, fmt.Errorf("invalid proof generated. size: %d expected: %d",
len(proofBytes), expectedBytes)
} }
// parse the proof as [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ] // 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 proofOffset := 128
rootOffset := proofOffset + 32 rootOffset := proofOffset + 32
epochOffset := rootOffset + 32 externalNullifierOffset := rootOffset + 32
shareXOffset := epochOffset + 32 shareXOffset := externalNullifierOffset + 32
shareYOffset := shareXOffset + 32 shareYOffset := shareXOffset + 32
nullifierOffset := shareYOffset + 32 nullifierOffset := shareYOffset + 32
rlnIdentifierOffset := nullifierOffset + 32
var zkproof ZKSNARK var zkproof ZKSNARK
var proofRoot, shareX, shareY MerkleNode var proofRoot, shareX, shareY MerkleNode
var epochR Epoch var externalNullifier Nullifier
var nullifier Nullifier var nullifier Nullifier
var rlnIdentifier RLNIdentifier
copy(zkproof[:], proofBytes[0:proofOffset]) copy(zkproof[:], proofBytes[0:proofOffset])
copy(proofRoot[:], proofBytes[proofOffset:rootOffset]) copy(proofRoot[:], proofBytes[proofOffset:rootOffset])
copy(epochR[:], proofBytes[rootOffset:epochOffset]) copy(externalNullifier[:], proofBytes[rootOffset:externalNullifierOffset])
copy(shareX[:], proofBytes[epochOffset:shareXOffset]) copy(shareX[:], proofBytes[externalNullifierOffset:shareXOffset])
copy(shareY[:], proofBytes[shareXOffset:shareYOffset]) copy(shareY[:], proofBytes[shareXOffset:shareYOffset])
copy(nullifier[:], proofBytes[shareYOffset:nullifierOffset]) copy(nullifier[:], proofBytes[shareYOffset:nullifierOffset])
copy(rlnIdentifier[:], proofBytes[nullifierOffset:rlnIdentifierOffset])
return &RateLimitProof{ return &RateLimitProof{
Proof: zkproof, Proof: zkproof,
MerkleRoot: proofRoot, MerkleRoot: proofRoot,
Epoch: epochR, ExternalNullifier: externalNullifier,
ShareX: shareX, ShareX: shareX,
ShareY: shareY, ShareY: shareY,
Nullifier: nullifier, Nullifier: nullifier,
RLNIdentifier: rlnIdentifier,
}, nil }, nil
} }
@ -248,6 +270,8 @@ func (r *RLN) GenerateProof(data []byte, key IdentityCredential, index Membershi
// input [ id_secret_hash<32> | num_elements<8> | path_elements<var1> | num_indexes<8> | path_indexes<var2> | x<32> | epoch<32> | rln_identifier<32> ] // input [ id_secret_hash<32> | num_elements<8> | path_elements<var1> | num_indexes<8> | path_indexes<var2> | x<32> | epoch<32> | rln_identifier<32> ]
// output [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ] // output [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ]
func (r *RLN) GenerateRLNProofWithWitness(witness RLNWitnessInput) (*RateLimitProof, error) { func (r *RLN) GenerateRLNProofWithWitness(witness RLNWitnessInput) (*RateLimitProof, error) {
// TODO: Will be implemented once custom witness is supported in RLN v2
return nil, errors.New("not implemented")
proofBytes, err := r.w.GenerateRLNProofWithWitness(witness.serialize()) proofBytes, err := r.w.GenerateRLNProofWithWitness(witness.serialize())
if err != nil { if err != nil {
@ -284,11 +308,9 @@ func (r *RLN) GenerateRLNProofWithWitness(witness RLNWitnessInput) (*RateLimitPr
return &RateLimitProof{ return &RateLimitProof{
Proof: zkproof, Proof: zkproof,
MerkleRoot: proofRoot, MerkleRoot: proofRoot,
Epoch: epochR,
ShareX: shareX, ShareX: shareX,
ShareY: shareY, ShareY: shareY,
Nullifier: nullifier, Nullifier: nullifier,
RLNIdentifier: rlnIdentifier,
}, nil }, nil
} }
@ -368,9 +390,17 @@ func (r *RLN) RecoverIDSecret(proof1 RateLimitProof, proof2 RateLimitProof) (IDS
return result, nil return result, nil
} }
// InsertMember adds the member to the tree // InsertMember adds the member to the tree. The leaf is made of
func (r *RLN) InsertMember(idComm IDCommitment) error { // the id commitment and the user message limit
insertionSuccess := r.w.SetNextLeaf(idComm[:]) func (r *RLN) InsertMember(idComm IDCommitment, userMessageLimit uint32) error {
userMessageLimitBytes := SerializeUint32(userMessageLimit)
hashedLeaf, err := r.Poseidon(idComm[:], userMessageLimitBytes[:])
if err != nil {
return err
}
insertionSuccess := r.w.SetNextLeaf(hashedLeaf[:])
if !insertionSuccess { if !insertionSuccess {
return errors.New("could not insert member") return errors.New("could not insert member")
} }
@ -476,9 +506,9 @@ func (r *RLN) GetMerkleProof(index MembershipIndex) (MerkleProof, error) {
} }
// AddAll adds members to the Merkle tree // AddAll adds members to the Merkle tree
func (r *RLN) AddAll(list []IDCommitment) error { func (r *RLN) AddAll(list []IdentityCredential) error {
for _, member := range list { for _, member := range list {
if err := r.InsertMember(member); err != nil { if err := r.InsertMember(member.IDCommitment, member.UserMessageLimit); err != nil {
return err return err
} }
} }
@ -520,7 +550,7 @@ func CreateMembershipList(n int) ([]IdentityCredential, MerkleNode, error) {
output = append(output, *keypair) output = append(output, *keypair)
// insert the key to the Merkle tree // insert the key to the Merkle tree
if err := rln.InsertMember(keypair.IDCommitment); err != nil { if err := rln.InsertMember(keypair.IDCommitment, keypair.UserMessageLimit); err != nil {
return nil, MerkleNode{}, err return nil, MerkleNode{}, err
} }
} }

View File

@ -76,7 +76,7 @@ func (s *RLNSuite) TestInsertMember() {
keypair, err := rln.MembershipKeyGen() keypair, err := rln.MembershipKeyGen()
s.NoError(err) s.NoError(err)
err = rln.InsertMember(keypair.IDCommitment) err = rln.InsertMember(keypair.IDCommitment, keypair.UserMessageLimit)
s.NoError(err) s.NoError(err)
} }
@ -105,7 +105,7 @@ func (s *RLNSuite) TestRemoveMember() {
keypair, err := rln.MembershipKeyGen() keypair, err := rln.MembershipKeyGen()
s.NoError(err) s.NoError(err)
err = rln.InsertMember(keypair.IDCommitment) err = rln.InsertMember(keypair.IDCommitment, keypair.UserMessageLimit)
s.NoError(err) s.NoError(err)
err = rln.DeleteMember(MembershipIndex(0)) err = rln.DeleteMember(MembershipIndex(0))
@ -123,7 +123,7 @@ func (s *RLNSuite) TestMerkleTreeConsistenceBetweenDeletionAndInsertion() {
keypair, err := rln.MembershipKeyGen() keypair, err := rln.MembershipKeyGen()
s.NoError(err) s.NoError(err)
err = rln.InsertMember(keypair.IDCommitment) err = rln.InsertMember(keypair.IDCommitment, keypair.UserMessageLimit)
s.NoError(err) s.NoError(err)
// read the Merkle Tree root after insertion // read the Merkle Tree root after insertion
@ -207,37 +207,64 @@ func (s *RLNSuite) TestCheckCorrectness() {
s.Equal(expectedRoot, root[:]) 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() { func (s *RLNSuite) TestValidProof() {
rln, err := NewRLN() rln, err := NewRLN()
s.NoError(err) s.NoError(err)
memKeys, err := rln.MembershipKeyGen() // allowed messages per epoch of the membership
s.NoError(err) userMessageLimit := uint32(10)
//peer's index in the Merkle Tree //peer's index in the Merkle Tree
index := uint(5) index := uint(5)
memKeys, err := rln.MembershipKeyGen(userMessageLimit)
s.NoError(err)
// Create a Merkle tree with random members // Create a Merkle tree with random members
for i := uint(0); i < 10; i++ { for i := uint(0); i < 10; i++ {
if i == index { if i == index {
// insert the current peer's pk err = rln.InsertMember(memKeys.IDCommitment, memKeys.UserMessageLimit)
err = rln.InsertMember(memKeys.IDCommitment)
s.NoError(err) s.NoError(err)
fifthIndexLeaf, err := rln.GetLeaf(index)
s.NoError(err)
s.Equal(memKeys.IDCommitment, fifthIndexLeaf)
} else { } else {
// create a new key pair // create a new key pair
memberKeys, err := rln.MembershipKeyGen() memberKeys, err := rln.MembershipKeyGen(userMessageLimit)
s.NoError(err) s.NoError(err)
err = rln.InsertMember(memberKeys.IDCommitment) err = rln.InsertMember(memberKeys.IDCommitment, memberKeys.UserMessageLimit)
s.NoError(err) s.NoError(err)
leaf, err := rln.GetLeaf(i)
s.NoError(err)
s.Equal(memberKeys.IDCommitment, leaf)
} }
} }
@ -245,10 +272,15 @@ func (s *RLNSuite) TestValidProof() {
msg := []byte("Hello") msg := []byte("Hello")
// prepare the epoch // prepare the epoch
var epoch Epoch var epoch Epoch = SerializeUint32(1000)
// 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 // generate proof
proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(index), epoch) proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(index), epoch, messageId)
s.NoError(err) s.NoError(err)
// verify the proof // verify the proof
@ -263,6 +295,52 @@ func (s *RLNSuite) TestValidProof() {
verified, err = rln.Verify(msg, *proofRes, root) verified, err = rln.Verify(msg, *proofRes, root)
s.NoError(err) s.NoError(err)
s.True(verified) s.True(verified)
}
}
func (s *RLNSuite) TestProofBeyondLimit() {
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)
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)
}
} }
func (s *RLNSuite) TestInvalidProof() { func (s *RLNSuite) TestInvalidProof() {
@ -279,14 +357,14 @@ func (s *RLNSuite) TestInvalidProof() {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
if i == index { if i == index {
// insert the current peer's pk // insert the current peer's pk
err := rln.InsertMember(memKeys.IDCommitment) err := rln.InsertMember(memKeys.IDCommitment, memKeys.UserMessageLimit)
s.NoError(err) s.NoError(err)
} else { } else {
// create a new key pair // create a new key pair
memberKeys, err := rln.MembershipKeyGen() memberKeys, err := rln.MembershipKeyGen()
s.NoError(err) s.NoError(err)
err = rln.InsertMember(memberKeys.IDCommitment) err = rln.InsertMember(memberKeys.IDCommitment, memberKeys.UserMessageLimit)
s.NoError(err) s.NoError(err)
} }
} }
@ -302,8 +380,11 @@ func (s *RLNSuite) TestInvalidProof() {
badIndex := 4 badIndex := 4
// message sequence within the epoch
messageId := uint32(1)
// generate proof // generate proof
proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(badIndex), epoch) proofRes, err := rln.GenerateProof(msg, *memKeys, MembershipIndex(badIndex), epoch, messageId)
s.NoError(err) s.NoError(err)
// verify the proof (should not be verified) // verify the proof (should not be verified)
@ -351,6 +432,7 @@ func (s *RLNSuite) TestGetMerkleProof() {
} }
func (s *RLNSuite) TestGenerateRLNProofWithWitness_VerifiesOK() { func (s *RLNSuite) TestGenerateRLNProofWithWitness_VerifiesOK() {
s.T().Skip("Skipped until proof generation with witness is implemented for RLNv2")
treeSize := 20 treeSize := 20
rln, err := NewRLN() rln, err := NewRLN()
@ -363,7 +445,7 @@ func (s *RLNSuite) TestGenerateRLNProofWithWitness_VerifiesOK() {
memberKeys, err := rln.MembershipKeyGen() memberKeys, err := rln.MembershipKeyGen()
s.NoError(err) s.NoError(err)
err = rln.InsertMember(memberKeys.IDCommitment) err = rln.InsertMember(memberKeys.IDCommitment, memberKeys.UserMessageLimit)
s.NoError(err) s.NoError(err)
treeElements = append(treeElements, *memberKeys) treeElements = append(treeElements, *memberKeys)
} }
@ -393,8 +475,11 @@ func (s *RLNSuite) TestGenerateRLNProofWithWitness_VerifiesOK() {
s.NoError(err) s.NoError(err)
s.True(verified1) s.True(verified1)
// message sequence within the epoch
messageId := uint32(1)
// Generate a proof without our custom witness, to ensure they match // Generate a proof without our custom witness, to ensure they match
proofRes2, err := rln.GenerateProof(message, treeElements[memberIndex], MembershipIndex(memberIndex), epoch) proofRes2, err := rln.GenerateProof(message, treeElements[memberIndex], MembershipIndex(memberIndex), epoch, messageId)
s.NoError(err) s.NoError(err)
// Ensure we have the same root // Ensure we have the same root
@ -403,15 +488,17 @@ func (s *RLNSuite) TestGenerateRLNProofWithWitness_VerifiesOK() {
// Proof generate with custom witness match the proof generate with the witness // Proof generate with custom witness match the proof generate with the witness
// from zerokit. Proof itself is not asserted, can be different. // from zerokit. Proof itself is not asserted, can be different.
s.Equal(proofRes1.MerkleRoot, proofRes2.MerkleRoot) s.Equal(proofRes1.MerkleRoot, proofRes2.MerkleRoot)
s.Equal(proofRes1.Epoch, proofRes2.Epoch) //s.Equal(proofRes1.Epoch, proofRes2.Epoch)
s.Equal(proofRes1.ShareX, proofRes2.ShareX) s.Equal(proofRes1.ShareX, proofRes2.ShareX)
s.Equal(proofRes1.ShareY, proofRes2.ShareY) s.Equal(proofRes1.ShareY, proofRes2.ShareY)
s.Equal(proofRes1.Nullifier, proofRes2.Nullifier) s.Equal(proofRes1.Nullifier, proofRes2.Nullifier)
s.Equal(proofRes1.RLNIdentifier, proofRes2.RLNIdentifier) //s.Equal(proofRes1.RLNIdentifier, proofRes2.RLNIdentifier)
} }
} }
func (s *RLNSuite) TestGenerateRLNProofWithWitness_VerifiesNOK() { func (s *RLNSuite) TestGenerateRLNProofWithWitness_VerifiesNOK() {
s.T().Skip("Skipped until proof generation with witness is implemented for RLNv2")
treeSize := 20 treeSize := 20
rln, err := NewRLN() rln, err := NewRLN()
@ -424,7 +511,7 @@ func (s *RLNSuite) TestGenerateRLNProofWithWitness_VerifiesNOK() {
memberKeys, err := rln.MembershipKeyGen() memberKeys, err := rln.MembershipKeyGen()
s.NoError(err) s.NoError(err)
err = rln.InsertMember(memberKeys.IDCommitment) err = rln.InsertMember(memberKeys.IDCommitment, memberKeys.UserMessageLimit)
s.NoError(err) s.NoError(err)
treeElements = append(treeElements, *memberKeys) treeElements = append(treeElements, *memberKeys)
} }
@ -457,7 +544,7 @@ func (s *RLNSuite) TestGenerateRLNProofWithWitness_VerifiesNOK() {
s.False(verified1) s.False(verified1)
// 2) Different epoch, does not verify // 2) Different epoch, does not verify
proofRes1.Epoch = ToEpoch(999) //proofRes1.Epoch = ToEpoch(999)
verified2, err := rln.Verify(message, *proofRes1, root) verified2, err := rln.Verify(message, *proofRes1, root)
s.NoError(err) s.NoError(err)
s.False(verified2) s.False(verified2)

View File

@ -8,18 +8,30 @@ import (
) )
// serialize converts a RateLimitProof and the data to a byte seq // serialize converts a RateLimitProof and the data to a byte seq
// this conversion is used in the proofGen function // format taken from: https://github.com/vacp2p/zerokit/blob/v0.5.0/rln/src/public.rs#L747
// the serialization is done as instructed in https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L146 // [identity_secret<32> | id_index<8> | user_message_limit<32> | message_id<32> | external_nullifier<32> | signal_len<8> | signal<var> ]
// [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ] func serialize(
func serialize(idKey IDSecretHash, memIndex MembershipIndex, epoch Epoch, msg []byte) []byte { idKey IDSecretHash,
memIndex MembershipIndex,
userMessageLimit uint32,
messageId uint32,
externalNullifier [32]byte,
msg []byte) []byte {
memIndexBytes := make([]byte, 8) memIndexBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(memIndexBytes, uint64(memIndex)) binary.LittleEndian.PutUint64(memIndexBytes, uint64(memIndex))
lenPrefMsg := appendLength(msg) 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(idKey[:], memIndexBytes...)
output = append(output, epoch[:]...) output = append(output, userMessageLimitByte[:]...)
output = append(output, messageIdByte[:]...)
output = append(output, externalNullifier[:]...)
output = append(output, lenPrefMsg...) output = append(output, lenPrefMsg...)
return output return output
@ -28,7 +40,7 @@ func serialize(idKey IDSecretHash, memIndex MembershipIndex, epoch Epoch, msg []
// serialize converts a RateLimitProof and data to a byte seq // serialize converts a RateLimitProof and data to a byte seq
// this conversion is used in the proof verification proc // 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 // the order of serialization is based on https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L205
// [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal<var> ] // [ 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 { func (r RateLimitProof) serializeWithData(data []byte) []byte {
lenPrefMsg := appendLength(data) lenPrefMsg := appendLength(data)
proofBytes := r.serialize() proofBytes := r.serialize()
@ -37,14 +49,13 @@ func (r RateLimitProof) serializeWithData(data []byte) []byte {
} }
// serialize converts a RateLimitProof to a byte seq // serialize converts a RateLimitProof to a byte seq
// [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> // [ proof<128> | root<32> | external_nullifier<32> | x<32> | y<32> | nullifier<32>]
func (r RateLimitProof) serialize() []byte { func (r RateLimitProof) serialize() []byte {
proofBytes := append(r.Proof[:], r.MerkleRoot[:]...) proofBytes := append(r.Proof[:], r.MerkleRoot[:]...)
proofBytes = append(proofBytes, r.Epoch[:]...) proofBytes = append(proofBytes, r.ExternalNullifier[:]...)
proofBytes = append(proofBytes, r.ShareX[:]...) proofBytes = append(proofBytes, r.ShareX[:]...)
proofBytes = append(proofBytes, r.ShareY[:]...) proofBytes = append(proofBytes, r.ShareY[:]...)
proofBytes = append(proofBytes, r.Nullifier[:]...) proofBytes = append(proofBytes, r.Nullifier[:]...)
proofBytes = append(proofBytes, r.RLNIdentifier[:]...)
return proofBytes return proofBytes
} }

View File

@ -36,12 +36,19 @@ type IdentityCredential = struct {
// Poseidon hash function implemented in rln lib // Poseidon hash function implemented in rln lib
// more details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership // more details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership
IDCommitment IDCommitment `json:"idCommitment"` IDCommitment IDCommitment `json:"idCommitment"`
// user's allowed messages per epoch, added in RLN v2
UserMessageLimit uint32 `json:"userMessageLimit"`
} }
func IdentityCredentialEquals(i IdentityCredential, i2 IdentityCredential) bool { func IdentityCredentialEquals(i IdentityCredential, i2 IdentityCredential) bool {
return bytes.Equal(i.IDTrapdoor[:], i2.IDTrapdoor[:]) && bytes.Equal(i.IDNullifier[:], i2.IDNullifier[:]) && bytes.Equal(i.IDSecretHash[:], i2.IDSecretHash[:]) && bytes.Equal(i.IDCommitment[:], i2.IDCommitment[:]) return bytes.Equal(i.IDTrapdoor[:], i2.IDTrapdoor[:]) &&
bytes.Equal(i.IDNullifier[:], i2.IDNullifier[:]) &&
bytes.Equal(i.IDSecretHash[:], i2.IDSecretHash[:]) &&
bytes.Equal(i.IDCommitment[:], i2.IDCommitment[:]) &&
i.UserMessageLimit == i2.UserMessageLimit
} }
// Equivalent plus proof: https://github.com/vacp2p/zerokit/blob/v0.5.0/rln/src/protocol.rs#L52
type RateLimitProof struct { type RateLimitProof struct {
// RateLimitProof holds the public inputs to rln circuit as // RateLimitProof holds the public inputs to rln circuit as
// defined in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Public-Inputs // defined in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Public-Inputs
@ -50,7 +57,7 @@ type RateLimitProof struct {
// the root of Merkle tree used for the generation of the `proof` // the root of Merkle tree used for the generation of the `proof`
MerkleRoot MerkleNode `json:"root"` MerkleRoot MerkleNode `json:"root"`
// the epoch used for the generation of the `proof` // the epoch used for the generation of the `proof`
Epoch Epoch `json:"epoch"` ExternalNullifier Nullifier `json:"external_nullifier"`
// shareX and shareY are shares of user's identity key // shareX and shareY are shares of user's identity key
// these shares are created using Shamir secret sharing scheme // these shares are created using Shamir secret sharing scheme
// see details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Linear-Equation-amp-SSS // see details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Linear-Equation-amp-SSS
@ -59,8 +66,6 @@ type RateLimitProof struct {
// nullifier enables linking two messages published during the same epoch // nullifier enables linking two messages published during the same epoch
// see details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Nullifiers // see details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Nullifiers
Nullifier Nullifier `json:"nullifier"` Nullifier Nullifier `json:"nullifier"`
// Application specific RLN Identifier
RLNIdentifier RLNIdentifier `json:"rlnIdentifier"`
} }
type MerkleProof struct { type MerkleProof struct {

View File

@ -1,6 +1,7 @@
package rln package rln
import ( import (
"encoding/binary"
"encoding/hex" "encoding/hex"
"hash" "hash"
"math/big" "math/big"
@ -181,3 +182,10 @@ func HashToBN255(data []byte) [32]byte {
copy(fixexLen[:], revert(frBN254Bytes[:])) copy(fixexLen[:], revert(frBN254Bytes[:]))
return fixexLen return fixexLen
} }
func SerializeUint32(input uint32) [32]byte {
var byte32Type [32]byte
binary.LittleEndian.PutUint32(byte32Type[0:], input)
return byte32Type
}