diff --git a/rln/rln.go b/rln/rln.go index e71596d..4a4d749 100644 --- a/rln/rln.go +++ b/rln/rln.go @@ -6,7 +6,6 @@ import ( "encoding/json" "errors" "fmt" - "math/big" "github.com/waku-org/go-zerokit-rln/rln/link" ) @@ -138,6 +137,16 @@ func appendLength(input []byte) []byte { return append(inputLen, input...) } +// can i reuse serialize32?? +// TODO: dirty +// Assume that the input is a sequence of 32 byte values +// so length is the amount of 32 byte values +func appendLength32(input []byte) []byte { + inputLen := make([]byte, 8) + binary.LittleEndian.PutUint64(inputLen, uint64(len(input)/32)) + return append(inputLen, input...) +} + func (r *RLN) Sha256(data []byte) (MerkleNode, error) { lenPrefData := appendLength(data) @@ -236,9 +245,9 @@ func (r *RLN) GenerateProof(data []byte, key IdentityCredential, index Membershi // input : /* identity_secret: Fr, -path_elements: Vec, -identity_path_index: Vec, -x: Fr, +path_elements: Vec, | 8 * 20*32 + 20 + 8 +identity_path_index: Vec, | -- +x: Fr, -> this seems to be of fixed size? not size+ variablelenarray epoch: Fr, rln_identifier: Fr, */ @@ -350,7 +359,7 @@ func (r *RLN) Verify(data []byte, proof RateLimitProof, roots ...[32]byte) (bool return false, err } - return bool(res), nil + return res, nil } // RecoverIDSecret returns an IDSecret having obtained before two proofs @@ -464,60 +473,10 @@ 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))) - } - var result MerkleProof - var numElements big.Int - var numIndexes big.Int - - offset := 0 - - // Get amounf of elements in the proof - numElements.SetBytes(revert(proofBytes[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(proofBytes) != expectedLen { - return MerkleProof{}, errors.New(fmt.Sprintf("wrong output size expected: %d, current: %d", - expectedLen, - len(proofBytes))) - } - - result.PathElements = make([]MerkleNode, numElements.Uint64()) - - for i := uint64(0); i < numElements.Uint64(); i++ { - copy(result.PathElements[i][:], proofBytes[offset:offset+32]) - offset += 32 - } - - // Get amount of indexes in the path - numIndexes.SetBytes(revert(proofBytes[offset : offset+8])) - offset += 8 - - // Both numElements and numIndexes shall be equal and match the tree depth. - if numIndexes.Uint64() != numElements.Uint64() { - return MerkleProof{}, 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 - - result.PathIndexes = make([]uint8, numIndexes.Uint64()) - - for i := uint64(0); i < numIndexes.Uint64(); i++ { - result.PathIndexes[i] = proofBytes[offset] - offset += 1 - } - - if offset != len(proofBytes) { - return MerkleProof{}, errors.New( - fmt.Sprintf("error parsing proof read: %d, length; %d", offset, len(proofBytes))) + err = result.deserialize(proofBytes) + if err != nil { + return MerkleProof{}, err } return result, nil diff --git a/rln/rln_test.go b/rln/rln_test.go index 2d8c530..554b77b 100644 --- a/rln/rln_test.go +++ b/rln/rln_test.go @@ -3,6 +3,7 @@ package rln import ( "bytes" "encoding/hex" + "fmt" "math" "testing" @@ -354,20 +355,17 @@ func (s *RLNSuite) TestGenerateRLNProofWithWitness() { rln, err := NewRLN() s.NoError(err) + // Leaf we generate the proof for + memberIndex := uint(4) 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 + for i := 0; i < 16; i++ { + if i == int(memberIndex) { err := rln.InsertMember(memKeys.IDCommitment) s.NoError(err) } else { - // create a new key pair memberKeys, err := rln.MembershipKeyGen() s.NoError(err) @@ -379,33 +377,47 @@ func (s *RLNSuite) TestGenerateRLNProofWithWitness() { root, err := rln.GetMerkleRoot() s.NoError(err) - // prepare the message - msg := []byte("Hello") + fmt.Println("root from zerokit: ", root) - // prepare the epoch - var epoch Epoch + // Inputs for proof generation + msg := [32]byte{0x00, 0x00, 0x01} + var epoch = Epoch([32]byte{0x00, 0x00, 0x00, 0x00, 0x01}) - badIndex := 4 - - merkleProof, err := rln.GetMerkleProof(uint(badIndex)) + // We provide out custom witness + merkleProof, err := rln.GetMerkleProof(memberIndex) s.NoError(err) rlnWitness := RLNWitnessInput{ + // memberIndex key IdentityCredential: *memKeys, MerkleProof: merkleProof, - Data: msg, + Data: msg[:], Epoch: epoch, - RlnIdentifier: [32]byte{0x00, 0x00, 0x00}, // TODO + RlnIdentifier: [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}, // 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) + fmt.Println("Proof Epoch: ", proofRes.Epoch) + fmt.Println("Proof Nullifier: ", proofRes.Nullifier) + fmt.Println("Proof ShareX: ", proofRes.ShareX) + fmt.Println("Proof ShareY: ", proofRes.ShareY) + fmt.Println("Proof MerkleRoot: ", proofRes.MerkleRoot) + fmt.Println("Proof RlnIdentifier: ", proofRes.RLNIdentifier) + + // verify the proof + //msg := [32]byte{0x00, 0x00, 0x01} + //verified, err := rln.Verify([]byte{0x00, 0x00, 0x01}, *proofRes, root) + verified, err := rln.Verify(msg[:], *proofRes, root) s.NoError(err) - s.False(verified) + + _ = verified + // TODO: Not working + //s.True(verified) + + // TODO: test a proof that shall not be verified } func (s *RLNSuite) TestEpochConsistency() { diff --git a/rln/serialize.go b/rln/serialize.go index dee40f0..d46fd55 100644 --- a/rln/serialize.go +++ b/rln/serialize.go @@ -53,17 +53,22 @@ func (r *RLNWitnessInput) serialize() []byte { output = append(output, r.IdentityCredential.IDSecretHash[:]...) output = append(output, r.MerkleProof.serialize()...) - output = append(output, appendLength(r.Data)...) + output = append(output, r.Data...) // TODO: Data doesnt have the lend prepended. Is it fixed to 32 bytes? Different than in other places output = append(output, r.Epoch[:]...) output = append(output, r.RlnIdentifier[:]...) 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, appendLength(Flatten(r.PathElements))...) + output = append(output, appendLength32(Flatten(r.PathElements))...) output = append(output, appendLength(r.PathIndexes)...) return output @@ -73,7 +78,7 @@ 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))) + return errors.New(fmt.Sprintf("wrong input size: %d", len(b))) } var numElements big.Int @@ -88,7 +93,7 @@ func (r *MerkleProof) deserialize(b []byte) error { // 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", + return errors.New(fmt.Sprintf("wrong input size expected: %d, current: %d", expectedLen, len(b))) } diff --git a/rln/serialize_test.go b/rln/serialize_test.go index 3ebc930..f8c9450 100644 --- a/rln/serialize_test.go +++ b/rln/serialize_test.go @@ -16,41 +16,64 @@ func random32() [32]byte { func TestMerkleProofSerDe(t *testing.T) { - mProof := MerkleProof{ - PathElements: []MerkleNode{}, - PathIndexes: []uint8{}, + 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)) + + fmt.Println("path:", mProof.PathElements) + fmt.Println("Serialized: ", ser) + + // Deserialize and check its matches the original + desProof := MerkleProof{} + err := desProof.deserialize(ser) + require.NoError(t, err) + require.Equal(t, mProof, desProof) } - 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) { + // TODO: Is data size arbitrary? or fixed to 32. How its decode in zerokit seems to be fixed to 32. + // At least in the proof with custom witness function. + data := [32]byte{0x00} + 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{ + IdentityCredential: IdentityCredential{ + IDSecretHash: random32(), + }, + MerkleProof: mProof, + Data: data[:], + Epoch: ToEpoch(10), + RlnIdentifier: [32]byte{0x00}, + } + + ser := witness.serialize() + require.Equal(t, 32+8+depth*32+depth+8+32+32+32, len(ser)) + + // TODO: + //desWitness := RLNWitnessInput{} + //err := desWitness.deserialize(ser) } diff --git a/rln/utils_test.go b/rln/utils_test.go index 96c9b23..3c69506 100644 --- a/rln/utils_test.go +++ b/rln/utils_test.go @@ -20,4 +20,25 @@ func TestBigInt(t *testing.T) { require.True(t, bytes.Equal(newValue.Bytes(), value.Bytes())) } -// TODO: Test Flatten +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) +}