mirror of
https://github.com/logos-messaging/go-zerokit-rln.git
synced 2026-01-03 21:53:09 +00:00
Wrap proof with custom witness
This commit is contained in:
parent
7e086e8f89
commit
4c93f5564f
2
go.mod
2
go.mod
@ -4,7 +4,7 @@ go 1.19
|
||||
|
||||
require (
|
||||
github.com/stretchr/testify v1.7.2
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240116135015-f6f595c7b8ef
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240117094748-68b4162e8fd7
|
||||
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240116134931-a8b8c6ab4b80
|
||||
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20240116135046-2875fec12afc
|
||||
)
|
||||
|
||||
6
go.sum
6
go.sum
@ -21,6 +21,12 @@ github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240116121347-ee5a1d931442 h1:x
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240116121347-ee5a1d931442/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240116135015-f6f595c7b8ef h1:MAkZryAeRhiH3TKHRK2h+WztZI1VqfQ/oeXMIxKZNy0=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240116135015-f6f595c7b8ef/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240117093624-7ba5a338d490 h1:1OivqdMCBCRIp2qzUggSpZPhcaRkcFl0U5UoPfGWB9g=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240117093624-7ba5a338d490/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240117093914-f79c87b06466 h1:Baxd/BPVGKgaVvLoI0//UtSVNovlY/IOROQpfni8pbE=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240117093914-f79c87b06466/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240117094748-68b4162e8fd7 h1:MOpAZITkW2EkI7aO1uUGWsGuUnQH3K/Mk7WuqLpFQGo=
|
||||
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20240117094748-68b4162e8fd7/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
|
||||
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20230916171929-1dd9494ff065 h1:Sd7QD/1Yo2o2M1MY49F8Zr4KNBPUEK5cz5HoXQVJbrs=
|
||||
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20230916171929-1dd9494ff065/go.mod h1:7cSGUoGVIla1IpnChrLbkVjkYgdOcr7rcifEfh4ReR4=
|
||||
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20240116134931-a8b8c6ab4b80 h1:3KObRaYJnTI41U0reNBk7DYr5PVCTq8T9gJLXGfPfaY=
|
||||
|
||||
@ -91,6 +91,10 @@ 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)
|
||||
}
|
||||
|
||||
@ -90,6 +90,10 @@ 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)
|
||||
}
|
||||
|
||||
@ -91,6 +91,10 @@ 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)
|
||||
}
|
||||
|
||||
60
rln/rln.go
60
rln/rln.go
@ -233,6 +233,64 @@ func (r *RLN) GenerateProof(data []byte, key IdentityCredential, index Membershi
|
||||
}, nil
|
||||
}
|
||||
|
||||
// input :
|
||||
/*
|
||||
identity_secret: Fr,
|
||||
path_elements: Vec<Fr>,
|
||||
identity_path_index: Vec<u8>,
|
||||
x: Fr,
|
||||
epoch: Fr,
|
||||
rln_identifier: Fr,
|
||||
*/
|
||||
// todo: output same as other function.
|
||||
// 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) {
|
||||
|
||||
proofBytes, err := r.w.GenerateRLNProofWithWitness(witness.serialize())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(proofBytes) != 320 {
|
||||
return nil, errors.New("invalid proof generated")
|
||||
}
|
||||
|
||||
// TODO: maybe move this into a common function (used by the other generateRlnproof function)
|
||||
// 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
|
||||
epochOffset := rootOffset + 32
|
||||
shareXOffset := epochOffset + 32
|
||||
shareYOffset := shareXOffset + 32
|
||||
nullifierOffset := shareYOffset + 32
|
||||
rlnIdentifierOffset := nullifierOffset + 32
|
||||
|
||||
var zkproof ZKSNARK
|
||||
var proofRoot, shareX, shareY MerkleNode
|
||||
var epochR Epoch
|
||||
var nullifier Nullifier
|
||||
var rlnIdentifier RLNIdentifier
|
||||
|
||||
copy(zkproof[:], proofBytes[0:proofOffset])
|
||||
copy(proofRoot[:], proofBytes[proofOffset:rootOffset])
|
||||
copy(epochR[:], proofBytes[rootOffset:epochOffset])
|
||||
copy(shareX[:], proofBytes[epochOffset:shareXOffset])
|
||||
copy(shareY[:], proofBytes[shareXOffset:shareYOffset])
|
||||
copy(nullifier[:], proofBytes[shareYOffset:nullifierOffset])
|
||||
copy(rlnIdentifier[:], proofBytes[nullifierOffset:rlnIdentifierOffset])
|
||||
|
||||
return &RateLimitProof{
|
||||
Proof: zkproof,
|
||||
MerkleRoot: proofRoot,
|
||||
Epoch: epochR,
|
||||
ShareX: shareX,
|
||||
ShareY: shareY,
|
||||
Nullifier: nullifier,
|
||||
RLNIdentifier: rlnIdentifier,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func serialize32(roots [][32]byte) []byte {
|
||||
var result []byte
|
||||
for _, r := range roots {
|
||||
@ -406,6 +464,8 @@ func (r *RLN) GetMerkleProof(index MembershipIndex) (MerkleProof, error) {
|
||||
return MerkleProof{}, err
|
||||
}
|
||||
|
||||
// TODO: Take this from the function
|
||||
|
||||
// Check if we can read the first byte
|
||||
if len(proofBytes) < 8 {
|
||||
return MerkleProof{}, errors.New(fmt.Sprintf("wrong output size: %d", len(proofBytes)))
|
||||
|
||||
@ -350,6 +350,64 @@ func (s *RLNSuite) TestGetMerkleProof() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestGenerateRLNProofWithWitness() {
|
||||
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++ {
|
||||
if i == index {
|
||||
// insert the current peer's pk
|
||||
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)
|
||||
s.NoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
root, err := rln.GetMerkleRoot()
|
||||
s.NoError(err)
|
||||
|
||||
// prepare the message
|
||||
msg := []byte("Hello")
|
||||
|
||||
// prepare the epoch
|
||||
var epoch Epoch
|
||||
|
||||
badIndex := 4
|
||||
|
||||
merkleProof, err := rln.GetMerkleProof(uint(badIndex))
|
||||
s.NoError(err)
|
||||
|
||||
rlnWitness := RLNWitnessInput{
|
||||
IdentityCredential: *memKeys,
|
||||
MerkleProof: merkleProof,
|
||||
Data: msg,
|
||||
Epoch: epoch,
|
||||
RlnIdentifier: [32]byte{0x00, 0x00, 0x00}, // TODO
|
||||
}
|
||||
|
||||
// generate proof
|
||||
proofRes, err := rln.GenerateRLNProofWithWitness(rlnWitness)
|
||||
s.NoError(err)
|
||||
|
||||
// verify the proof (should not be verified)
|
||||
verified, err := rln.Verify(msg, *proofRes, root)
|
||||
s.NoError(err)
|
||||
s.False(verified)
|
||||
}
|
||||
|
||||
func (s *RLNSuite) TestEpochConsistency() {
|
||||
// check edge cases
|
||||
var epoch uint64 = math.MaxUint64
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
package rln
|
||||
|
||||
import "encoding/binary"
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// serialize converts a RateLimitProof and the data to a byte seq
|
||||
// this conversion is used in the proofGen function
|
||||
@ -42,3 +47,82 @@ func (r RateLimitProof) serialize() []byte {
|
||||
proofBytes = append(proofBytes, r.RLNIdentifier[:]...)
|
||||
return proofBytes
|
||||
}
|
||||
|
||||
func (r *RLNWitnessInput) serialize() []byte {
|
||||
output := make([]byte, 0)
|
||||
|
||||
output = append(output, r.IdentityCredential.IDSecretHash[:]...)
|
||||
output = append(output, r.MerkleProof.serialize()...)
|
||||
output = append(output, appendLength(r.Data)...)
|
||||
output = append(output, r.Epoch[:]...)
|
||||
output = append(output, r.RlnIdentifier[:]...)
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func (r *MerkleProof) serialize() []byte {
|
||||
output := make([]byte, 0)
|
||||
|
||||
output = append(output, appendLength(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 output 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 output 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()))
|
||||
}
|
||||
|
||||
// TODO: Depth check, but currently not accesible
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
56
rln/serialize_test.go
Normal file
56
rln/serialize_test.go
Normal file
@ -0,0 +1,56 @@
|
||||
package rln
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"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) {
|
||||
|
||||
mProof := MerkleProof{
|
||||
PathElements: []MerkleNode{},
|
||||
PathIndexes: []uint8{},
|
||||
}
|
||||
|
||||
ser := mProof.serialize()
|
||||
//require.Equal(t, []byte{0, 0, 0, 0}, ser, )
|
||||
require.Equal(t, 16, len(ser))
|
||||
|
||||
mProof = MerkleProof{
|
||||
PathElements: []MerkleNode{[32]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}},
|
||||
PathIndexes: []uint8{0},
|
||||
}
|
||||
|
||||
ser = mProof.serialize()
|
||||
//require.Equal(t, []byte{0, 0, 0, 0}, ser, )
|
||||
require.Equal(t, 49, len(ser))
|
||||
|
||||
mProof = MerkleProof{}
|
||||
|
||||
for i := 0; i < 16; i++ {
|
||||
mProof.PathElements = append(mProof.PathElements, random32())
|
||||
mProof.PathIndexes = append(mProof.PathIndexes, uint8(i%2))
|
||||
}
|
||||
|
||||
ser = mProof.serialize()
|
||||
fmt.Println(ser)
|
||||
|
||||
desProof := MerkleProof{}
|
||||
err := desProof.deserialize(ser)
|
||||
require.NoError(t, err)
|
||||
|
||||
// TODO test for errors. eg different size.
|
||||
}
|
||||
|
||||
func TestRLNWitnessInputSerDe(t *testing.T) {
|
||||
|
||||
}
|
||||
@ -68,6 +68,14 @@ type MerkleProof struct {
|
||||
PathIndexes []uint8 `json:"pathIndexes"`
|
||||
}
|
||||
|
||||
type RLNWitnessInput struct {
|
||||
IdentityCredential IdentityCredential `json:"identityCredential"`
|
||||
MerkleProof MerkleProof `json:"merkleProof"`
|
||||
Data []byte `json:"data"`
|
||||
Epoch Epoch `json:"epoch"`
|
||||
RlnIdentifier RLNIdentifier `json:"rlnIdentifier"` // what is this? TOOD: app specific. which one is ours?
|
||||
}
|
||||
|
||||
type TreeDepth int
|
||||
|
||||
const (
|
||||
|
||||
@ -56,6 +56,14 @@ func Bytes128(b []byte) [128]byte {
|
||||
return result
|
||||
}
|
||||
|
||||
func Flatten(b [][32]byte) []byte {
|
||||
var result []byte
|
||||
for _, v := range b {
|
||||
result = append(result, v[:]...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func ToBytes32LE(hexStr string) ([32]byte, error) {
|
||||
|
||||
b, err := hex.DecodeString(hexStr)
|
||||
|
||||
@ -19,3 +19,5 @@ func TestBigInt(t *testing.T) {
|
||||
newValue := Bytes32ToBigInt(b32Value)
|
||||
require.True(t, bytes.Equal(newValue.Bytes(), value.Bytes()))
|
||||
}
|
||||
|
||||
// TODO: Test Flatten
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user