mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 03:16:45 +01:00
Add HashGlobalInputs for ZKInputs
Add HashGlobalInputs for ZKInputs compatible with js & circom circuits version.
Compatible with hermeznetwork/commonjs at version: c6a1448db5bae4cda839ce36c1f35d8defccc9cd
(c6a1448db5)
This commit is contained in:
@@ -125,11 +125,13 @@ type Account struct {
|
||||
|
||||
func (a *Account) String() string {
|
||||
buf := bytes.NewBufferString("")
|
||||
fmt.Fprintf(buf, "Idx: %v, ", a.Idx)
|
||||
fmt.Fprintf(buf, "PublicKey: %s..., ", a.PublicKey.String()[:10])
|
||||
fmt.Fprintf(buf, "EthAddr: %s..., ", a.EthAddr.String()[:10])
|
||||
fmt.Fprintf(buf, "TokenID: %v, ", a.TokenID)
|
||||
fmt.Fprintf(buf, "Nonce: %d, ", a.Nonce)
|
||||
fmt.Fprintf(buf, "Balance: %s, ", a.Balance.String())
|
||||
fmt.Fprintf(buf, "BatchNum: %v, ", a.BatchNum)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
|
||||
@@ -153,9 +153,11 @@ func (tx L1Tx) Tx() Tx {
|
||||
func (tx *L1Tx) BytesGeneric() ([]byte, error) {
|
||||
var b [L1UserTxBytesLen]byte
|
||||
copy(b[0:20], tx.FromEthAddr.Bytes())
|
||||
pkCompL := tx.FromBJJ.Compress()
|
||||
pkCompB := SwapEndianness(pkCompL[:])
|
||||
copy(b[20:52], pkCompB[:])
|
||||
if tx.FromBJJ != nil {
|
||||
pkCompL := tx.FromBJJ.Compress()
|
||||
pkCompB := SwapEndianness(pkCompL[:])
|
||||
copy(b[20:52], pkCompB[:])
|
||||
}
|
||||
fromIdxBytes, err := tx.FromIdx.Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -104,7 +104,7 @@ func L2TxsToPoolL2Txs(txs []L2Tx) []PoolL2Tx {
|
||||
}
|
||||
|
||||
// Bytes encodes a L2Tx into []byte
|
||||
func (tx *L2Tx) Bytes(nLevels int) ([]byte, error) {
|
||||
func (tx L2Tx) Bytes(nLevels uint32) ([]byte, error) {
|
||||
idxLen := nLevels / 8 //nolint:gomnd
|
||||
|
||||
b := make([]byte, ((nLevels*2)+16+8)/8) //nolint:gomnd
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
|
||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||
)
|
||||
|
||||
// SwapEndianness swaps the order of the bytes in the slice.
|
||||
@@ -19,3 +21,18 @@ func SwapEndianness(b []byte) []byte {
|
||||
func EthAddrToBigInt(a ethCommon.Address) *big.Int {
|
||||
return new(big.Int).SetBytes(a.Bytes())
|
||||
}
|
||||
|
||||
// BJJFromStringWithChecksum parses a hex string in Hermez format (which has
|
||||
// the Hermez checksum at the last byte, and is encoded in BigEndian) and
|
||||
// returns the corresponding *babyjub.PublicKey. This method is not part of the
|
||||
// spec, is used for importing javascript test vectors data.
|
||||
func BJJFromStringWithChecksum(s string) (*babyjub.PublicKey, error) {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkBytes := SwapEndianness(b)
|
||||
var pkComp babyjub.PublicKeyComp
|
||||
copy(pkComp[:], pkBytes[:])
|
||||
return pkComp.Decompress()
|
||||
}
|
||||
|
||||
21
common/utils_test.go
Normal file
21
common/utils_test.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBJJFromStringWithChecksum(t *testing.T) {
|
||||
s := "21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7"
|
||||
pk, err := BJJFromStringWithChecksum(s)
|
||||
assert.Nil(t, err)
|
||||
sBytes, err := hex.DecodeString(s)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, hex.EncodeToString(SwapEndianness(sBytes)), pk.Compress().String())
|
||||
|
||||
// expected values computed with js implementation
|
||||
assert.Equal(t, "2492816973395423007340226948038371729989170225696553239457870892535792679622", pk.X.String())
|
||||
assert.Equal(t, "15238403086306505038849621710779816852318505119327426213168494964113886299863", pk.Y.String())
|
||||
}
|
||||
127
common/zk.go
127
common/zk.go
@@ -3,10 +3,15 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/hermeznetwork/hermez-node/log"
|
||||
cryptoConstants "github.com/iden3/go-iden3-crypto/constants"
|
||||
"github.com/iden3/go-merkletree"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
@@ -21,6 +26,8 @@ type ZKMetadata struct {
|
||||
MaxLevels uint32
|
||||
// absolute maximum of L1 transaction allowed
|
||||
MaxL1Tx uint32
|
||||
// total txs allowed
|
||||
MaxTx uint32
|
||||
// Maximum number of Idxs where Fees can be send in a batch (currently
|
||||
// is constant for all circuits: 64)
|
||||
MaxFeeIdxs uint32
|
||||
@@ -28,6 +35,10 @@ type ZKMetadata struct {
|
||||
L1TxsData [][]byte
|
||||
L2TxsData [][]byte
|
||||
ChainID uint16
|
||||
|
||||
NewLastIdxRaw Idx
|
||||
NewStateRootRaw *merkletree.Hash
|
||||
NewExitRootRaw *merkletree.Hash
|
||||
}
|
||||
|
||||
// ZKInputs represents the inputs that will be used to generate the zkSNARK proof
|
||||
@@ -250,11 +261,14 @@ func (z ZKInputs) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
// NewZKInputs returns a pointer to an initialized struct of ZKInputs
|
||||
func NewZKInputs(nTx, maxFeeIdxs, nLevels int) *ZKInputs {
|
||||
func NewZKInputs(nTx, maxL1Tx, maxTx, maxFeeIdxs, nLevels uint32) *ZKInputs {
|
||||
zki := &ZKInputs{}
|
||||
zki.Metadata.NTx = uint32(nTx)
|
||||
zki.Metadata.MaxFeeIdxs = uint32(maxFeeIdxs)
|
||||
zki.Metadata.NLevels = uint32(nLevels)
|
||||
zki.Metadata.NTx = nTx
|
||||
zki.Metadata.MaxFeeIdxs = maxFeeIdxs
|
||||
zki.Metadata.NLevels = nLevels
|
||||
zki.Metadata.MaxLevels = uint32(48) //nolint:gomnd
|
||||
zki.Metadata.MaxL1Tx = maxL1Tx
|
||||
zki.Metadata.MaxTx = maxTx
|
||||
|
||||
// General
|
||||
zki.OldLastIdx = big.NewInt(0)
|
||||
@@ -359,10 +373,113 @@ func NewZKInputs(nTx, maxFeeIdxs, nLevels int) *ZKInputs {
|
||||
// set all the elements, and if a transaction does not use a parameter, can be
|
||||
// leaved as it is in the ZKInputs, as will be 0, so later when using the
|
||||
// ZKInputs to generate the zkSnark proof there is no 'nil'/'null' values.
|
||||
func newSlice(n int) []*big.Int {
|
||||
func newSlice(n uint32) []*big.Int {
|
||||
s := make([]*big.Int, n)
|
||||
for i := 0; i < len(s); i++ {
|
||||
s[i] = big.NewInt(0)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// HashGlobalData returns the HashGlobalData
|
||||
func (z ZKInputs) HashGlobalData() (*big.Int, error) {
|
||||
b, err := z.ToHashGlobalData()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := sha256.New()
|
||||
_, err = h.Write(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := new(big.Int).SetBytes(h.Sum(nil))
|
||||
v := r.Mod(r, cryptoConstants.Q)
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// ToHashGlobalData returns the data to be hashed in the method HashGlobalData
|
||||
func (z ZKInputs) ToHashGlobalData() ([]byte, error) {
|
||||
var b []byte
|
||||
bytesMaxLevels := int(z.Metadata.MaxLevels / 8) //nolint:gomnd
|
||||
|
||||
// [MAX_NLEVELS bits] oldLastIdx
|
||||
oldLastIdx := make([]byte, bytesMaxLevels)
|
||||
copy(oldLastIdx, z.OldLastIdx.Bytes())
|
||||
b = append(b, SwapEndianness(oldLastIdx)...)
|
||||
|
||||
// [MAX_NLEVELS bits] newLastIdx
|
||||
newLastIdx := make([]byte, bytesMaxLevels)
|
||||
newLastIdxBytes, err := z.Metadata.NewLastIdxRaw.Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(newLastIdx, newLastIdxBytes[len(newLastIdxBytes)-bytesMaxLevels:])
|
||||
b = append(b, newLastIdx...)
|
||||
|
||||
// [256 bits] oldStRoot
|
||||
oldStateRoot := make([]byte, 32)
|
||||
copy(oldStateRoot, z.OldStateRoot.Bytes())
|
||||
b = append(b, oldStateRoot...)
|
||||
|
||||
// [256 bits] newStateRoot
|
||||
newStateRoot := make([]byte, 32)
|
||||
copy(newStateRoot, z.Metadata.NewStateRootRaw.Bytes())
|
||||
b = append(b, newStateRoot...)
|
||||
|
||||
// [256 bits] newExitRoot
|
||||
newExitRoot := make([]byte, 32)
|
||||
copy(newExitRoot, z.Metadata.NewExitRootRaw.Bytes())
|
||||
b = append(b, newExitRoot...)
|
||||
|
||||
// [MAX_L1_TX * (2 * MAX_NLEVELS + 480) bits] L1TxsData
|
||||
l1TxDataLen := (2*z.Metadata.MaxLevels + 480)
|
||||
l1TxsDataLen := (z.Metadata.MaxL1Tx * l1TxDataLen)
|
||||
l1TxsData := make([]byte, l1TxsDataLen/8) //nolint:gomnd
|
||||
for i := 0; i < len(z.Metadata.L1TxsData); i++ {
|
||||
dataLen := int(l1TxDataLen) / 8 //nolint:gomnd
|
||||
pos0 := i * dataLen
|
||||
pos1 := i*dataLen + dataLen
|
||||
copy(l1TxsData[pos0:pos1], z.Metadata.L1TxsData[i])
|
||||
}
|
||||
b = append(b, l1TxsData...)
|
||||
|
||||
// [MAX_TX*(2*NLevels + 24) bits] L2TxsData
|
||||
var l2TxsData []byte
|
||||
l2TxDataLen := 2*z.Metadata.NLevels + 24 //nolint:gomnd
|
||||
l2TxsDataLen := (z.Metadata.MaxTx * l2TxDataLen)
|
||||
expectedL2TxsDataLen := l2TxsDataLen / 8 //nolint:gomnd
|
||||
for i := 0; i < len(z.Metadata.L2TxsData); i++ {
|
||||
l2TxsData = append(l2TxsData, z.Metadata.L2TxsData[i]...)
|
||||
}
|
||||
if len(l2TxsData) > int(expectedL2TxsDataLen) {
|
||||
return nil, fmt.Errorf("len(l2TxsData): %d, expected: %d", len(l2TxsData), expectedL2TxsDataLen)
|
||||
}
|
||||
|
||||
l2TxsPadding := make([]byte, (int(z.Metadata.MaxTx)-len(z.Metadata.L2TxsData))*int(l2TxDataLen)/8) //nolint:gomnd
|
||||
b = append(b, l2TxsPadding...)
|
||||
b = append(b, l2TxsData...)
|
||||
|
||||
// [NLevels * MAX_TOKENS_FEE bits] feeTxsData
|
||||
for i := 0; i < len(z.FeeIdxs); i++ {
|
||||
var r []byte
|
||||
|
||||
padding := make([]byte, bytesMaxLevels/4) //nolint:gomnd
|
||||
r = append(r, padding...)
|
||||
|
||||
feeIdx := make([]byte, bytesMaxLevels/2) //nolint:gomnd
|
||||
feeIdxBytes := z.FeeIdxs[i].Bytes()
|
||||
copy(feeIdx[len(feeIdx)-len(feeIdxBytes):], feeIdxBytes[:])
|
||||
r = append(r, feeIdx...)
|
||||
b = append(b, r...)
|
||||
}
|
||||
|
||||
// [16 bits] chainID
|
||||
var chainID [2]byte
|
||||
binary.BigEndian.PutUint16(chainID[:], z.Metadata.ChainID)
|
||||
b = append(b, chainID[:]...)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func TestZKInputs(t *testing.T) {
|
||||
zki := NewZKInputs(100, 24, 32)
|
||||
zki := NewZKInputs(100, 16, 512, 24, 32)
|
||||
_, err := json.Marshal(zki)
|
||||
require.Nil(t, err)
|
||||
// fmt.Println(string(s))
|
||||
|
||||
Reference in New Issue
Block a user