diff --git a/go.mod b/go.mod index abccbfc..1a26b29 100644 --- a/go.mod +++ b/go.mod @@ -3,21 +3,22 @@ module github.com/waku-org/go-zerokit-rln go 1.19 require ( + github.com/consensys/gnark-crypto v0.12.1 github.com/ethereum/go-ethereum v1.13.10 github.com/stretchr/testify v1.8.4 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 - golang.org/x/crypto v0.18.0 ) require ( + github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/holiman/uint256 v1.2.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/crypto v0.18.0 // indirect golang.org/x/sys v0.16.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 01357c5..58039f3 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,10 @@ +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +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/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/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= @@ -11,11 +15,9 @@ github.com/ethereum/go-ethereum v1.13.10 h1:Ppdil79nN+Vc+mXfge0AuUgmKWuVv4eMqzoI github.com/ethereum/go-ethereum v1.13.10/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -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/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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= @@ -33,6 +35,5 @@ golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= 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 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/rln/rln_test.go b/rln/rln_test.go index fb6e6db..e664531 100644 --- a/rln/rln_test.go +++ b/rln/rln_test.go @@ -377,80 +377,51 @@ func (s *RLNSuite) TestGenerateRLNProofWithWitness() { root, err := rln.GetMerkleRoot() s.NoError(err) + // TODO: Add some asserts on roots fmt.Println("root from zerokit: ", root) // Inputs for proof generation - msg := [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0} - //msg := [32]byte{69, 7, 140, 46, 26, 131, 147, 30, 161, 68, 2, 5, 234, 195, 227, 223, 119, 187, 116, 97, 153, 70, 71, 254, 60, 149, 54, 109, 77, 79, 105, 20} + 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) - //hashMsg, err := rln.Poseidon(msg[:]) - //s.NoError(err) - hashMsg := [32]byte{69, 7, 140, 46, 26, 131, 147, 30, 161, 68, 2, 5, 234, 195, 227, 223, 119, 187, 116, 97, 153, 70, 71, 254, 60, 149, 54, 109, 77, 79, 105, 20} + // TODO: This should be abstracted away, move inside somewhere + x := HashToBN255(msg) rlnWitness := RLNWitnessInput{ // memberIndex key IdentityCredential: *memKeys, MerkleProof: merkleProof, - Data: hashMsg[:], + 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 } - fmt.Println("Witness secrethash ", rlnWitness.IdentityCredential.IDSecretHash) - fmt.Println("Witness merkle path", rlnWitness.MerkleProof.PathElements) - fmt.Println("Witness merkle indexes", rlnWitness.MerkleProof.PathIndexes) - fmt.Println("Witness data", rlnWitness.Data) - fmt.Println("Witness epoch", rlnWitness.Epoch) - fmt.Println("Witness rln identifier", rlnWitness.RlnIdentifier) - - // generate proof - proofRes, err := rln.GenerateRLNProofWithWitness(rlnWitness) + // Generate a proof with our custom witness (Merkle Path of the memberIndex) + proofRes1, err := rln.GenerateRLNProofWithWitness(rlnWitness) s.NoError(err) - - //proofRes.ShareX = dataToReplace - - fmt.Println("Proof Epoch: ", proofRes) - - // TODO: for testing. proof without witness (are proofs deterministic? maybe not) - proofRes2, err := rln.GenerateProof(msg[:], *memKeys, MembershipIndex(memberIndex), epoch) - s.NoError(err) - - fmt.Println("Proof1 Epoch: ", proofRes2.Epoch) - fmt.Println("Proof1 Nullifier: ", proofRes2.Nullifier) - fmt.Println("Proof1 ShareX: ", proofRes2.ShareX) - fmt.Println("Proof1 ShareY: ", proofRes2.ShareY) - fmt.Println("Proof1 MerkleRoot: ", proofRes2.MerkleRoot) - fmt.Println("Proof1 RlnIdentifier: ", proofRes2.RLNIdentifier) - - 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) - - // Verifty old proofs - verified1, err := rln.Verify(msg[:], *proofRes2, root) + verified1, err := rln.Verify(msg[:], *proofRes1, root) s.NoError(err) s.True(verified1) - // verify the proof with the witness - //msg := [32]byte{0x00, 0x00, 0x01} - //verified, err := rln.Verify([]byte{0x00, 0x00, 0x01}, *proofRes, root) - verified, err := rln.Verify(msg[:], *proofRes, root) + proofRes2, err := rln.GenerateProof(msg[:], *memKeys, MembershipIndex(memberIndex), epoch) s.NoError(err) - _ = verified - // TODO: Not working - s.True(verified) + // 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 + s.Equal(proofRes1.MerkleRoot, proofRes2.MerkleRoot) + s.Equal(proofRes1.Epoch, proofRes2.Epoch) + s.Equal(proofRes1.ShareX, proofRes2.ShareX) + s.Equal(proofRes1.ShareY, proofRes2.ShareY) + s.Equal(proofRes1.Nullifier, proofRes2.Nullifier) + s.Equal(proofRes1.RLNIdentifier, proofRes2.RLNIdentifier) // TODO: test a proof that shall not be verified + // TODO: generate multiple proofs with random data } func (s *RLNSuite) TestEpochConsistency() { diff --git a/rln/types.go b/rln/types.go index d329621..17f299c 100644 --- a/rln/types.go +++ b/rln/types.go @@ -74,7 +74,7 @@ type RLNWitnessInput struct { MerkleProof MerkleProof `json:"merkleProof"` // This is not the data but the hashed version of it "x"..TODO rename and reconsider - Data []byte `json:"data"` + Data []byte `json:"data"` // TODO: this should be fixed 32 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 14fe231..c9ef403 100644 --- a/rln/utils.go +++ b/rln/utils.go @@ -2,9 +2,9 @@ package rln import ( "encoding/hex" - "fmt" "math/big" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/ethereum/go-ethereum/crypto" ) @@ -110,38 +110,19 @@ func Bytes32ToBigInt(value [32]byte) *big.Int { return result } -func EndianConvertTODO(data []byte) [32]byte { +// Hashes a byte array to a field element in BN254, as used by zerokit. +// Equivalent to: https://github.com/vacp2p/zerokit/blob/v0.3.4/rln/src/hashers.rs +func HashToBN255(data []byte) [32]byte { + // Hash is fixed to 32 bytes + hashed := crypto.Keccak256(data[:]) - hashGoEth := crypto.Keccak256(data[:]) - _ = hashGoEth - //if len(hashGoEth) != 32 { - // fmt.Println("errorrrrrr") - // } - myHash32 := [32]byte{} - // copy(myHash32[:], hashGoEth) + // Convert to field element + var frBN254 fr.Element + frBN254.Unmarshal(revert(hashed)) + frBN254Bytes := frBN254.Bytes() - // el hash esta controlado por ahora - copy(myHash32[:], data) - - fmt.Println("inpit is: ", data) - fmt.Println("hash is: ", myHash32) - - var uintVals [4]uint64 - - for i := 0; i < 4; i++ { - chunk := make([]byte, 8) - copy(chunk, myHash32[i*8:(i+1)*8]) - fmt.Println("chunk is: ", chunk) - - myBig := new(big.Int) - myBig.SetBytes(revert(chunk)) - fmt.Println("big is: ", myBig) - uintVals[i] = myBig.Uint64() - } - - fmt.Println("uintVals is: ", uintVals) - - returnthis := [32]byte{} - - return returnthis + // Return fixed size + fixexLen := [32]byte{} + copy(fixexLen[:], revert(frBN254Bytes[:])) + return fixexLen } diff --git a/rln/utils_test.go b/rln/utils_test.go index 1f924fa..e8ba168 100644 --- a/rln/utils_test.go +++ b/rln/utils_test.go @@ -4,8 +4,6 @@ import ( "bytes" "fmt" "math/big" - "strconv" - "strings" "testing" "github.com/stretchr/testify/require" @@ -45,100 +43,13 @@ func TestFlatten(t *testing.T) { out3 := Flatten(in3) require.Equal(t, expected3, out3) } - -func TestTODO(t *testing.T) { +func TestHashToBN255(t *testing.T) { // Inputs for proof generation - msg := []byte{72, 7, 140, 254, 213, 99, 57, 234, 84, 150, 46, 114, 195, 124, 127, 88, 143, 196, 248, 229, 188, 23, 56, 39, 186, 117, 203, 16, 166, 58, 150, 165} + msg := []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - conv := EndianConvertTODO(msg) - - fmt.Println(conv) - - ints := []uint64{16877630849297418056, 6376952776256034388, 2826034866254562447, 11931788747685459386} - - fmt.Println(ints[0]) - - str := "" - for i, _ := range ints { - str = str + padBinaryString(uint64ToBinaryString(ints[4-i-1]), 64) - } - - fmt.Println("-- ", str) - - byteArray, err := binaryStringToBytes(str) - if err != nil { - fmt.Println("Error:", err) - return - } - - myBigInt := new(big.Int) - myBigInt.SetBytes(byteArray[:]) - - fmt.Println("mybigint", myBigInt.String()) - - fmt.Println(byteArray) - - // Expected - // in := [32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0} - // hashed: []byte{72, 7, 140, 254, 213, 99, 57, 234, 84, 150, 46, 114, 195, 124, 127, 88, 143, 196, 248, 229, 188, 23, 56, 39, 186, 117, 203, 16, 166, 58, 150, 165} - // expected := [32]byte{69, 7, 140, 46, 26, 131, 147, 30, 161, 68, 2, 5, 234, 195, 227, 223, 119, 187, 116, 97, 153, 70, 71, 254, 60, 149, 54, 109, 77, 79, 105, 20} -} - -func reverseString(input string) string { - // Convert string to a slice of runes - runes := []rune(input) - - // Reverse the order of runes - for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { - runes[i], runes[j] = runes[j], runes[i] - } - - // Convert the slice of runes back to a string - reversedString := string(runes) - - return reversedString -} - -func binaryStringToBytes(binaryString string) ([32]byte, error) { - var byteArray [32]byte - - // Ensure the binary string has 256 bits (32 bytes) - if len(binaryString) != 256 { - return byteArray, fmt.Errorf("binary string must have exactly 256 bits") - } - - // Iterate over 32 chunks of 8 bits each and parse them to bytes - for i := 0; i < 32; i++ { - startIndex := i * 8 - endIndex := startIndex + 8 - bits := binaryString[startIndex:endIndex] - - // Parse the 8-bit chunk to a byte - byteValue, err := strconv.ParseUint(bits, 2, 8) - if err != nil { - return byteArray, err - } - - byteArray[i] = byte(byteValue) - } - - return byteArray, nil -} - -func padBinaryString(binaryString string, length int) string { - // Calculate padding length - paddingLength := length - len(binaryString) - - // Pad with zeros - paddedBinaryString := strings.Repeat("0", paddingLength) + binaryString - - return paddedBinaryString -} - -func bigIntToBinaryString(num *big.Int) string { - return fmt.Sprintf("%b", num) -} - -func uint64ToBinaryString(num uint64) string { - return strconv.FormatUint(num, 2) + out := HashToBN255(msg) + fmt.Println("out: ", out) + require.Equal(t, + [32]byte{69, 7, 140, 46, 26, 131, 147, 30, 161, 68, 2, 5, 234, 195, 227, 223, 119, 187, 116, 97, 153, 70, 71, 254, 60, 149, 54, 109, 77, 79, 105, 20}, + out) }