Skip to content

Commit

Permalink
Add Jun hash code and update some tests
Browse files Browse the repository at this point in the history
  • Loading branch information
thiagodeev committed Aug 8, 2024
1 parent 0cf4b31 commit 5ea1f16
Show file tree
Hide file tree
Showing 12 changed files with 288 additions and 418 deletions.
42 changes: 12 additions & 30 deletions account/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/NethermindEth/juno/core/crypto"
"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/starknet.go/contracts"
"github.com/NethermindEth/starknet.go/curve"
"github.com/NethermindEth/starknet.go/hash"
"github.com/NethermindEth/starknet.go/rpc"
"github.com/NethermindEth/starknet.go/utils"
Expand Down Expand Up @@ -180,10 +181,7 @@ func (account *Account) TransactionHashDeployAccount(tx rpc.DeployAccountType, c
case rpc.DeployAccountTxn:
calldata := []*felt.Felt{txn.ClassHash, txn.ContractAddressSalt}
calldata = append(calldata, txn.ConstructorCalldata...)
calldataHash, err := hash.ComputeHashOnElementsFelt(calldata)
if err != nil {
return nil, err
}
calldataHash := curve.ComputeHashOnElementsFelt(calldata)

versionFelt, err := new(felt.Felt).SetString(string(txn.Version))
if err != nil {
Expand All @@ -200,7 +198,7 @@ func (account *Account) TransactionHashDeployAccount(tx rpc.DeployAccountType, c
txn.MaxFee,
account.ChainId,
[]*felt.Felt{txn.Nonce},
)
), nil
case rpc.DeployAccountTxnV3:
if txn.Version == "" || txn.ResourceBounds == (rpc.ResourceBoundsMapping{}) || txn.Nonce == nil || txn.PayMasterData == nil {
return nil, ErrNotAllParametersSet
Expand Down Expand Up @@ -265,11 +263,7 @@ func (account *Account) TransactionHashInvoke(tx rpc.InvokeTxnType) (*felt.Felt,
return nil, ErrNotAllParametersSet
}

calldataHash, err := hash.ComputeHashOnElementsFelt(txn.Calldata)
if err != nil {
return nil, err
}

calldataHash := curve.ComputeHashOnElementsFelt(txn.Calldata)
txnVersionFelt, err := new(felt.Felt).SetString(string(txn.Version))
if err != nil {
return nil, err
Expand All @@ -283,17 +277,14 @@ func (account *Account) TransactionHashInvoke(tx rpc.InvokeTxnType) (*felt.Felt,
txn.MaxFee,
account.ChainId,
[]*felt.Felt{},
)
), nil

case rpc.InvokeTxnV1:
if txn.Version == "" || len(txn.Calldata) == 0 || txn.Nonce == nil || txn.MaxFee == nil || txn.SenderAddress == nil {
return nil, ErrNotAllParametersSet
}

calldataHash, err := hash.ComputeHashOnElementsFelt(txn.Calldata)
if err != nil {
return nil, err
}
calldataHash := curve.ComputeHashOnElementsFelt(txn.Calldata)
txnVersionFelt, err := new(felt.Felt).SetString(string(txn.Version))
if err != nil {
return nil, err
Expand All @@ -307,7 +298,7 @@ func (account *Account) TransactionHashInvoke(tx rpc.InvokeTxnType) (*felt.Felt,
txn.MaxFee,
account.ChainId,
[]*felt.Felt{txn.Nonce},
)
), nil
case rpc.InvokeTxnV3:
// https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-8.md#protocol-changes
if txn.Version == "" || txn.ResourceBounds == (rpc.ResourceBoundsMapping{}) || len(txn.Calldata) == 0 || txn.Nonce == nil || txn.SenderAddress == nil || txn.PayMasterData == nil || txn.AccountDeploymentData == nil {
Expand Down Expand Up @@ -398,10 +389,7 @@ func (account *Account) TransactionHashDeclare(tx rpc.DeclareTxnType) (*felt.Fel
return nil, ErrNotAllParametersSet
}

calldataHash, err := hash.ComputeHashOnElementsFelt([]*felt.Felt{txn.ClassHash})
if err != nil {
return nil, err
}
calldataHash := curve.ComputeHashOnElementsFelt([]*felt.Felt{txn.ClassHash})

txnVersionFelt, err := new(felt.Felt).SetString(string(txn.Version))
if err != nil {
Expand All @@ -416,16 +404,13 @@ func (account *Account) TransactionHashDeclare(tx rpc.DeclareTxnType) (*felt.Fel
txn.MaxFee,
account.ChainId,
[]*felt.Felt{txn.Nonce},
)
), nil
case rpc.DeclareTxnV2:
if txn.CompiledClassHash == nil || txn.SenderAddress == nil || txn.Version == "" || txn.ClassHash == nil || txn.MaxFee == nil || txn.Nonce == nil {
return nil, ErrNotAllParametersSet
}

calldataHash, err := hash.ComputeHashOnElementsFelt([]*felt.Felt{txn.ClassHash})
if err != nil {
return nil, err
}
calldataHash := curve.ComputeHashOnElementsFelt([]*felt.Felt{txn.ClassHash})

txnVersionFelt, err := new(felt.Felt).SetString(string(txn.Version))
if err != nil {
Expand All @@ -440,7 +425,7 @@ func (account *Account) TransactionHashDeclare(tx rpc.DeclareTxnType) (*felt.Fel
txn.MaxFee,
account.ChainId,
[]*felt.Felt{txn.Nonce, txn.CompiledClassHash},
)
), nil
case rpc.DeclareTxnV3:
// https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-8.md#protocol-changes
if txn.Version == "" || txn.ResourceBounds == (rpc.ResourceBoundsMapping{}) || txn.Nonce == nil || txn.SenderAddress == nil || txn.PayMasterData == nil || txn.AccountDeploymentData == nil ||
Expand Down Expand Up @@ -495,10 +480,7 @@ func (account *Account) TransactionHashDeclare(tx rpc.DeclareTxnType) (*felt.Fel
// - *felt.Felt: the precomputed address as a *felt.Felt
// - error: an error if any
func (account *Account) PrecomputeAccountAddress(salt *felt.Felt, classHash *felt.Felt, constructorCalldata []*felt.Felt) (*felt.Felt, error) {
result, err := contracts.PrecomputeAddress(&felt.Zero, salt, classHash, constructorCalldata)
if err != nil {
return nil, err
}
result := contracts.PrecomputeAddress(&felt.Zero, salt, classHash, constructorCalldata)

return result, nil
}
Expand Down
19 changes: 6 additions & 13 deletions contracts/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/starknet.go/curve"
"github.com/NethermindEth/starknet.go/utils"
)

var PREFIX_CONTRACT_ADDRESS = new(felt.Felt).SetBytes([]byte("STARKNET_CONTRACT_ADDRESS"))
Expand Down Expand Up @@ -61,23 +60,17 @@ func UnmarshalCasmClass(filePath string) (*CasmClass, error) {
// - constructorCalldata: the constructor calldata
// Returns:
// - *felt.Felt: the precomputed address as a *felt.Felt
// - error: an error if any
func PrecomputeAddress(deployerAddress *felt.Felt, salt *felt.Felt, classHash *felt.Felt, constructorCalldata []*felt.Felt) (*felt.Felt, error) {
func PrecomputeAddress(deployerAddress *felt.Felt, salt *felt.Felt, classHash *felt.Felt, constructorCalldata []*felt.Felt) *felt.Felt {

bigIntArr := utils.FeltArrToBigIntArr([]*felt.Felt{
feltArr := []*felt.Felt{
PREFIX_CONTRACT_ADDRESS,
deployerAddress,
salt,
classHash,
})
}

constructorCalldataBigIntArr := utils.FeltArrToBigIntArr(constructorCalldata)
constructorCallDataHashInt, _ := curve.Curve.ComputeHashOnElements(constructorCalldataBigIntArr)
bigIntArr = append(bigIntArr, constructorCallDataHashInt)
constructorCallDataHash := curve.ComputeHashOnElementsFelt(constructorCalldata)
feltArr = append(feltArr, constructorCallDataHash)

preBigInt, err := curve.Curve.ComputeHashOnElements(bigIntArr)
if err != nil {
return nil, err
}
return utils.BigIntToFelt(preBigInt), nil
return curve.ComputeHashOnElementsFelt(feltArr)
}
8 changes: 3 additions & 5 deletions contracts/contracts_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package contracts_test
package contracts

import (
"encoding/json"
"os"
"testing"

"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/starknet.go/contracts"
"github.com/NethermindEth/starknet.go/rpc"
"github.com/NethermindEth/starknet.go/utils"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -46,7 +45,7 @@ func TestUnmarshalContractClass(t *testing.T) {
//
// none
func TestUnmarshalCasmClass(t *testing.T) {
casmClass, err := contracts.UnmarshalCasmClass("./tests/hello_starknet_compiled.casm.json")
casmClass, err := UnmarshalCasmClass("./tests/hello_starknet_compiled.casm.json")
require.NoError(t, err)
assert.Equal(t, casmClass.Prime, "0x800000000000011000000000000000000000000000000000000000000000001")
assert.Equal(t, casmClass.Version, "2.1.0")
Expand Down Expand Up @@ -106,13 +105,12 @@ func TestPrecomputeAddress(t *testing.T) {
}

for _, test := range testSet {
precomputedAddress, err := contracts.PrecomputeAddress(
precomputedAddress := PrecomputeAddress(
utils.TestHexToFelt(t, test.DeployerAddress),
utils.TestHexToFelt(t, test.Salt),
utils.TestHexToFelt(t, test.ClassHash),
test.ConstructorCalldata,
)
require.NoError(t, err)
require.Equal(t, test.ExpectedPrecomputedAddress, precomputedAddress.String())
}
}
111 changes: 46 additions & 65 deletions curve/curve.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (

junoCrypto "github.com/NethermindEth/juno/core/crypto"
"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/starknet.go/utils"
)

var Curve StarkCurve
Expand Down Expand Up @@ -520,101 +521,81 @@ func (sc StarkCurve) SignFelt(msgHash, privKey *felt.Felt) (*felt.Felt, *felt.Fe
return xFelt, yFelt, nil
}

// HashElements calculates the hash of a list of elements using the StarkCurve struct and a golang Pedersen Hash.
// (ref: https://github.com/seanjameshan/starknet.js/blob/main/src/utils/ellipticCurve.ts)
//
// HashElements calculates the hash of a list of elements using a golang Pedersen Hash.
// Parameters:
// - elems: slice of big.Int pointers to be hashed
// Returns:
// - hash: The hash of the list of elements
// - err: An error if any
func (sc StarkCurve) HashElements(elems []*big.Int) (hash *big.Int, err error) {
func HashElements(elems []*big.Int) (hash *big.Int) {
feltArr := utils.BigIntArrToFeltArr(elems)
if len(elems) == 0 {
elems = append(elems, big.NewInt(0))
feltArr = append(feltArr, new(felt.Felt))
}

hash = big.NewInt(0)
for _, h := range elems {
hash, err = sc.PedersenHash([]*big.Int{hash, h})
if err != nil {
return hash, err
}
feltHash := new(felt.Felt)
for _, felt := range feltArr {
feltHash = Pedersen(feltHash, felt)
}
return hash, err

hash = utils.FeltToBigInt(feltHash)
return
}

// ComputeHashOnElements computes the hash on the given elements using a golang Pedersen Hash implementation.
// (ref: https://github.com/starkware-libs/cairo-lang/blob/13cef109cd811474de114925ee61fd5ac84a25eb/src/starkware/cairo/common/hash_state.py#L6)
//
// The function appends the length of `elems` to the slice and then calls the `HashElements` method of the
// `Curve` struct, passing in `elems` as an argument. The resulting hash and
// any error that occurred during computation are returned.
// The function appends the length of `elems` to the slice and then calls the `HashElements` method
// passing in `elems` as an argument. The resulting hash is returned.
//
// Parameters:
// - elems: slice of big.Int pointers to be hashed
// Returns:
// - hash: The hash of the list of elements
// - err: An error if any
func (sc StarkCurve) ComputeHashOnElements(elems []*big.Int) (hash *big.Int, err error) {
func ComputeHashOnElements(elems []*big.Int) (hash *big.Int) {
elems = append(elems, big.NewInt(int64(len(elems))))
return Curve.HashElements((elems))
return HashElements(elems)
}

// PedersenHash calculates the Pedersen hash of the given elements.
// NOTE: This function assumes the curve has been initialized with constant points
// (ref: https://github.com/seanjameshan/starknet.js/blob/main/src/utils/ellipticCurve.ts)
//
// The function requires that the precomputed constant points have been initiated.
// If the length of `sc.ConstantPoints` is zero, an error is returned.
// The function iterates over the elements in `elems` and performs the Pedersen hash calculation.
// For each element, it checks if the value is within the valid range.
// If the value is invalid, an error is returned.
// For each bit in the element, the function performs an addition operation on `ptx` and `pty`
// using the corresponding constant point from the precomputed constant points.
// If the constant point is a duplicate of `ptx`, an error is returned.
// The function returns the resulting hash and a nil error if the calculation is successful.
// Otherwise, it returns `ptx` and an error describing the issue encountered.
// ComputeHashOnElementsFelt computes the hash on elements of a Felt array.
// Does the same as ComputeHashOnElements, but receives and returns felt types.
//
// Parameters:
// - elems: An array of big integers representing the elements to hash.
// - feltArr: A pointer to an array of Felt objects.
// Returns:
// - hash: The resulting Pedersen hash as a big integer.
// - err: An error, if any, encountered during the calculation.
func (sc StarkCurve) PedersenHash(elems []*big.Int) (hash *big.Int, err error) {
if len(sc.ConstantPoints) == 0 {
return hash, fmt.Errorf("must initiate precomputed constant points")
}

ptx := new(big.Int).Set(sc.Gx)
pty := new(big.Int).Set(sc.Gy)
for i, elem := range elems {
x := new(big.Int).Set(elem)

if x.Cmp(big.NewInt(0)) == -1 || x.Cmp(sc.P) >= 0 {
return ptx, fmt.Errorf("invalid x: %v", x)
}
// - *felt.Felt: a pointer to a Felt object
func ComputeHashOnElementsFelt(feltArr []*felt.Felt) *felt.Felt {
return PedersenArray(feltArr...)
}

for j := 0; j < 252; j++ {
idx := 2 + (i * 252) + j
xin := new(big.Int).Set(sc.ConstantPoints[idx][0])
yin := new(big.Int).Set(sc.ConstantPoints[idx][1])
if xin.Cmp(ptx) == 0 {
return hash, fmt.Errorf("constant point duplication: %v %v", ptx, xin)
}
if x.Bit(0) == 1 {
ptx, pty = sc.Add(ptx, pty, xin, yin)
}
x = x.Rsh(x, 1)
}
}
// Pedersen is a function that implements the Pedersen hash.
// NOTE: This function just wraps the Juno implementation
// (ref: https://github.com/NethermindEth/juno/blob/32fd743c774ec11a1bb2ce3dceecb57515f4873e/core/crypto/pedersen_hash.go#L20)
//
// Parameters:
// - a: a pointers to felt.Felt to be hashed.
// - b: a pointers to felt.Felt to be hashed.
// Returns:
// - *felt.Felt: a pointer to a felt.Felt storing the resulting hash.
func Pedersen(a, b *felt.Felt) *felt.Felt {
return junoCrypto.Pedersen(a, b)
}

return ptx, nil
// PedersenArray is a function that takes a variadic number of felt.Felt pointers as parameters and
// calls the PedersenArray function from the junoCrypto package with the provided parameters.
// NOTE: This function just wraps the Juno implementation
// (ref: https://github.com/NethermindEth/juno/blob/32fd743c774ec11a1bb2ce3dceecb57515f4873e/core/crypto/pedersen_hash.go#L12)
//
// Parameters:
// - felts: A variadic number of pointers to felt.Felt
// Returns:
// - *felt.Felt: pointer to a felt.Felt
func PedersenArray(felts ...*felt.Felt) *felt.Felt {
return junoCrypto.PedersenArray(felts...)
}

// PoseidonArray is a function that takes a variadic number of felt.Felt pointers as parameters and
// calls the PoseidonArray function from the junoCrypto package with the provided parameters.
// NOTE: This function just wraps the Juno implementation
// (ref: https://github.com/NethermindEth/juno/blob/main/core/crypto/poseidon_hash.go#L74)
// calls the PoseidonArray function from the junoCrypto package with the provided parameters.
//
// Parameters:
// - felts: A variadic number of pointers to felt.Felt
Expand Down
Loading

0 comments on commit 5ea1f16

Please sign in to comment.