diff --git a/rln/rln.go b/rln/rln.go index d3bd8bd..80b5353 100644 --- a/rln/rln.go +++ b/rln/rln.go @@ -10,6 +10,10 @@ import ( "github.com/waku-org/go-zerokit-rln/rln/link" ) +// Same as: https://github.com/vacp2p/zerokit/blob/v0.3.5/rln/src/public.rs#L35 +// 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} + // RLN represents the context used for rln. type RLN struct { w *link.RLNWrapper @@ -130,17 +134,14 @@ func (r *RLN) SeededMembershipKeyGen(seed []byte) (*IdentityCredential, error) { // appendLength returns length prefixed version of the input with the following format // [len<8>|input], the len is a 8 byte value serialized in little endian - func appendLength(input []byte) []byte { inputLen := make([]byte, 8) binary.LittleEndian.PutUint64(inputLen, uint64(len(input))) 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 +// Similar to appendLength but for 32 byte values. The length that is prepended is +// the length of elements that are 32 bytes long each func appendLength32(input []byte) []byte { inputLen := make([]byte, 8) binary.LittleEndian.PutUint64(inputLen, uint64(len(input)/32)) @@ -242,32 +243,12 @@ func (r *RLN) GenerateProof(data []byte, key IdentityCredential, index Membershi }, nil } -// input : -/* -identity_secret: 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, -*/ -// todo: output same as other function. +// Returns a RLN proof with a custom witness, so no tree is required in the RLN instance +// to calculate such proof. The witness can be created with GetMerkleProof data +// input [ id_secret_hash<32> | num_elements<8> | path_elements | num_indexes<8> | path_indexes | 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> ] func (r *RLN) GenerateRLNProofWithWitness(witness RLNWitnessInput) (*RateLimitProof, error) { - // TODO: this shouldn go here but i think there is an issue in zerokit - fmt.Println("len data before ", len(witness.Data)) - // Remove its not a poseidon hash but kekkack - hashedData, err := r.Poseidon(witness.Data[:]) - if err != nil { - return nil, err - } - - //witness.Data = hashedData[:] - _ = hashedData - - fmt.Println("len data after ", len(witness.Data)) - proofBytes, err := r.w.GenerateRLNProofWithWitness(witness.serialize()) if err != nil { return nil, err @@ -277,7 +258,6 @@ func (r *RLN) GenerateRLNProofWithWitness(witness RLNWitnessInput) (*RateLimitPr 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 diff --git a/rln/rln_test.go b/rln/rln_test.go index e664531..5413524 100644 --- a/rln/rln_test.go +++ b/rln/rln_test.go @@ -355,6 +355,8 @@ func (s *RLNSuite) TestGenerateRLNProofWithWitness() { rln, err := NewRLN() s.NoError(err) + // TODO: Run multiple test with multiple indexes + // Leaf we generate the proof for memberIndex := uint(4) memKeys, err := rln.MembershipKeyGen() @@ -380,39 +382,30 @@ func (s *RLNSuite) TestGenerateRLNProofWithWitness() { // TODO: Add some asserts on roots fmt.Println("root from zerokit: ", root) - // Inputs for proof generation - msg := []byte("hi there") - var epoch = Epoch([32]byte{0x00, 0x00, 0x00, 0x00, 0x01}) - // We provide out custom witness merkleProof, err := rln.GetMerkleProof(memberIndex) s.NoError(err) - // TODO: This should be abstracted away, move inside somewhere - x := HashToBN255(msg) - - rlnWitness := RLNWitnessInput{ - // memberIndex key - IdentityCredential: *memKeys, - MerkleProof: merkleProof, - Data: x[:], // TODO: This is not really data, its a hash of data - Epoch: epoch, - 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 - } + message := []byte("some rln protected message") + epoch := ToEpoch(1000) + rlnWitness := CreateWitness( + *memKeys, + message, + epoch, + merkleProof) // Generate a proof with our custom witness (Merkle Path of the memberIndex) proofRes1, err := rln.GenerateRLNProofWithWitness(rlnWitness) s.NoError(err) - verified1, err := rln.Verify(msg[:], *proofRes1, root) + verified1, err := rln.Verify(message, *proofRes1, root) s.NoError(err) s.True(verified1) - proofRes2, err := rln.GenerateProof(msg[:], *memKeys, MembershipIndex(memberIndex), epoch) + proofRes2, err := rln.GenerateProof(message, *memKeys, MembershipIndex(memberIndex), epoch) s.NoError(err) // Proof generate with custom witness match the proof generate with the witness - // from zerokit - //s.Equal(proofRes1.Proof, proofRes2.Proof) // The proof itself can be different + // from zerokit. Proof itself is not asserted, can be different. s.Equal(proofRes1.MerkleRoot, proofRes2.MerkleRoot) s.Equal(proofRes1.Epoch, proofRes2.Epoch) s.Equal(proofRes1.ShareX, proofRes2.ShareX) diff --git a/rln/serialize.go b/rln/serialize.go index d46fd55..aad97d3 100644 --- a/rln/serialize.go +++ b/rln/serialize.go @@ -53,7 +53,7 @@ func (r *RLNWitnessInput) serialize() []byte { output = append(output, r.IdentityCredential.IDSecretHash[:]...) output = append(output, r.MerkleProof.serialize()...) - 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.X[:]...) output = append(output, r.Epoch[:]...) output = append(output, r.RlnIdentifier[:]...) @@ -115,8 +115,6 @@ func (r *MerkleProof) deserialize(b []byte) error { 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++ { diff --git a/rln/serialize_test.go b/rln/serialize_test.go index f8c9450..f810cdc 100644 --- a/rln/serialize_test.go +++ b/rln/serialize_test.go @@ -47,7 +47,6 @@ func TestMerkleProofSerDe(t *testing.T) { 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{ @@ -65,7 +64,7 @@ func TestRLNWitnessInputSerDe(t *testing.T) { IDSecretHash: random32(), }, MerkleProof: mProof, - Data: data[:], + X: [32]byte{0x00}, Epoch: ToEpoch(10), RlnIdentifier: [32]byte{0x00}, } diff --git a/rln/types.go b/rln/types.go index 17f299c..3d4b736 100644 --- a/rln/types.go +++ b/rln/types.go @@ -68,13 +68,14 @@ type MerkleProof struct { PathIndexes []uint8 `json:"pathIndexes"` } +// Equivalent: https://github.com/vacp2p/zerokit/blob/v0.3.5/rln/src/protocol.rs#L33-L40 type RLNWitnessInput struct { // TODO: Maybe dont store the whole IdentityCredential and just the secret IdentityCredential IdentityCredential `json:"identityCredential"` MerkleProof MerkleProof `json:"merkleProof"` // This is not the data but the hashed version of it "x"..TODO rename and reconsider - Data []byte `json:"data"` // TODO: this should be fixed 32 + X [32]byte `json:"x"` Epoch Epoch `json:"epoch"` RlnIdentifier RLNIdentifier `json:"rlnIdentifier"` // what is this? TOOD: app specific. which one is ours? } diff --git a/rln/utils.go b/rln/utils.go index c9ef403..8f3717e 100644 --- a/rln/utils.go +++ b/rln/utils.go @@ -8,6 +8,21 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) +func CreateWitness( + identityCredential IdentityCredential, // TODO only the secret hash. + data []byte, + epoch [32]byte, + merkleProof MerkleProof) RLNWitnessInput { + + return RLNWitnessInput{ + IdentityCredential: identityCredential, + MerkleProof: merkleProof, + X: HashToBN255(data), + Epoch: epoch, + RlnIdentifier: RLN_IDENTIFIER, + } +} + func ToIdentityCredentials(groupKeys [][]string) ([]IdentityCredential, error) { // groupKeys is sequence of membership key tuples in the form of (identity key, identity commitment) all in the hexadecimal format // the toIdentityCredentials proc populates a sequence of IdentityCredentials using the supplied groupKeys