-
Notifications
You must be signed in to change notification settings - Fork 108
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a381df5
commit d6fe349
Showing
1 changed file
with
173 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
package utils | ||
|
||
import ( | ||
"bytes" | ||
"encoding/hex" | ||
"fmt" | ||
"hash" | ||
"math/big" | ||
"strings" | ||
|
||
"github.com/NethermindEth/juno/core/felt" | ||
"golang.org/x/crypto/sha3" | ||
) | ||
|
||
// KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports | ||
// Read to get a variable amount of data from the hash state. Read is faster than Sum | ||
// because it doesn't copy the internal state, but also modifies the internal state. | ||
type KeccakState interface { | ||
hash.Hash | ||
Read([]byte) (int, error) | ||
} | ||
|
||
// Convert utf8 string to big int | ||
func UTF8StrToBig(str string) *big.Int { | ||
hexStr := hex.EncodeToString([]byte(str)) | ||
b, _ := new(big.Int).SetString(hexStr, 16) | ||
|
||
return b | ||
} | ||
|
||
// convert decimal string to big int | ||
func StrToBig(str string) *big.Int { | ||
b, _ := new(big.Int).SetString(str, 10) | ||
|
||
return b | ||
} | ||
|
||
// convert hex string to Starknet 'short string' | ||
func HexToShortStr(hexStr string) string { | ||
numStr := strings.Replace(hexStr, "0x", "", -1) | ||
hb, _ := new(big.Int).SetString(numStr, 16) | ||
|
||
return string(hb.Bytes()) | ||
} | ||
|
||
// trim "0x" prefix(if exists) and converts hexidecimal string to big int | ||
func HexToBN(hexString string) *big.Int { | ||
numStr := strings.Replace(hexString, "0x", "", -1) | ||
|
||
n, _ := new(big.Int).SetString(numStr, 16) | ||
return n | ||
} | ||
|
||
// trim "0x" prefix(if exists) and converts hexidecimal string to byte slice | ||
func HexToBytes(hexString string) ([]byte, error) { | ||
numStr := strings.Replace(hexString, "0x", "", -1) | ||
if (len(numStr) % 2) != 0 { | ||
numStr = fmt.Sprintf("%s%s", "0", numStr) | ||
} | ||
|
||
return hex.DecodeString(numStr) | ||
} | ||
|
||
func BytesToBig(bytes []byte) *big.Int { | ||
return new(big.Int).SetBytes(bytes) | ||
} | ||
|
||
// convert big int to hexidecimal string | ||
func BigToHex(in *big.Int) string { | ||
return fmt.Sprintf("0x%x", in) | ||
} | ||
|
||
// todo(): this is used by the signer. Should it return a felt? | ||
func GetSelectorFromName(funcName string) *big.Int { | ||
kec := Keccak256([]byte(funcName)) | ||
|
||
maskedKec := MaskBits(250, 8, kec) | ||
|
||
return new(big.Int).SetBytes(maskedKec) | ||
} | ||
|
||
func GetSelectorFromNameFelt(funcName string) *felt.Felt { | ||
kec := Keccak256([]byte(funcName)) | ||
|
||
maskedKec := MaskBits(250, 8, kec) | ||
|
||
return new(felt.Felt).SetBytes(maskedKec) | ||
} | ||
|
||
// Keccak256 calculates and returns the Keccak256 hash of the input data. | ||
// (ref: https://github.com/ethereum/go-ethereum/blob/master/crypto/crypto.go) | ||
func Keccak256(data ...[]byte) []byte { | ||
b := make([]byte, 32) | ||
d := NewKeccakState() | ||
for _, b := range data { | ||
d.Write(b) | ||
} | ||
d.Read(b) | ||
return b | ||
} | ||
|
||
// NewKeccakState creates a new KeccakState | ||
// (ref: https://github.com/ethereum/go-ethereum/blob/master/crypto/crypto.go) | ||
func NewKeccakState() KeccakState { | ||
return sha3.NewLegacyKeccak256().(KeccakState) | ||
} | ||
|
||
// mask excess bits | ||
func MaskBits(mask, wordSize int, slice []byte) (ret []byte) { | ||
excess := len(slice)*wordSize - mask | ||
for _, by := range slice { | ||
if excess > 0 { | ||
if excess > wordSize { | ||
excess = excess - wordSize | ||
continue | ||
} | ||
by <<= excess | ||
by >>= excess | ||
excess = 0 | ||
} | ||
ret = append(ret, by) | ||
} | ||
return ret | ||
} | ||
|
||
// compute the keccack fact given the program hash and outputs | ||
func ComputeFact(programHash *big.Int, programOutputs []*big.Int) *big.Int { | ||
var progOutBuf []byte | ||
for _, programOutput := range programOutputs { | ||
inBuf := FmtKecBytes(programOutput, 32) | ||
progOutBuf = append(progOutBuf[:], inBuf...) | ||
} | ||
|
||
kecBuf := FmtKecBytes(programHash, 32) | ||
kecBuf = append(kecBuf[:], Keccak256(progOutBuf)...) | ||
|
||
return new(big.Int).SetBytes(Keccak256(kecBuf)) | ||
} | ||
|
||
// split a fact into two felts | ||
func SplitFactStr(fact string) (fact_low, fact_high string) { | ||
factBN := HexToBN(fact) | ||
factBytes := factBN.Bytes() | ||
lpadfactBytes := bytes.Repeat([]byte{0x00}, 32-len(factBytes)) | ||
factBytes = append(lpadfactBytes, factBytes...) | ||
low := BytesToBig(factBytes[16:]) | ||
high := BytesToBig(factBytes[:16]) | ||
return BigToHex(low), BigToHex(high) | ||
} | ||
|
||
// format the bytes in Keccak hash | ||
func FmtKecBytes(in *big.Int, rolen int) (buf []byte) { | ||
buf = append(buf, in.Bytes()...) | ||
|
||
// pad with zeros if too short | ||
if len(buf) < rolen { | ||
padded := make([]byte, rolen) | ||
copy(padded[rolen-len(buf):], buf) | ||
|
||
return padded | ||
} | ||
|
||
return buf | ||
} | ||
|
||
// used in string conversions when interfacing with the APIs | ||
func SNValToBN(str string) *big.Int { | ||
if strings.Contains(str, "0x") { | ||
return HexToBN(str) | ||
} else { | ||
return StrToBig(str) | ||
} | ||
} |