From b3eea17cbaddeb7bab34ccd85bff6ba7b8640d68 Mon Sep 17 00:00:00 2001 From: Samuael A <39623015+samuael@users.noreply.github.com> Date: Thu, 17 Oct 2024 23:51:23 +0300 Subject: [PATCH] Working on rescue and other hash implementation --- internal/utils/hash/rescue_hash.go | 207 +++++++++++++++++++++++++ internal/utils/hash/rescue_test.go | 1 + internal/utils/hash/types.go | 20 +++ internal/utils/jubjub/jubjub.go | 26 +++- internal/utils/mathutils/math_utils.go | 20 --- internal/utils/zklink/zklink_types.go | 10 -- 6 files changed, 253 insertions(+), 31 deletions(-) create mode 100644 internal/utils/hash/rescue_hash.go create mode 100644 internal/utils/hash/rescue_test.go diff --git a/internal/utils/hash/rescue_hash.go b/internal/utils/hash/rescue_hash.go new file mode 100644 index 00000000000..4f69aa53fc8 --- /dev/null +++ b/internal/utils/hash/rescue_hash.go @@ -0,0 +1,207 @@ +package hash + +import ( + "crypto/cipher" + "encoding/binary" + "errors" + "fmt" + "log" + "math/big" + + "golang.org/x/crypto/blake2s" + "golang.org/x/crypto/chacha20poly1305" +) + +const PAD_MSG_BEFORE_HASH_BITS_LEN = 736 + +func RescueHashTransactionMsg(message *big.Int) (interface{}, error) { + // msgBits := BytesIntoBits(message) + if len(message.Bits()) <= PAD_MSG_BEFORE_HASH_BITS_LEN { + return nil, errors.New("invalid message") + } + // bits := BytesIntoBits(message.Bytes()) + return nil, nil +} + +func BytesIntoBits(message []byte) []bool { + msg := make([]bool, len(message)*8) + for _, b := range message { + x := b + for i := range 8 { + msg = append(msg, (x&(1< 0 { + bits = append(make([]bool, 8-(len(bits)%8)), bits...) + } + bytesMsg := make([]byte, int64(float64(len(bits)/8))) + start := 0 + for i := 0; i < len(bits); i += 8 { + var val uint8 + for _, b := range bits[start : i+8] { + if b { + val |= 1 + } + } + start += 8 + bytesMsg = append(bytesMsg, byte(val)) + } + return bytesMsg +} + +func RescueHashFr(input []bool) *big.Int { + // packed := ComputeMultiPacking(input) + // spotgeOutput := RescueHash() + return nil +} + +func ComputeMultiPacking(input []bool) []*big.Int { + if len(input)%8 > 0 { + input = append(make([]bool, 8-(len(input)%8)), input...) + } + result := []*big.Int{} + start := 0 + for i := 0; i < len(input); i += 8 { + cur := big.NewInt(0) + coeff := big.NewInt(1) + + sample := input[start : i+8] + + for _, b := range sample { + if b { + cur.Add(cur, coeff) + } + coeff.Mul(coeff, coeff) + } + result = append(result, cur) + start += 8 + } + return result +} + +func (b *Bn256RescueParams) NewCheck2Into1() (*Bn256RescueParams, error) { + c := uint32(1) + r := uint32(2) + round := uint32(22) + securityLevel := uint32(12) + return b.NewForParams(c, r, round, securityLevel) +} + +func (b *Bn256RescueParams) NewForParams(c, r, rounds, securityLevel uint32) (*Bn256RescueParams, error) { + stateWidth := c + r + numRoundConstants := int((1 + rounds*2) * stateWidth) + + roundConstants, err := func() ([]*big.Int, error) { + tag := []byte("Rescue_f") + roundConstants := make([]*big.Int, numRoundConstants) + nonce := uint32(0) + var nonceBytes []byte + + for { + binary.BigEndian.PutUint32(nonceBytes[:], nonce) + hasher, err := blake2s.New256(nil) + if err != nil { + return nil, err + } + // nonceBytes = []byte() + hasher.Write(tag) + hasher.Write(GH_FIRST_BLOCK) + hasher.Write(nonceBytes) + + hashData := hasher.Sum(nil) + if len(hashData) != 32 { + return nil, fmt.Errorf("expecting a hash length of 32 bytes, got a hash with length %d", len(hashData)) + } + + constantRepr := big.NewInt(0).SetBytes(hashData) + constant := constantRepr + if constant.Cmp(big.NewInt(0)) != 0 { + roundConstants = append(roundConstants, constant) + } + + if len(roundConstants) == numRoundConstants { + break + } + nonce += 1 + } + return roundConstants, nil + }() + if err != nil { + return nil, err + } + + mdsMatrix, err := func() ([]*big.Int, error) { + // This tag is a first one in a sequence of b"ResMxxxx" + // that produces MDS matrix without eigenvalues for rate = 2, + // capacity = 1 variant over Bn254 curve + tag := []byte("ResM0003") + rng, err := func() (cipher.AEAD, error) { + hasher, err := blake2s.New256(nil) + if err != nil { + return nil, err + } + // nonceBytes = []byte() + hasher.Write(tag) + hasher.Write(GH_FIRST_BLOCK) + hashData := hasher.Sum(nil) + if len(hashData) != 32 { + return nil, fmt.Errorf("expecting a hash length of 32 bytes, got a hash with length %d", len(hashData)) + } + var seed [8]uint32 + if len(hashData) < 32 { + return nil, errors.New("digest is not large enough") + } + // Populate the seed array from the byte slice + for i := 0; i < 8; i++ { + seed[i] = binary.BigEndian.Uint32(hashData[i*4 : i*4+4]) + } + + // Convert uint32 array to a byte slice for the seed + var byteSeed []byte + buf := make([]byte, 4) + for _, v := range seed { + binary.BigEndian.PutUint32(buf, v) + byteSeed = append(byteSeed, buf...) + } + + // Create a ChaCha20-Poly1305 cipher + aead, err := chacha20poly1305.NewX(byteSeed) + if err != nil { + log.Fatal("failed to create cipher:", err) + } + return aead, nil + }() + if err != nil { + return nil, err + } + // return rng, nil + // + // TODO: ... + // generatemdsMatrix() + println(rng) + return nil, nil + }() + return &Bn256RescueParams{ + C: c, + R: r, + Rounds: rounds, + SecurityLevel: securityLevel, + RoundConstants: roundConstants, + MDSMatrix: mdsMatrix, + CustomGatesAllowed: false, + }, nil +} + +type PowerSBox struct { + Power *big.Int + Inv uint64 +} + +type QuinticSBox struct { + Marker *big.Int +} diff --git a/internal/utils/hash/rescue_test.go b/internal/utils/hash/rescue_test.go new file mode 100644 index 00000000000..7adc22fef06 --- /dev/null +++ b/internal/utils/hash/rescue_test.go @@ -0,0 +1 @@ +package hash diff --git a/internal/utils/hash/types.go b/internal/utils/hash/types.go index d498f7ce2f6..40ecd52ec7b 100644 --- a/internal/utils/hash/types.go +++ b/internal/utils/hash/types.go @@ -2,6 +2,12 @@ package hash import "math/big" +// / First 64 bytes of the BLAKE2s input during group hash. +// / This is chosen to be some random string that we couldn't have anticipated when we designed +// / the algorithm, for rigidity purposes. +// / We deliberately use an ASCII hex string of 32 bytes here. +var GH_FIRST_BLOCK = []byte("096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0") + // PedersenCfg represents a pedersen hash configuration options type PedersenCfg struct { Comment string `json:"_comment"` @@ -12,3 +18,17 @@ type PedersenCfg struct { BETA *big.Int `json:"BETA"` ConstantPoints [][2]*big.Int `json:"CONSTANT_POINTS"` } + +// Bn256RescueParams represents capacity, rate of hash, and other details of the rescue hash algorithm +type Bn256RescueParams struct { + C uint32 + R uint32 + Rounds uint32 + SecurityLevel uint32 + RoundConstants []*big.Int + MDSMatrix []*big.Int + SBox0 *PowerSBox + SBox1 *QuinticSBox + + CustomGatesAllowed bool +} diff --git a/internal/utils/jubjub/jubjub.go b/internal/utils/jubjub/jubjub.go index cc9cb3c1afb..bc64e187b92 100644 --- a/internal/utils/jubjub/jubjub.go +++ b/internal/utils/jubjub/jubjub.go @@ -18,7 +18,31 @@ type AltJubJubBn256 struct { Montgometry2A *big.Int Scale *big.Int - // PedersenHashGenerators + PedersenHashGenerators []interface{} + PedersenHashExp []interface{} + PedersenCircuitGenerators []interface{} + FixedBaseGenerators []interface{} + FixedBaseCircuitGenerators []interface{} +} + +func NewAltJubJubBn256() *AltJubJubBn256 { + edwardsD, _ := big.NewInt(0).SetString("12181644023421730124874158521699555681764249180949974110617291017600649128846", 0) + montegomeryA := big.NewInt(168698) + + doubleMontgomery2A := new(big.Int).Mul(montegomeryA, montegomeryA) + scale, _ := big.NewInt(0).SetString("6360561867910373094066688120553762416144456282423235903351243436111059670888", 0) + + return &AltJubJubBn256{ + MontgometryA: montegomeryA, + EdwardsD: edwardsD, + Montgometry2A: doubleMontgomery2A, + Scale: scale, + PedersenHashGenerators: make([]interface{}, 0), + PedersenHashExp: make([]interface{}, 0), + PedersenCircuitGenerators: make([]interface{}, 0), + FixedBaseGenerators: make([]interface{}, 0), + FixedBaseCircuitGenerators: make([]interface{}, 0), + } } // const defaultJubjubConfigsPath = "internal/utils/hash/elliptic_curve_config/" diff --git a/internal/utils/mathutils/math_utils.go b/internal/utils/mathutils/math_utils.go index 7e130166269..3697ebaa70e 100644 --- a/internal/utils/mathutils/math_utils.go +++ b/internal/utils/mathutils/math_utils.go @@ -4,7 +4,6 @@ import ( "bytes" "crypto/sha256" "encoding/binary" - "errors" "fmt" "math/big" ) @@ -182,22 +181,3 @@ func GenerateKRfc6979(msgHash, priKey, ecOrder *big.Int, seed int) *big.Int { } return GenerateSecret(ecOrder, priKey, sha256.New, msgHash.Bytes(), extra) } - -const PAD_MSG_BEFORE_HASH_BITS_LEN = 736 - -func RescueHashTransactionMsg(message *big.Int) (interface{}, error) { - // msgBits := BytesIntoBits(message) - if len(message.Bits()) <= PAD_MSG_BEFORE_HASH_BITS_LEN { - return nil, errors.New("invalid message") - } - return nil, nil -} - -func BytesIntoBits(message []byte) *big.Int { - msg := new(big.Int) - for _, b := range message { - msg.Add(msg, big.NewInt(int64(b))) - msg.Lsh(msg, 8) - } - return msg -} diff --git a/internal/utils/zklink/zklink_types.go b/internal/utils/zklink/zklink_types.go index 8094c20754b..89cf3f53aad 100644 --- a/internal/utils/zklink/zklink_types.go +++ b/internal/utils/zklink/zklink_types.go @@ -83,13 +83,3 @@ type TransferBuilder struct { Nonce *big.Int Timestamp *big.Int } - -// Bn256RescueParams -type Bn256RescueParams struct { - C uint64 - R uint64 - Rounds uint64 - SecurityLevel uint64 - - CustomGatesAllowed bool -}