Skip to content
2 changes: 2 additions & 0 deletions op-geth/core/types/hashing.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build !(js || wasm || wasip1)
// +build !wasm,!wasip1, !js
// Copyright 2021 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
Expand Down
144 changes: 144 additions & 0 deletions op-geth/core/types/hashing_wasm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
//go:build js || wasm || wasip1
// +build js wasm wasip1
package types

import (
"bytes"
"sync"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/sha3"
)

// hasherPool holds LegacyKeccak256 hashers for rlpHash.
var hasherPool = sync.Pool{
New: func() interface{} { return sha3.NewLegacyKeccak256() },
}

// encodeBufferPool holds temporary encoder buffers for DeriveSha and TX encoding.
var encodeBufferPool = sync.Pool{
New: func() interface{} { return new(bytes.Buffer) },
}

// rlpHash encodes x and hashes the encoded bytes.
func oldrlpHash(x interface{}) (h common.Hash) {
sha := hasherPool.Get().(crypto.KeccakState)
defer hasherPool.Put(sha)
sha.Reset()
rlp.Encode(sha, x)
sha.Read(h[:])
return h
}

func checkrlpHash(x interface{}) (h common.Hash) {
sha := hasherPool.Get().(crypto.KeccakState)
defer hasherPool.Put(sha)
sha.Reset()
hash := NewHashHelper()
rlp.Encode(hash, x)
hash.WriteTo(sha)
sha.Read(h[:])
n := hash.Hash()
for i := 0; i < 32; i++ {
if h[i] != n[i] {
}
require_bool(h[i] == n[i])
}
return n
}

func rlpHash(x interface{}) (h common.Hash) {
hash := NewHashHelper()
rlp.Encode(hash, x)
n := hash.Hash()
return n
}

// prefixedRlpHash writes the prefix into the hasher before rlp-encoding x.
// It's used for typed transactions.
func prefixedRlpHash(prefix byte, x interface{}) (h common.Hash) {
sha := hasherPool.Get().(crypto.KeccakState)
defer hasherPool.Put(sha)
sha.Reset()
sha.Write([]byte{prefix})
rlp.Encode(sha, x)
sha.Read(h[:])
wasm_dbg(222)
return h
}

// TrieHasher is the tool used to calculate the hash of derivable list.
// This is internal, do not use.
type TrieHasher interface {
Reset()
Update([]byte, []byte) error
Hash() common.Hash
}

// DerivableList is the input to DeriveSha.
// It is implemented by the 'Transactions' and 'Receipts' types.
// This is internal, do not use these methods.
type DerivableList interface {
Len() int
EncodeIndex(int, *bytes.Buffer)
}

func encodeForDerive(list DerivableList, i int, buf *bytes.Buffer) []byte {
buf.Reset()
list.EncodeIndex(i, buf)
// It's really unfortunate that we need to do perform this copy.
// StackTrie holds onto the values until Hash is called, so the values
// written to it must not alias.
return common.CopyBytes(buf.Bytes())
}

// DeriveSha creates the tree hashes of transactions, receipts, and withdrawals in a block header.
func DeriveSha(list DerivableList, hasher TrieHasher) common.Hash {
hasher.Reset()

valueBuf := encodeBufferPool.Get().(*bytes.Buffer)
defer encodeBufferPool.Put(valueBuf)

// StackTrie requires values to be inserted in increasing hash order, which is not the
// order that `list` provides hashes in. This insertion sequence ensures that the
// order is correct.
//
// The error returned by hasher is omitted because hasher will produce an incorrect
// hash in case any error occurs.
var indexBuf []byte
for i := 1; i < list.Len() && i <= 0x7f; i++ {
indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i))
value := encodeForDerive(list, i, valueBuf)
hasher.Update(indexBuf, value)
}
if list.Len() > 0 {
indexBuf = rlp.AppendUint64(indexBuf[:0], 0)
value := encodeForDerive(list, 0, valueBuf)
hasher.Update(indexBuf, value)
}
for i := 0x80; i < list.Len(); i++ {
indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i))
value := encodeForDerive(list, i, valueBuf)
hasher.Update(indexBuf, value)
}
wasm_dbg(111)
return hasher.Hash()
}

//go:wasmimport env wasm_dbg
//go:noescape
func wasm_dbg(uint64)

//go:wasmimport env require
//go:noescape
func require(uint32)

func require_bool(cond bool) {
if cond {
require(1)
} else {
require(0)
}
}
164 changes: 164 additions & 0 deletions op-geth/core/types/keccak256_wasm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
//go:build js || wasm || wasip1
// +build js wasm wasip1
package types

import (
"encoding/binary"
"io"
)

//go:wasmimport env keccak_new
//go:noescape
func keccak_new(uint64)

//go:wasmimport env keccak_push
//go:noescape
func keccak_push(uint64)

//go:wasmimport env keccak_finalize
//go:noescape
func keccak_finalize() uint64

func NewHashHelper() *HashHelper {
return &HashHelper{}
}

type HashHelper struct {
data []byte
}

func (b *HashHelper) Write(p []byte) (n int, err error) {
b.data = append(b.data, p...)
return len(p), nil
}

func (b *HashHelper) WriteTo(w io.Writer) (err error) {
w.Write(b.data)
return nil
}

func (b *HashHelper) Hash() [32]byte {
size := uint64(len(b.data))
padding := size % 136
if padding != 0 {
padding = 136 - padding
} else {
padding = 136
}
buf := make([]byte, size+padding)
//wasm_dbg(size)
wasm_dbg(size + padding)
copy(buf, b.data)
hash := Keccak256Hash(buf, size, padding)
return hash
}

/*
*func (b HashHelper) PrintData() {
* for _, v := range b.data {
* wasm_dbg(v)
* }
* for i := 0; i < 136; i++ {
* wasm_dbg(v)
* }
*}
*/

var hash [32]byte

func Keccak256Hash(data []byte, size uint64, padding uint64) [32]byte {
total_len := len(data)
if padding == 1 {
data[total_len-1] = 0x81
} else {
data[size] = 0x01
data[total_len-1] = 0x80
}

var hash_0 uint64
var hash_1 uint64
var hash_2 uint64
var hash_3 uint64

var val uint64

round := total_len / 136
keccak_new(1)
for i := 0; i < round; i++ {
for j := 0; j < 17; j++ {
start := i*136 + j*8
val = binary.LittleEndian.Uint64(data[start : start+8])
keccak_push(val)
}
hash_0 = keccak_finalize()
hash_1 = keccak_finalize()
hash_2 = keccak_finalize()
hash_3 = keccak_finalize()
keccak_new(0)
}

binary.LittleEndian.PutUint64(hash[:], hash_0)
binary.LittleEndian.PutUint64(hash[8:], hash_1)
binary.LittleEndian.PutUint64(hash[16:], hash_2)
binary.LittleEndian.PutUint64(hash[24:], hash_3)

return hash
}

func Keccak256HashUint64(data []uint64) [32]byte {
var hash [32]byte
var hash_0 uint64
var hash_1 uint64
var hash_2 uint64
var hash_3 uint64

keccak_new(1)
round := len(data) / 17
for i := 0; i < round; i++ {
for j := 0; j < 17; j++ {
keccak_push(data[i*17+j])
}
hash_0 = keccak_finalize()
hash_1 = keccak_finalize()
hash_2 = keccak_finalize()
hash_3 = keccak_finalize()
keccak_new(0)
}

binary.LittleEndian.PutUint64(hash[:], hash_0)
binary.LittleEndian.PutUint64(hash[8:], hash_1)
binary.LittleEndian.PutUint64(hash[16:], hash_2)
binary.LittleEndian.PutUint64(hash[24:], hash_3)

return hash
}

/*
// for test

func keccak256check(input []byte, output []byte) {
result := Keccak256Hash(input)
for i := 0; i < len(result); i++ {
if result[i] != output[i] {
require(1)
require(0)
}
}
}

func main() {
input := make([]byte, 0)
emtpy_output := []byte{
197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83,
202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112,
}
keccak256check(input, emtpy_output)

input = []byte{102, 111, 111, 98, 97, 114, 97, 97}
short_output := []byte{
172, 132, 33, 155, 248, 181, 178, 245, 199, 105, 157, 164, 188, 53, 193, 25, 7, 35, 159,
188, 30, 123, 91, 143, 30, 100, 188, 128, 172, 248, 137, 202,
}
keccak256check(input, short_output)
}
*/
2 changes: 2 additions & 0 deletions op-preimage/oracle.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build !(js || wasm || wasip1)
// +build !wasm,!wasip1, !js
package preimage

import (
Expand Down
Loading