Commit b9402913 authored by harrylee's avatar harrylee Committed by 33cn

update evm

parent 97383193
...@@ -19,8 +19,12 @@ package abi ...@@ -19,8 +19,12 @@ package abi
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common/crypto"
) )
// The ABI holds information about a contract's context and available // The ABI holds information about a contract's context and available
...@@ -30,6 +34,12 @@ type ABI struct { ...@@ -30,6 +34,12 @@ type ABI struct {
Constructor Method Constructor Method
Methods map[string]Method Methods map[string]Method
Events map[string]Event Events map[string]Event
// Additional "special" functions introduced in solidity v0.6.0.
// It's separated from the original default fallback. Each contract
// can only define one fallback and receive function.
Fallback Method // Note it's also used to represent legacy fallback before v0.6.0
Receive Method
} }
// JSON returns a parsed ABI interface and error if it failed. // JSON returns a parsed ABI interface and error if it failed.
...@@ -70,7 +80,7 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { ...@@ -70,7 +80,7 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
return nil, err return nil, err
} }
// Pack up the method ID too if not a constructor and return // Pack up the method ID too if not a constructor and return
return append(method.ID(), arguments...), nil return append(method.ID, arguments...), nil
} }
// Unpack output in v according to the abi specification // Unpack output in v according to the abi specification
...@@ -91,49 +101,145 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) { ...@@ -91,49 +101,145 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) {
return fmt.Errorf("abi: could not locate named method or event") return fmt.Errorf("abi: could not locate named method or event")
} }
// UnpackIntoMap unpacks a log into the provided map[string]interface{}
func (abi ABI) UnpackIntoMap(v map[string]interface{}, name string, data []byte) (err error) {
// since there can't be naming collisions with contracts and events,
// we need to decide whether we're calling a method or an event
if method, ok := abi.Methods[name]; ok {
if len(data)%32 != 0 {
return fmt.Errorf("abi: improperly formatted output")
}
return method.Outputs.UnpackIntoMap(v, data)
}
if event, ok := abi.Events[name]; ok {
return event.Inputs.UnpackIntoMap(v, data)
}
return fmt.Errorf("abi: could not locate named method or event")
}
// UnmarshalJSON implements json.Unmarshaler interface // UnmarshalJSON implements json.Unmarshaler interface
func (abi *ABI) UnmarshalJSON(data []byte) error { func (abi *ABI) UnmarshalJSON(data []byte) error {
var fields []struct { var fields []struct {
Type string Type string
Name string Name string
Constant bool Inputs []Argument
Outputs []Argument
// Status indicator which can be: "pure", "view",
// "nonpayable" or "payable".
StateMutability string
// Deprecated Status indicators, but removed in v0.6.0.
Constant bool // True if function is either pure or view
Payable bool // True if function is payable
// Event relevant indicator represents the event is
// declared as anonymous.
Anonymous bool Anonymous bool
Inputs []Argument
Outputs []Argument
} }
if err := json.Unmarshal(data, &fields); err != nil { if err := json.Unmarshal(data, &fields); err != nil {
return err return err
} }
abi.Methods = make(map[string]Method) abi.Methods = make(map[string]Method)
abi.Events = make(map[string]Event) abi.Events = make(map[string]Event)
for _, field := range fields { for _, field := range fields {
switch field.Type { switch field.Type {
case "constructor": case "constructor":
abi.Constructor = Method{ abi.Constructor = NewMethod("", "", Constructor, field.StateMutability, field.Constant, field.Payable, field.Inputs, nil)
Inputs: field.Inputs, case "function":
name := abi.overloadedMethodName(field.Name)
abi.Methods[name] = NewMethod(name, field.Name, Function, field.StateMutability, field.Constant, field.Payable, field.Inputs, field.Outputs)
case "fallback":
// New introduced function type in v0.6.0, check more detail
// here https://solidity.readthedocs.io/en/v0.6.0/contracts.html#fallback-function
if abi.HasFallback() {
return errors.New("only single fallback is allowed")
} }
// empty defaults to function according to the abi spec abi.Fallback = NewMethod("", "", Fallback, field.StateMutability, field.Constant, field.Payable, nil, nil)
case "function", "": case "receive":
abi.Methods[field.Name] = Method{ // New introduced function type in v0.6.0, check more detail
Name: field.Name, // here https://solidity.readthedocs.io/en/v0.6.0/contracts.html#fallback-function
Const: field.Constant, if abi.HasReceive() {
Inputs: field.Inputs, return errors.New("only single receive is allowed")
Outputs: field.Outputs,
} }
case "event": if field.StateMutability != "payable" {
abi.Events[field.Name] = Event{ return errors.New("the statemutability of receive can only be payable")
Name: field.Name,
Anonymous: field.Anonymous,
Inputs: field.Inputs,
} }
abi.Receive = NewMethod("", "", Receive, field.StateMutability, field.Constant, field.Payable, nil, nil)
case "event":
name := abi.overloadedEventName(field.Name)
abi.Events[name] = NewEvent(name, field.Name, field.Anonymous, field.Inputs)
default:
return fmt.Errorf("abi: could not recognize type %v of field %v", field.Type, field.Name)
} }
} }
return nil return nil
} }
// overloadedMethodName returns the next available name for a given function.
// Needed since solidity allows for function overload.
//
// e.g. if the abi contains Methods send, send1
// overloadedMethodName would return send2 for input send.
func (abi *ABI) overloadedMethodName(rawName string) string {
name := rawName
_, ok := abi.Methods[name]
for idx := 0; ok; idx++ {
name = fmt.Sprintf("%s%d", rawName, idx)
_, ok = abi.Methods[name]
}
return name
}
// overloadedEventName returns the next available name for a given event.
// Needed since solidity allows for event overload.
//
// e.g. if the abi contains events received, received1
// overloadedEventName would return received2 for input received.
func (abi *ABI) overloadedEventName(rawName string) string {
name := rawName
_, ok := abi.Events[name]
for idx := 0; ok; idx++ {
name = fmt.Sprintf("%s%d", rawName, idx)
_, ok = abi.Events[name]
}
return name
}
// MethodById looks up a method by the 4-byte id, returns nil if none found
func (abi *ABI) MethodById(sigdata []byte) (*Method, error) {
if len(sigdata) < 4 {
return nil, fmt.Errorf("data too short (%d bytes) for abi method lookup", len(sigdata))
}
for _, method := range abi.Methods {
if bytes.Equal(method.ID, sigdata[:4]) {
return &method, nil
}
}
return nil, fmt.Errorf("no method with id: %#x", sigdata[:4])
}
// EventByID looks an event up by its topic hash in the
// ABI and returns nil if none found.
func (abi *ABI) EventByID(topic common.Hash) (*Event, error) {
for _, event := range abi.Events {
if bytes.Equal(event.ID.Bytes(), topic.Bytes()) {
return &event, nil
}
}
return nil, fmt.Errorf("no event with id: %#x", topic.Hex())
}
// HasFallback returns an indicator whether a fallback function is included.
func (abi *ABI) HasFallback() bool {
return abi.Fallback.Type == Fallback
}
// HasReceive returns an indicator whether a receive function is included.
func (abi *ABI) HasReceive() bool {
return abi.Receive.Type == Receive
}
// MethodByID looks up a method by the 4-byte id // MethodByID looks up a method by the 4-byte id
// returns nil if none found // returns nil if none found
func (abi *ABI) MethodByID(sigdata []byte) (*Method, error) { func (abi *ABI) MethodByID(sigdata []byte) (*Method, error) {
...@@ -141,9 +247,26 @@ func (abi *ABI) MethodByID(sigdata []byte) (*Method, error) { ...@@ -141,9 +247,26 @@ func (abi *ABI) MethodByID(sigdata []byte) (*Method, error) {
return nil, fmt.Errorf("data too short (% bytes) for abi method lookup", len(sigdata)) return nil, fmt.Errorf("data too short (% bytes) for abi method lookup", len(sigdata))
} }
for _, method := range abi.Methods { for _, method := range abi.Methods {
if bytes.Equal(method.ID(), sigdata[:4]) { if bytes.Equal(method.ID, sigdata[:4]) {
return &method, nil return &method, nil
} }
} }
return nil, fmt.Errorf("no method with id: %#x", sigdata[:4]) return nil, fmt.Errorf("no method with id: %#x", sigdata[:4])
} }
var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4]
func UnpackRevert(data []byte) (string, error) {
if len(data) < 4 {
return "", errors.New("invalid data for unpacking")
}
if !bytes.Equal(data[:4], revertSelector) {
return "", errors.New("invalid data for unpacking")
}
var reason string
typ, _ := NewType("string", "", nil)
if err := (Arguments{{Type: typ}}).Unpack(&reason, data[4:]); err != nil {
return "", err
}
return reason, nil
}
This diff is collapsed.
...@@ -39,7 +39,7 @@ func Pack(param, abiData string, readOnly bool) (methodName string, packData []b ...@@ -39,7 +39,7 @@ func Pack(param, abiData string, readOnly bool) (methodName string, packData []b
return methodName, packData, err return methodName, packData, err
} }
if readOnly && !method.Const { if readOnly && !method.IsConstant() {
return methodName, packData, errors.New("method is not readonly") return methodName, packData, errors.New("method is not readonly")
} }
if len(params) != method.Inputs.LengthNonIndexed() { if len(params) != method.Inputs.LengthNonIndexed() {
...@@ -163,7 +163,7 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) { ...@@ -163,7 +163,7 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) {
if err != nil { if err != nil {
return res, err return res, err
} }
return convertInt(x, typ.Kind), nil return convertInt(x, typ.GetType().Kind()), nil
} }
b := new(big.Int) b := new(big.Int)
b.SetString(val, 10) b.SetString(val, 10)
...@@ -174,7 +174,7 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) { ...@@ -174,7 +174,7 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) {
if err != nil { if err != nil {
return res, err return res, err
} }
return convertUint(x, typ.Kind), nil return convertUint(x, typ.GetType().Kind()), nil
} }
b := new(big.Int) b := new(big.Int)
b.SetString(val, 10) b.SetString(val, 10)
...@@ -192,7 +192,7 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) { ...@@ -192,7 +192,7 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) {
if err != nil { if err != nil {
return res, err return res, err
} }
rval := reflect.MakeSlice(typ.Type, len(subs), len(subs)) rval := reflect.MakeSlice(typ.GetType(), len(subs), len(subs))
for idx, sub := range subs { for idx, sub := range subs {
subVal, er := str2GoValue(*typ.Elem, sub) subVal, er := str2GoValue(*typ.Elem, sub)
if er != nil { if er != nil {
...@@ -202,7 +202,7 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) { ...@@ -202,7 +202,7 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) {
} }
return rval.Interface(), nil return rval.Interface(), nil
case ArrayTy: case ArrayTy:
rval := reflect.New(typ.Type).Elem() rval := reflect.New(typ.GetType()).Elem()
subs, err := procArrayItem(val) subs, err := procArrayItem(val)
if err != nil { if err != nil {
return res, err return res, err
...@@ -227,7 +227,7 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) { ...@@ -227,7 +227,7 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) {
if err != nil { if err != nil {
return res, err return res, err
} }
rval := reflect.New(typ.Type).Elem() rval := reflect.New(typ.GetType()).Elem()
for i, b := range x { for i, b := range x {
rval.Index(i).Set(reflect.ValueOf(b)) rval.Index(i).Set(reflect.ValueOf(b))
} }
...@@ -251,6 +251,102 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) { ...@@ -251,6 +251,102 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) {
} }
} }
//func str2GoValue(typ Type, val string) (res interface{}, err error) {
// switch typ.T {
// case IntTy:
// if typ.Size < 256 {
// x, err := strconv.ParseInt(val, 10, typ.Size)
// if err != nil {
// return res, err
// }
// return convertInt(x, typ.Kind), nil
// }
// b := new(big.Int)
// b.SetString(val, 10)
// return b, err
// case UintTy:
// if typ.Size < 256 {
// x, err := strconv.ParseUint(val, 10, typ.Size)
// if err != nil {
// return res, err
// }
// return convertUint(x, typ.Kind), nil
// }
// b := new(big.Int)
// b.SetString(val, 10)
// return b, err
// case BoolTy:
// x, err := strconv.ParseBool(val)
// if err != nil {
// return res, err
// }
// return x, nil
// case StringTy:
// return val, nil
// case SliceTy:
// subs, err := procArrayItem(val)
// if err != nil {
// return res, err
// }
// rval := reflect.MakeSlice(typ.Type, len(subs), len(subs))
// for idx, sub := range subs {
// subVal, er := str2GoValue(*typ.Elem, sub)
// if er != nil {
// return res, er
// }
// rval.Index(idx).Set(reflect.ValueOf(subVal))
// }
// return rval.Interface(), nil
// case ArrayTy:
// rval := reflect.New(typ.Type).Elem()
// subs, err := procArrayItem(val)
// if err != nil {
// return res, err
// }
// for idx, sub := range subs {
// subVal, er := str2GoValue(*typ.Elem, sub)
// if er != nil {
// return res, er
// }
// rval.Index(idx).Set(reflect.ValueOf(subVal))
// }
// return rval.Interface(), nil
// case AddressTy:
// addr := common.StringToAddress(val)
// if addr == nil {
// return res, fmt.Errorf("invalid address: %v", val)
// }
// return addr.ToHash160(), nil
// case FixedBytesTy:
// // 固定长度多字节,输入时以十六进制方式表示,如 0xabcd00ff
// x, err := common.HexToBytes(val)
// if err != nil {
// return res, err
// }
// rval := reflect.New(typ.Type).Elem()
// for i, b := range x {
// rval.Index(i).Set(reflect.ValueOf(b))
// }
// return rval.Interface(), nil
// case BytesTy:
// // 单个字节,输入时以十六进制方式表示,如 0xab
// x, err := common.HexToBytes(val)
// if err != nil {
// return res, err
// }
// return x, nil
// case HashTy:
// // 哈希类型,也是以十六进制为输入,如:0xabcdef
// x, err := common.HexToBytes(val)
// if err != nil {
// return res, err
// }
// return common.BytesToHash(x), nil
// default:
// return res, fmt.Errorf("not support type: %v", typ.stringKind)
// }
//}
// 本方法可以将一个表示数组的字符串,经过处理后,返回数组内的字面元素; // 本方法可以将一个表示数组的字符串,经过处理后,返回数组内的字面元素;
// 如果数组为多层,则只返回第一级 // 如果数组为多层,则只返回第一级
// 例如:"[a,b,c]" -> "a","b","c" // 例如:"[a,b,c]" -> "a","b","c"
......
...@@ -439,7 +439,7 @@ func Test_GoValue(t *testing.T) { ...@@ -439,7 +439,7 @@ func Test_GoValue(t *testing.T) {
common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"), common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"),
}, },
} { } {
typ, err := NewType(test.typ) typ, err := NewType(test.typ, "", nil)
if err != nil { if err != nil {
t.Fatalf("%v failed. Unexpected new type error: %v", i, err) t.Fatalf("%v failed. Unexpected new type error: %v", i, err)
} }
......
This diff is collapsed.
...@@ -39,23 +39,21 @@ func formatSliceString(kind reflect.Kind, sliceSize int) string { ...@@ -39,23 +39,21 @@ func formatSliceString(kind reflect.Kind, sliceSize int) string {
// type in t. // type in t.
func sliceTypeCheck(t Type, val reflect.Value) error { func sliceTypeCheck(t Type, val reflect.Value) error {
if val.Kind() != reflect.Slice && val.Kind() != reflect.Array { if val.Kind() != reflect.Slice && val.Kind() != reflect.Array {
return typeErr(formatSliceString(t.Kind, t.Size), val.Type()) return typeErr(formatSliceString(t.GetType().Kind(), t.Size), val.Type())
} }
if t.T == ArrayTy && val.Len() != t.Size { if t.T == ArrayTy && val.Len() != t.Size {
return typeErr(formatSliceString(t.Elem.Kind, t.Size), formatSliceString(val.Type().Elem().Kind(), val.Len())) return typeErr(formatSliceString(t.Elem.GetType().Kind(), t.Size), formatSliceString(val.Type().Elem().Kind(), val.Len()))
} }
if t.Elem.T == SliceTy { if t.Elem.T == SliceTy || t.Elem.T == ArrayTy {
if val.Len() > 0 { if val.Len() > 0 {
return sliceTypeCheck(*t.Elem, val.Index(0)) return sliceTypeCheck(*t.Elem, val.Index(0))
} }
} else if t.Elem.T == ArrayTy {
return sliceTypeCheck(*t.Elem, val.Index(0))
} }
if elemKind := val.Type().Elem().Kind(); elemKind != t.Elem.Kind { if elemKind := val.Type().Elem().Kind(); elemKind != t.Elem.GetType().Kind() {
return typeErr(formatSliceString(t.Elem.Kind, t.Size), val.Type()) return typeErr(formatSliceString(t.Elem.GetType().Kind(), t.Size), val.Type())
} }
return nil return nil
} }
...@@ -68,10 +66,10 @@ func typeCheck(t Type, value reflect.Value) error { ...@@ -68,10 +66,10 @@ func typeCheck(t Type, value reflect.Value) error {
} }
// Check base type validity. Element types will be checked later on. // Check base type validity. Element types will be checked later on.
if t.Kind != value.Kind() { if t.GetType().Kind() != value.Kind() {
return typeErr(t.Kind, value.Kind()) return typeErr(t.GetType().Kind(), value.Kind())
} else if t.T == FixedBytesTy && t.Size != value.Len() { } else if t.T == FixedBytesTy && t.Size != value.Len() {
return typeErr(t.Type, value.Type()) return typeErr(t.GetType(), value.Type())
} else { } else {
return nil return nil
} }
......
...@@ -28,30 +28,73 @@ import ( ...@@ -28,30 +28,73 @@ import (
// holds type information (inputs) about the yielded output. Anonymous events // holds type information (inputs) about the yielded output. Anonymous events
// don't get the signature canonical representation as the first LOG topic. // don't get the signature canonical representation as the first LOG topic.
type Event struct { type Event struct {
Name string // Name is the event name used for internal representation. It's derived from
// the raw name and a suffix will be added in the case of a event overload.
//
// e.g.
// There are two events have same name:
// * foo(int,int)
// * foo(uint,uint)
// The event name of the first one wll be resolved as foo while the second one
// will be resolved as foo0.
Name string
// RawName is the raw event name parsed from ABI.
RawName string
Anonymous bool Anonymous bool
Inputs Arguments Inputs Arguments
str string
// Sig contains the string signature according to the ABI spec.
// e.g. event foo(uint32 a, int b) = "foo(uint32,int256)"
// Please note that "int" is substitute for its canonical representation "int256"
Sig string
// ID returns the canonical representation of the event's signature used by the
// abi definition to identify event names and types.
ID common.Hash
} }
func (e Event) String() string { // NewEvent creates a new Event.
inputs := make([]string, len(e.Inputs)) // It sanitizes the input arguments to remove unnamed arguments.
for i, input := range e.Inputs { // It also precomputes the id, signature and string representation
inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type) // of the event.
func NewEvent(name, rawName string, anonymous bool, inputs Arguments) Event {
// sanitize inputs to remove inputs without names
// and precompute string and sig representation.
names := make([]string, len(inputs))
types := make([]string, len(inputs))
for i, input := range inputs {
if input.Name == "" {
inputs[i] = Argument{
Name: fmt.Sprintf("arg%d", i),
Indexed: input.Indexed,
Type: input.Type,
}
} else {
inputs[i] = input
}
// string representation
names[i] = fmt.Sprintf("%v %v", input.Type, inputs[i].Name)
if input.Indexed { if input.Indexed {
inputs[i] = fmt.Sprintf("%v indexed %v", input.Name, input.Type) names[i] = fmt.Sprintf("%v indexed %v", input.Type, inputs[i].Name)
} }
// sig representation
types[i] = input.Type.String()
} }
return fmt.Sprintf("e %v(%v)", e.Name, strings.Join(inputs, ", "))
}
// ID returns the canonical representation of the event's signature used by the str := fmt.Sprintf("event %v(%v)", rawName, strings.Join(names, ", "))
// abi definition to identify event names and types. sig := fmt.Sprintf("%v(%v)", rawName, strings.Join(types, ","))
func (e Event) ID() common.Hash { id := common.BytesToHash(crypto.Keccak256([]byte(sig)))
types := make([]string, len(e.Inputs))
i := 0 return Event{
for _, input := range e.Inputs { Name: name,
types[i] = input.Type.String() RawName: rawName,
i++ Anonymous: anonymous,
Inputs: inputs,
str: str,
Sig: sig,
ID: id,
} }
return common.BytesToHash(crypto.Keccak256([]byte(fmt.Sprintf("%v(%v)", e.Name, strings.Join(types, ","))))) }
func (e Event) String() string {
return e.str
} }
...@@ -87,12 +87,12 @@ func TestEventId(t *testing.T) { ...@@ -87,12 +87,12 @@ func TestEventId(t *testing.T) {
}{ }{
{ {
definition: `[ definition: `[
{ "type" : "event", "name" : "balance", "inputs": [{ "name" : "in", "type": "uint256" }] }, { "type" : "event", "name" : "Balance", "inputs": [{ "name" : "in", "type": "uint256" }] },
{ "type" : "event", "name" : "check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] } { "type" : "event", "name" : "Check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] }
]`, ]`,
expectations: map[string]common.Hash{ expectations: map[string]common.Hash{
"balance": crypto.Keccak256Hash([]byte("balance(uint256)")), "Balance": crypto.Keccak256Hash([]byte("Balance(uint256)")),
"check": crypto.Keccak256Hash([]byte("check(address,uint256)")), "Check": crypto.Keccak256Hash([]byte("Check(address,uint256)")),
}, },
}, },
} }
...@@ -104,8 +104,41 @@ func TestEventId(t *testing.T) { ...@@ -104,8 +104,41 @@ func TestEventId(t *testing.T) {
} }
for name, event := range abi.Events { for name, event := range abi.Events {
if event.ID() != test.expectations[name] { if event.ID != test.expectations[name] {
t.Errorf("expected id to be %x, got %x", test.expectations[name], event.ID()) t.Errorf("expected id to be %x, got %x", test.expectations[name], event.ID)
}
}
}
}
func TestEventString(t *testing.T) {
var table = []struct {
definition string
expectations map[string]string
}{
{
definition: `[
{ "type" : "event", "name" : "Balance", "inputs": [{ "name" : "in", "type": "uint256" }] },
{ "type" : "event", "name" : "Check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] },
{ "type" : "event", "name" : "Transfer", "inputs": [{ "name": "from", "type": "address", "indexed": true }, { "name": "to", "type": "address", "indexed": true }, { "name": "value", "type": "uint256" }] }
]`,
expectations: map[string]string{
"Balance": "event Balance(uint256 in)",
"Check": "event Check(address t, uint256 b)",
"Transfer": "event Transfer(address indexed from, address indexed to, uint256 value)",
},
},
}
for _, test := range table {
abi, err := JSON(strings.NewReader(test.definition))
if err != nil {
t.Fatal(err)
}
for name, event := range abi.Events {
if event.String() != test.expectations[name] {
t.Errorf("expected string to be %s, got %s", test.expectations[name], event.String())
} }
} }
} }
...@@ -140,7 +173,7 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -140,7 +173,7 @@ func TestEventTupleUnpack(t *testing.T) {
type EventTransferWithTag struct { type EventTransferWithTag struct {
// this is valid because `value` is not exportable, // this is valid because `value` is not exportable,
// so value is only unmarshalled into `Value1`. // so value is only unmarshalled into `Value1`.
// value *big.Int value *big.Int //lint:ignore U1000 unused field is part of test
Value1 *big.Int `abi:"value"` Value1 *big.Int `abi:"value"`
} }
...@@ -159,7 +192,7 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -159,7 +192,7 @@ func TestEventTupleUnpack(t *testing.T) {
} }
type EventPledge struct { type EventPledge struct {
Who string Who common.Address
Wad *big.Int Wad *big.Int
Currency [3]byte Currency [3]byte
} }
...@@ -180,7 +213,7 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -180,7 +213,7 @@ func TestEventTupleUnpack(t *testing.T) {
bigintExpected := big.NewInt(1000000) bigintExpected := big.NewInt(1000000)
bigintExpected2 := big.NewInt(2218516807680) bigintExpected2 := big.NewInt(2218516807680)
bigintExpected3 := big.NewInt(1000001) bigintExpected3 := big.NewInt(1000001)
addr := common.HexToAddress("0x00Ce0d46d924CC8437c806721496599FC3FFA268").ToAddress().String() addr := common.HexToAddr("0x00Ce0d46d924CC8437c806721496599FC3FFA268")
var testCases = []struct { var testCases = []struct {
data string data string
dest interface{} dest interface{}
...@@ -242,7 +275,7 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -242,7 +275,7 @@ func TestEventTupleUnpack(t *testing.T) {
"Can unpack Pledge event into structure", "Can unpack Pledge event into structure",
}, { }, {
pledgeData1, pledgeData1,
&[]interface{}{new(string), &bigint, &[3]byte{}}, &[]interface{}{&common.Address{}, &bigint, &[3]byte{}},
&[]interface{}{ &[]interface{}{
&addr, &addr,
&bigintExpected2, &bigintExpected2,
...@@ -252,7 +285,7 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -252,7 +285,7 @@ func TestEventTupleUnpack(t *testing.T) {
"Can unpack Pledge event into slice", "Can unpack Pledge event into slice",
}, { }, {
pledgeData1, pledgeData1,
&[3]interface{}{new(string), &bigint, &[3]byte{}}, &[3]interface{}{&common.Address{}, &bigint, &[3]byte{}},
&[3]interface{}{ &[3]interface{}{
&addr, &addr,
&bigintExpected2, &bigintExpected2,
...@@ -265,28 +298,28 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -265,28 +298,28 @@ func TestEventTupleUnpack(t *testing.T) {
&[]interface{}{new(int), 0, 0}, &[]interface{}{new(int), 0, 0},
&[]interface{}{}, &[]interface{}{},
jsonEventPledge, jsonEventPledge,
"abi: cannot unmarshal string in to int", "abi: cannot unmarshal common.Address in to int",
"Can not unpack Pledge event into slice with wrong types", "Can not unpack Pledge event into slice with wrong types",
}, { }, {
pledgeData1, pledgeData1,
&BadEventPledge{}, &BadEventPledge{},
&BadEventPledge{}, &BadEventPledge{},
jsonEventPledge, jsonEventPledge,
"abi: cannot unmarshal *big.Int in to int", "abi: cannot unmarshal common.Address in to string",
"Can not unpack Pledge event into struct with wrong filed types", "Can not unpack Pledge event into struct with wrong filed types",
}, { }, {
pledgeData1, pledgeData1,
&[]interface{}{new(string), new(big.Int)}, &[]interface{}{common.Address{}, new(big.Int)},
&[]interface{}{}, &[]interface{}{},
jsonEventPledge, jsonEventPledge,
"abi: insufficient number of elements in the list/array for unpack, want 3, got 2", "abi: insufficient number of arguments for unpack, want 3, got 2",
"Can not unpack Pledge event into too short slice", "Can not unpack Pledge event into too short slice",
}, { }, {
pledgeData1, pledgeData1,
new(map[string]interface{}), new(map[string]interface{}),
&[]interface{}{}, &[]interface{}{},
jsonEventPledge, jsonEventPledge,
"abi: cannot unmarshal tuple into map[string]interface {}", "abi:[2] cannot unmarshal tuple in to map[string]interface {}",
"Can not unpack Pledge event into map", "Can not unpack Pledge event into map",
}, { }, {
mixedCaseData1, mixedCaseData1,
...@@ -321,11 +354,6 @@ func unpackTestEventData(dest interface{}, hexData string, jsonEvent []byte, ass ...@@ -321,11 +354,6 @@ func unpackTestEventData(dest interface{}, hexData string, jsonEvent []byte, ass
return a.Unpack(dest, "e", data) return a.Unpack(dest, "e", data)
} }
/*
Taken from
https://github.com/ethereum/go-ethereum/pull/15568
*/
// TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder. // TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder.
func TestEventUnpackIndexed(t *testing.T) { func TestEventUnpackIndexed(t *testing.T) {
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
......
...@@ -23,56 +23,145 @@ import ( ...@@ -23,56 +23,145 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common/crypto" "github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common/crypto"
) )
// FunctionType represents different types of functions a contract might have.
type FunctionType int
const (
// Constructor represents the constructor of the contract.
// The constructor function is called while deploying a contract.
Constructor FunctionType = iota
// Fallback represents the fallback function.
// This function is executed if no other function matches the given function
// signature and no receive function is specified.
Fallback
// Receive represents the receive function.
// This function is executed on plain Ether transfers.
Receive
// Function represents a normal function.
Function
)
// Method represents a callable given a `Name` and whether the method is a constant. // Method represents a callable given a `Name` and whether the method is a constant.
// If the method is `Const` no transaction needs to be created for this // If the method is `Const` no transaction needs to be created for this
// particular Method call. It can easily be simulated using a local VM. // particular Method call. It can easily be simulated using a local VM.
// For example a `Balance()` method only needs to retrieve something // For example a `Balance()` method only needs to retrieve something
// from the storage and therefor requires no Tx to be send to the // from the storage and therefore requires no Tx to be send to the
// network. A method such as `Transact` does require a Tx and thus will // network. A method such as `Transact` does require a Tx and thus will
// be flagged `true`. // be flagged `false`.
// Input specifies the required input parameters for this gives method. // Input specifies the required input parameters for this gives method.
type Method struct { type Method struct {
// Name is the method name used for internal representation. It's derived from
// the raw name and a suffix will be added in the case of a function overload.
//
// e.g.
// There are two functions have same name:
// * foo(int,int)
// * foo(uint,uint)
// The method name of the first one will be resolved as foo while the second one
// will be resolved as foo0.
Name string Name string
Const bool RawName string // RawName is the raw method name parsed from ABI
// Type indicates whether the method is a
// special fallback introduced in solidity v0.6.0
Type FunctionType
// StateMutability indicates the mutability state of method,
// the default value is nonpayable. It can be empty if the abi
// is generated by legacy compiler.
StateMutability string
// Legacy indicators generated by compiler before v0.6.0
Constant bool
Payable bool
Inputs Arguments Inputs Arguments
Outputs Arguments Outputs Arguments
str string
// Sig returns the methods string signature according to the ABI spec.
// e.g. function foo(uint32 a, int b) = "foo(uint32,int256)"
// Please note that "int" is substitute for its canonical representation "int256"
Sig string
// ID returns the canonical representation of the method's signature used by the
// abi definition to identify method names and types.
ID []byte
} }
// Sig returns the methods string signature according to the ABI spec. // NewMethod creates a new Method.
// // A method should always be created using NewMethod.
// Example // It also precomputes the sig representation and the string representation
// // of the method.
// function foo(uint32 a, int b) = "foo(uint32,int256)" func NewMethod(name string, rawName string, funType FunctionType, mutability string, isConst, isPayable bool, inputs Arguments, outputs Arguments) Method {
// var (
// Please note that "int" is substitute for its canonical representation "int256" types = make([]string, len(inputs))
func (method Method) Sig() string { inputNames = make([]string, len(inputs))
types := make([]string, len(method.Inputs)) outputNames = make([]string, len(outputs))
for i, input := range method.Inputs { )
for i, input := range inputs {
inputNames[i] = fmt.Sprintf("%v %v", input.Type, input.Name)
types[i] = input.Type.String() types[i] = input.Type.String()
} }
return fmt.Sprintf("%v(%v)", method.Name, strings.Join(types, ",")) for i, output := range outputs {
} outputNames[i] = output.Type.String()
func (method Method) String() string {
inputs := make([]string, len(method.Inputs))
for i, input := range method.Inputs {
inputs[i] = fmt.Sprintf("%v %v", input.Name, input.Type)
}
outputs := make([]string, len(method.Outputs))
for i, output := range method.Outputs {
if len(output.Name) > 0 { if len(output.Name) > 0 {
outputs[i] = fmt.Sprintf("%v ", output.Name) outputNames[i] += fmt.Sprintf(" %v", output.Name)
} }
outputs[i] += output.Type.String()
} }
constant := "" // calculate the signature and method id. Note only function
if method.Const { // has meaningful signature and id.
constant = "constant " var (
sig string
id []byte
)
if funType == Function {
sig = fmt.Sprintf("%v(%v)", rawName, strings.Join(types, ","))
id = crypto.Keccak256([]byte(sig))[:4]
}
// Extract meaningful state mutability of solidity method.
// If it's default value, never print it.
state := mutability
if state == "nonpayable" {
state = ""
}
if state != "" {
state = state + " "
}
identity := fmt.Sprintf("function %v", rawName)
if funType == Fallback {
identity = "fallback"
} else if funType == Receive {
identity = "receive"
} else if funType == Constructor {
identity = "constructor"
}
str := fmt.Sprintf("%v(%v) %sreturns(%v)", identity, strings.Join(inputNames, ", "), state, strings.Join(outputNames, ", "))
return Method{
Name: name,
RawName: rawName,
Type: funType,
StateMutability: mutability,
Constant: isConst,
Payable: isPayable,
Inputs: inputs,
Outputs: outputs,
str: str,
Sig: sig,
ID: id,
} }
return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
} }
// ID method name hash func (method Method) String() string {
func (method Method) ID() []byte { return method.str
return crypto.Keccak256([]byte(method.Sig()))[:4] }
// IsConstant returns the indicator whether the method is read-only.
func (method Method) IsConstant() bool {
return method.StateMutability == "view" || method.StateMutability == "pure" || method.Constant
}
// IsPayable returns the indicator whether the method can process
// plain ether transfers.
func (method Method) IsPayable() bool {
return method.StateMutability == "payable" || method.Payable
} }
...@@ -21,6 +21,7 @@ import ( ...@@ -21,6 +21,7 @@ import (
"reflect" "reflect"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common" "github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common/math"
) )
// packBytesSlice packs the given bytes as [L, V] as the canonical representation // packBytesSlice packs the given bytes as [L, V] as the canonical representation
...@@ -46,9 +47,9 @@ func packElement(t Type, reflectValue reflect.Value) []byte { ...@@ -46,9 +47,9 @@ func packElement(t Type, reflectValue reflect.Value) []byte {
return common.LeftPadBytes(reflectValue.Bytes(), 32) return common.LeftPadBytes(reflectValue.Bytes(), 32)
case BoolTy: case BoolTy:
if reflectValue.Bool() { if reflectValue.Bool() {
return common.PaddedBigBytes(common.Big1, 32) return math.PaddedBigBytes(common.Big1, 32)
} }
return common.PaddedBigBytes(common.Big0, 32) return math.PaddedBigBytes(common.Big0, 32)
case BytesTy: case BytesTy:
if reflectValue.Kind() == reflect.Array { if reflectValue.Kind() == reflect.Array {
reflectValue = mustArrayToByteSlice(reflectValue) reflectValue = mustArrayToByteSlice(reflectValue)
...@@ -68,11 +69,11 @@ func packElement(t Type, reflectValue reflect.Value) []byte { ...@@ -68,11 +69,11 @@ func packElement(t Type, reflectValue reflect.Value) []byte {
func packNum(value reflect.Value) []byte { func packNum(value reflect.Value) []byte {
switch kind := value.Kind(); kind { switch kind := value.Kind(); kind {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return U256(new(big.Int).SetUint64(value.Uint())) return math.U256Bytes(new(big.Int).SetUint64(value.Uint()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return U256(big.NewInt(value.Int())) return math.U256Bytes(big.NewInt(value.Int()))
case reflect.Ptr: case reflect.Ptr:
return U256(value.Interface().(*big.Int)) return math.U256Bytes(new(big.Int).Set(value.Interface().(*big.Int)))
default: default:
panic("abi: fatal error") panic("abi: fatal error")
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -17,7 +17,9 @@ ...@@ -17,7 +17,9 @@
package abi package abi
import ( import (
"errors"
"fmt" "fmt"
"math/big"
"reflect" "reflect"
"strings" "strings"
) )
...@@ -25,38 +27,38 @@ import ( ...@@ -25,38 +27,38 @@ import (
// indirect recursively dereferences the value until it either gets the value // indirect recursively dereferences the value until it either gets the value
// or finds a big.Int // or finds a big.Int
func indirect(v reflect.Value) reflect.Value { func indirect(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Ptr && v.Elem().Type() != derefbigT { if v.Kind() == reflect.Ptr && v.Elem().Type() != reflect.TypeOf(big.Int{}) {
return indirect(v.Elem()) return indirect(v.Elem())
} }
return v return v
} }
// reflectIntKind returns the reflect using the given size and // reflectIntType returns the reflect using the given size and
// unsignedness. // unsignedness.
func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type) { func reflectIntType(unsigned bool, size int) reflect.Type {
if unsigned {
switch size {
case 8:
return reflect.TypeOf(uint8(0))
case 16:
return reflect.TypeOf(uint16(0))
case 32:
return reflect.TypeOf(uint32(0))
case 64:
return reflect.TypeOf(uint64(0))
}
}
switch size { switch size {
case 8: case 8:
if unsigned { return reflect.TypeOf(int8(0))
return reflect.Uint8, uint8T
}
return reflect.Int8, int8T
case 16: case 16:
if unsigned { return reflect.TypeOf(int16(0))
return reflect.Uint16, uint16T
}
return reflect.Int16, int16T
case 32: case 32:
if unsigned { return reflect.TypeOf(int32(0))
return reflect.Uint32, uint32T
}
return reflect.Int32, int32T
case 64: case 64:
if unsigned { return reflect.TypeOf(int64(0))
return reflect.Uint64, uint64T
}
return reflect.Int64, int64T
} }
return reflect.Ptr, bigT return reflect.TypeOf(&big.Int{})
} }
// mustArrayToBytesSlice creates a new byte slice with the exact same size as value // mustArrayToBytesSlice creates a new byte slice with the exact same size as value
...@@ -71,55 +73,91 @@ func mustArrayToByteSlice(value reflect.Value) reflect.Value { ...@@ -71,55 +73,91 @@ func mustArrayToByteSlice(value reflect.Value) reflect.Value {
// //
// set is a bit more lenient when it comes to assignment and doesn't force an as // set is a bit more lenient when it comes to assignment and doesn't force an as
// strict ruleset as bare `reflect` does. // strict ruleset as bare `reflect` does.
func set(dst, src reflect.Value, output Argument) error { func set(dst, src reflect.Value) error {
dstType := dst.Type() dstType, srcType := dst.Type(), src.Type()
srcType := src.Type()
switch { switch {
case dstType.AssignableTo(srcType): case dstType.Kind() == reflect.Interface && dst.Elem().IsValid():
dst.Set(src) return set(dst.Elem(), src)
case dstType.Kind() == reflect.Interface: case dstType.Kind() == reflect.Ptr && dstType.Elem() != reflect.TypeOf(big.Int{}):
return set(dst.Elem(), src)
case srcType.AssignableTo(dstType) && dst.CanSet():
dst.Set(src) dst.Set(src)
case dstType.Kind() == reflect.Ptr: case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice && dst.CanSet():
return set(dst.Elem(), src, output) return setSlice(dst, src)
case dstType.Kind() == reflect.Array:
return setArray(dst, src)
case dstType.Kind() == reflect.Struct:
return setStruct(dst, src)
default: default:
return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type()) return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type())
} }
return nil return nil
} }
// requireAssignable assures that `dest` is a pointer and it's not an interface. // setSlice attempts to assign src to dst when slices are not assignable by default
func requireAssignable(dst, src reflect.Value) error { // e.g. src: [][]byte -> dst: [][15]byte
if dst.Kind() != reflect.Ptr && dst.Kind() != reflect.Interface { // setSlice ignores if we cannot copy all of src' elements.
return fmt.Errorf("abi: cannot unmarshal %v into %v", src.Type(), dst.Type()) func setSlice(dst, src reflect.Value) error {
slice := reflect.MakeSlice(dst.Type(), src.Len(), src.Len())
for i := 0; i < src.Len(); i++ {
if src.Index(i).Kind() == reflect.Struct {
if err := set(slice.Index(i), src.Index(i)); err != nil {
return err
}
} else {
// e.g. [][32]uint8 to []common.Hash
if err := set(slice.Index(i), src.Index(i)); err != nil {
return err
}
}
} }
return nil if dst.CanSet() {
dst.Set(slice)
return nil
}
return errors.New("Cannot set slice, destination not settable")
} }
// requireUnpackKind verifies preconditions for unpacking `args` into `kind` func setArray(dst, src reflect.Value) error {
func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind, array := reflect.New(dst.Type()).Elem()
args Arguments) error { min := src.Len()
if src.Len() > dst.Len() {
min = dst.Len()
}
for i := 0; i < min; i++ {
if err := set(array.Index(i), src.Index(i)); err != nil {
return err
}
}
if dst.CanSet() {
dst.Set(array)
return nil
}
return errors.New("Cannot set array, destination not settable")
}
switch k { func setStruct(dst, src reflect.Value) error {
case reflect.Struct: for i := 0; i < src.NumField(); i++ {
case reflect.Slice, reflect.Array: srcField := src.Field(i)
if minLen := args.LengthNonIndexed(); v.Len() < minLen { dstField := dst.Field(i)
return fmt.Errorf("abi: insufficient number of elements in the list/array for unpack, want %d, got %d", if !dstField.IsValid() || !srcField.IsValid() {
minLen, v.Len()) return fmt.Errorf("Could not find src field: %v value: %v in destination", srcField.Type().Name(), srcField)
}
if err := set(dstField, srcField); err != nil {
return err
} }
default:
return fmt.Errorf("abi: cannot unmarshal tuple into %v", t)
} }
return nil return nil
} }
// mapAbiToStringField maps abi to struct fields. // mapArgNamesToStructFields maps a slice of argument names to struct fields.
// first round: for each Exportable field that contains a `abi:""` tag // first round: for each Exportable field that contains a `abi:""` tag
// and this field name exists in the arguments, pair them together. // and this field name exists in the given argument name list, pair them together.
// second round: for each argument field that has not been already linked, // second round: for each argument name that has not been already linked,
// find what variable is expected to be mapped into, if it exists and has not been // find what variable is expected to be mapped into, if it exists and has not been
// used, pair them. // used, pair them.
func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]string, error) { // Note this function assumes the given value is a struct value.
func mapArgNamesToStructFields(argNames []string, value reflect.Value) (map[string]string, error) {
typ := value.Type() typ := value.Type()
abi2struct := make(map[string]string) abi2struct := make(map[string]string)
...@@ -133,45 +171,38 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin ...@@ -133,45 +171,38 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin
if structFieldName[:1] != strings.ToUpper(structFieldName[:1]) { if structFieldName[:1] != strings.ToUpper(structFieldName[:1]) {
continue continue
} }
// skip fields that have no abi:"" tag. // skip fields that have no abi:"" tag.
var ok bool tagName, ok := typ.Field(i).Tag.Lookup("abi")
var tagName string if !ok {
if tagName, ok = typ.Field(i).Tag.Lookup("abi"); !ok {
continue continue
} }
// check if tag is empty. // check if tag is empty.
if tagName == "" { if tagName == "" {
return nil, fmt.Errorf("struct: abi tag in '%s' is empty", structFieldName) return nil, fmt.Errorf("struct: abi tag in '%s' is empty", structFieldName)
} }
// check which argument field matches with the abi tag. // check which argument field matches with the abi tag.
found := false found := false
for _, abiField := range args.NonIndexed() { for _, arg := range argNames {
if abiField.Name == tagName { if arg == tagName {
if abi2struct[abiField.Name] != "" { if abi2struct[arg] != "" {
return nil, fmt.Errorf("struct: abi tag in '%s' already mapped", structFieldName) return nil, fmt.Errorf("struct: abi tag in '%s' already mapped", structFieldName)
} }
// pair them // pair them
abi2struct[abiField.Name] = structFieldName abi2struct[arg] = structFieldName
struct2abi[structFieldName] = abiField.Name struct2abi[structFieldName] = arg
found = true found = true
} }
} }
// check if this tag has been mapped. // check if this tag has been mapped.
if !found { if !found {
return nil, fmt.Errorf("struct: abi tag '%s' defined but not found in abi", tagName) return nil, fmt.Errorf("struct: abi tag '%s' defined but not found in abi", tagName)
} }
} }
// second round ~~~ // second round ~~~
for _, arg := range args { for _, argName := range argNames {
abiFieldName := arg.Name structFieldName := ToCamelCase(argName)
structFieldName := capitalise(abiFieldName)
if structFieldName == "" { if structFieldName == "" {
return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct") return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct")
...@@ -181,11 +212,11 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin ...@@ -181,11 +212,11 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin
// struct field with the same field name. If so, raise an error: // struct field with the same field name. If so, raise an error:
// abi: [ { "name": "value" } ] // abi: [ { "name": "value" } ]
// struct { Value *big.Int , Value1 *big.Int `abi:"value"`} // struct { Value *big.Int , Value1 *big.Int `abi:"value"`}
if abi2struct[abiFieldName] != "" { if abi2struct[argName] != "" {
if abi2struct[abiFieldName] != structFieldName && if abi2struct[argName] != structFieldName &&
struct2abi[structFieldName] == "" && struct2abi[structFieldName] == "" &&
value.FieldByName(structFieldName).IsValid() { value.FieldByName(structFieldName).IsValid() {
return nil, fmt.Errorf("abi: multiple variables maps to the same abi field '%s'", abiFieldName) return nil, fmt.Errorf("abi: multiple variables maps to the same abi field '%s'", argName)
} }
continue continue
} }
...@@ -197,16 +228,14 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin ...@@ -197,16 +228,14 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin
if value.FieldByName(structFieldName).IsValid() { if value.FieldByName(structFieldName).IsValid() {
// pair them // pair them
abi2struct[abiFieldName] = structFieldName abi2struct[argName] = structFieldName
struct2abi[structFieldName] = abiFieldName struct2abi[structFieldName] = argName
} else { } else {
// not paired, but annotate as used, to detect cases like // not paired, but annotate as used, to detect cases like
// abi : [ { "name": "value" }, { "name": "_value" } ] // abi : [ { "name": "value" }, { "name": "_value" } ]
// struct { Value *big.Int } // struct { Value *big.Int }
struct2abi[structFieldName] = abiFieldName struct2abi[structFieldName] = argName
} }
} }
return abi2struct, nil return abi2struct, nil
} }
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package abi
import (
"encoding/binary"
"errors"
"fmt"
"math/big"
"reflect"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common/crypto"
)
// MakeTopics converts a filter query argument list into a filter topic set.
func MakeTopics(query ...[]interface{}) ([][]common.Hash, error) {
topics := make([][]common.Hash, len(query))
for i, filter := range query {
for _, rule := range filter {
var topic common.Hash
// Try to generate the topic based on simple types
switch rule := rule.(type) {
case common.Hash:
copy(topic[:], rule[:])
case common.Address:
copy(topic[common.HashLength-common.AddressLength:], rule.Bytes()[:])
case *big.Int:
blob := rule.Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case bool:
if rule {
topic[common.HashLength-1] = 1
}
case int8:
copy(topic[:], genIntType(int64(rule), 1))
case int16:
copy(topic[:], genIntType(int64(rule), 2))
case int32:
copy(topic[:], genIntType(int64(rule), 4))
case int64:
copy(topic[:], genIntType(rule, 8))
case uint8:
blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case uint16:
blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case uint32:
blob := new(big.Int).SetUint64(uint64(rule)).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case uint64:
blob := new(big.Int).SetUint64(rule).Bytes()
copy(topic[common.HashLength-len(blob):], blob)
case string:
hash := crypto.Keccak256Hash([]byte(rule))
copy(topic[:], hash[:])
case []byte:
hash := crypto.Keccak256Hash(rule)
copy(topic[:], hash[:])
default:
// todo(rjl493456442) according solidity documentation, indexed event
// parameters that are not value types i.e. arrays and structs are not
// stored directly but instead a keccak256-hash of an encoding is stored.
//
// We only convert stringS and bytes to hash, still need to deal with
// array(both fixed-size and dynamic-size) and struct.
// Attempt to generate the topic from funky types
val := reflect.ValueOf(rule)
switch {
// static byte array
case val.Kind() == reflect.Array && reflect.TypeOf(rule).Elem().Kind() == reflect.Uint8:
reflect.Copy(reflect.ValueOf(topic[:val.Len()]), val)
default:
return nil, fmt.Errorf("unsupported indexed type: %T", rule)
}
}
topics[i] = append(topics[i], topic)
}
}
return topics, nil
}
func genIntType(rule int64, size uint) []byte {
var topic [common.HashLength]byte
if rule < 0 {
// if a rule is negative, we need to put it into two's complement.
// extended to common.Hashlength bytes.
topic = [common.HashLength]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
}
for i := uint(0); i < size; i++ {
topic[common.HashLength-i-1] = byte(rule >> (i * 8))
}
return topic[:]
}
// ParseTopics converts the indexed topic fields into actual log field values.
func ParseTopics(out interface{}, fields Arguments, topics []common.Hash) error {
return parseTopicWithSetter(fields, topics,
func(arg Argument, reconstr interface{}) {
field := reflect.ValueOf(out).Elem().FieldByName(ToCamelCase(arg.Name))
field.Set(reflect.ValueOf(reconstr))
})
}
// ParseTopicsIntoMap converts the indexed topic field-value pairs into map key-value pairs
func ParseTopicsIntoMap(out map[string]interface{}, fields Arguments, topics []common.Hash) error {
return parseTopicWithSetter(fields, topics,
func(arg Argument, reconstr interface{}) {
out[arg.Name] = reconstr
})
}
// parseTopicWithSetter converts the indexed topic field-value pairs and stores them using the
// provided set function.
//
// Note, dynamic types cannot be reconstructed since they get mapped to Keccak256
// hashes as the topic value!
func parseTopicWithSetter(fields Arguments, topics []common.Hash, setter func(Argument, interface{})) error {
// Sanity check that the fields and topics match up
if len(fields) != len(topics) {
return errors.New("topic/field count mismatch")
}
// Iterate over all the fields and reconstruct them from topics
for i, arg := range fields {
if !arg.Indexed {
return errors.New("non-indexed field in topic reconstruction")
}
var reconstr interface{}
switch arg.Type.T {
case TupleTy:
return errors.New("tuple type in topic reconstruction")
case StringTy, BytesTy, SliceTy, ArrayTy:
// Array types (including strings and bytes) have their keccak256 hashes stored in the topic- not a hash
// whose bytes can be decoded to the actual value- so the best we can do is retrieve that hash
reconstr = topics[i]
case FunctionTy:
if garbage := binary.BigEndian.Uint64(topics[i][0:8]); garbage != 0 {
return fmt.Errorf("bind: got improperly encoded function type, got %v", topics[i].Bytes())
}
var tmp [24]byte
copy(tmp[:], topics[i][8:32])
reconstr = tmp
default:
var err error
reconstr, err = toGoType(0, arg.Type, topics[i].Bytes())
if err != nil {
return err
}
}
// Use the setter function to store the value
setter(arg, reconstr)
}
return nil
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -26,45 +26,47 @@ import ( ...@@ -26,45 +26,47 @@ import (
) )
var ( var (
maxUint256 = big.NewInt(0).Add( // MaxUint256 is the maximum value that can be represented by a uint256
big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil), MaxUint256 = new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 256), common.Big1)
big.NewInt(-1)) // MaxInt256 is the maximum value that can be represented by a int256
maxInt256 = big.NewInt(0).Add( MaxInt256 = new(big.Int).Sub(new(big.Int).Lsh(common.Big1, 255), common.Big1)
big.NewInt(0).Exp(big.NewInt(2), big.NewInt(255), nil),
big.NewInt(-1))
) )
// reads the integer based on its kind // ReadInteger reads the integer based on its kind and returns the appropriate value
func readInteger(typ byte, kind reflect.Kind, b []byte) interface{} { func ReadInteger(typ Type, b []byte) interface{} {
switch kind { if typ.T == UintTy {
case reflect.Uint8: switch typ.Size {
return b[len(b)-1] case 8:
case reflect.Uint16: return b[len(b)-1]
return binary.BigEndian.Uint16(b[len(b)-2:]) case 16:
case reflect.Uint32: return binary.BigEndian.Uint16(b[len(b)-2:])
return binary.BigEndian.Uint32(b[len(b)-4:]) case 32:
case reflect.Uint64: return binary.BigEndian.Uint32(b[len(b)-4:])
return binary.BigEndian.Uint64(b[len(b)-8:]) case 64:
case reflect.Int8: return binary.BigEndian.Uint64(b[len(b)-8:])
default:
// the only case left for unsigned integer is uint256.
return new(big.Int).SetBytes(b)
}
}
switch typ.Size {
case 8:
return int8(b[len(b)-1]) return int8(b[len(b)-1])
case reflect.Int16: case 16:
return int16(binary.BigEndian.Uint16(b[len(b)-2:])) return int16(binary.BigEndian.Uint16(b[len(b)-2:]))
case reflect.Int32: case 32:
return int32(binary.BigEndian.Uint32(b[len(b)-4:])) return int32(binary.BigEndian.Uint32(b[len(b)-4:]))
case reflect.Int64: case 64:
return int64(binary.BigEndian.Uint64(b[len(b)-8:])) return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
default: default:
// the only case lefts for integer is int256/uint256. // the only case left for integer is int256
// big.SetBytes can't tell if a number is negative, positive on itself. // big.SetBytes can't tell if a number is negative or positive in itself.
// On EVM, if the returned number > max int256, it is negative. // On EVM, if the returned number > max int256, it is negative.
// A number is > max int256 if the bit at position 255 is set.
ret := new(big.Int).SetBytes(b) ret := new(big.Int).SetBytes(b)
if typ == UintTy { if ret.Bit(255) == 1 {
return ret ret.Add(MaxUint256, new(big.Int).Neg(ret))
} ret.Add(ret, common.Big1)
if ret.Cmp(maxInt256) > 0 {
ret.Add(maxUint256, big.NewInt(0).Neg(ret))
ret.Add(ret, big.NewInt(1))
ret.Neg(ret) ret.Neg(ret)
} }
return ret return ret
...@@ -102,30 +104,19 @@ func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) { ...@@ -102,30 +104,19 @@ func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) {
return return
} }
// through reflection, creates a fixed array to be read from // ReadFixedBytes uses reflection to create a fixed array to be read from
func readFixedBytes(t Type, word []byte) (interface{}, error) { func ReadFixedBytes(t Type, word []byte) (interface{}, error) {
if t.T != FixedBytesTy { if t.T != FixedBytesTy {
return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array") return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array")
} }
// convert // convert
array := reflect.New(t.Type).Elem() array := reflect.New(t.GetType()).Elem()
reflect.Copy(array, reflect.ValueOf(word[0:t.Size])) reflect.Copy(array, reflect.ValueOf(word[0:t.Size]))
return array.Interface(), nil return array.Interface(), nil
} }
func getFullElemSize(elem *Type) int {
//all other should be counted as 32 (slices have pointers to respective elements)
size := 32
//arrays wrap it, each element being the same size
for elem.T == ArrayTy {
size *= elem.Size
elem = elem.Elem
}
return size
}
// iteratively unpack elements // iteratively unpack elements
func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) { func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) {
if size < 0 { if size < 0 {
...@@ -140,23 +131,19 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) ...@@ -140,23 +131,19 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
if t.T == SliceTy { if t.T == SliceTy {
// declare our slice // declare our slice
refSlice = reflect.MakeSlice(t.Type, size, size) refSlice = reflect.MakeSlice(t.GetType(), size, size)
} else if t.T == ArrayTy { } else if t.T == ArrayTy {
// declare our array // declare our array
refSlice = reflect.New(t.Type).Elem() refSlice = reflect.New(t.GetType()).Elem()
} else { } else {
return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage")
} }
// Arrays have packed elements, resulting in longer unpack steps. // Arrays have packed elements, resulting in longer unpack steps.
// Slices have just 32 bytes per element (pointing to the contents). // Slices have just 32 bytes per element (pointing to the contents).
elemSize := 32 elemSize := getTypeSize(*t.Elem)
if t.T == ArrayTy {
elemSize = getFullElemSize(t.Elem)
}
for i, j := start, 0; j < size; i, j = i+elemSize, j+1 { for i, j := start, 0; j < size; i, j = i+elemSize, j+1 {
inter, err := toGoType(i, *t.Elem, output) inter, err := toGoType(i, *t.Elem, output)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -170,6 +157,36 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) ...@@ -170,6 +157,36 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
return refSlice.Interface(), nil return refSlice.Interface(), nil
} }
func forTupleUnpack(t Type, output []byte) (interface{}, error) {
retval := reflect.New(t.GetType()).Elem()
virtualArgs := 0
for index, elem := range t.TupleElems {
marshalledValue, err := toGoType((index+virtualArgs)*32, *elem, output)
if elem.T == ArrayTy && !isDynamicType(*elem) {
// If we have a static array, like [3]uint256, these are coded as
// just like uint256,uint256,uint256.
// This means that we need to add two 'virtual' arguments when
// we count the index from now on.
//
// Array values nested multiple levels deep are also encoded inline:
// [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256
//
// Calculate the full array size to get the correct offset for the next argument.
// Decrement it by 1, as the normal index increment is still applied.
virtualArgs += getTypeSize(*elem)/32 - 1
} else if elem.T == TupleTy && !isDynamicType(*elem) {
// If we have a static tuple, like (uint256, bool, uint256), these are
// coded as just like uint256,bool,uint256
virtualArgs += getTypeSize(*elem)/32 - 1
}
if err != nil {
return nil, err
}
retval.Field(index).Set(reflect.ValueOf(marshalledValue))
}
return retval.Interface(), nil
}
// toGoType parses the output bytes and recursively assigns the value of these bytes // toGoType parses the output bytes and recursively assigns the value of these bytes
// into a go type with accordance with the ABI spec. // into a go type with accordance with the ABI spec.
func toGoType(index int, t Type, output []byte) (interface{}, error) { func toGoType(index int, t Type, output []byte) (interface{}, error) {
...@@ -178,14 +195,14 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) { ...@@ -178,14 +195,14 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
} }
var ( var (
returnOutput []byte returnOutput []byte
begin, end int begin, length int
err error err error
) )
// if we require a length prefix, find the beginning word and size returned. // if we require a length prefix, find the beginning word and size returned.
if t.requiresLengthPrefix() { if t.requiresLengthPrefix() {
begin, end, err = lengthPrefixPointsTo(index, output) begin, length, err = lengthPrefixPointsTo(index, output)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -194,24 +211,37 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) { ...@@ -194,24 +211,37 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
} }
switch t.T { switch t.T {
case TupleTy:
if isDynamicType(t) {
begin, err := tuplePointsTo(index, output)
if err != nil {
return nil, err
}
return forTupleUnpack(t, output[begin:])
}
return forTupleUnpack(t, output[index:])
case SliceTy: case SliceTy:
return forEachUnpack(t, output, begin, end) return forEachUnpack(t, output[begin:], 0, length)
case ArrayTy: case ArrayTy:
return forEachUnpack(t, output, index, t.Size) if isDynamicType(*t.Elem) {
offset := int64(binary.BigEndian.Uint64(returnOutput[len(returnOutput)-8:]))
return forEachUnpack(t, output[offset:], 0, t.Size)
}
return forEachUnpack(t, output[index:], 0, t.Size)
case StringTy: // variable arrays are written at the end of the return bytes case StringTy: // variable arrays are written at the end of the return bytes
return string(output[begin : begin+end]), nil return string(output[begin : begin+length]), nil
case IntTy, UintTy: case IntTy, UintTy:
return readInteger(t.T, t.Kind, returnOutput), nil return ReadInteger(t, returnOutput), nil
case BoolTy: case BoolTy:
return readBool(returnOutput) return readBool(returnOutput)
case AddressTy: case AddressTy:
return common.BytesToHash160Address(returnOutput), nil return common.BytesToAddress(returnOutput), nil
case HashTy: case HashTy:
return common.BytesToHash(returnOutput), nil return common.BytesToHash(returnOutput), nil
case BytesTy: case BytesTy:
return output[begin : begin+end], nil return output[begin : begin+length], nil
case FixedBytesTy: case FixedBytesTy:
return readFixedBytes(t, returnOutput) return ReadFixedBytes(t, returnOutput)
case FunctionTy: case FunctionTy:
return readFunctionType(t, returnOutput) return readFunctionType(t, returnOutput)
default: default:
...@@ -240,7 +270,7 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err ...@@ -240,7 +270,7 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err
totalSize.Add(totalSize, bigOffsetEnd) totalSize.Add(totalSize, bigOffsetEnd)
totalSize.Add(totalSize, lengthBig) totalSize.Add(totalSize, lengthBig)
if totalSize.BitLen() > 63 { if totalSize.BitLen() > 63 {
return 0, 0, fmt.Errorf("abi length larger than int64: %v", totalSize) return 0, 0, fmt.Errorf("abi: length larger than int64: %v", totalSize)
} }
if totalSize.Cmp(outputLength) > 0 { if totalSize.Cmp(outputLength) > 0 {
...@@ -250,3 +280,17 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err ...@@ -250,3 +280,17 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err
length = int(lengthBig.Uint64()) length = int(lengthBig.Uint64())
return return
} }
// tuplePointsTo resolves the location reference for dynamic tuple.
func tuplePointsTo(index int, output []byte) (start int, err error) {
offset := big.NewInt(0).SetBytes(output[index : index+32])
outputLen := big.NewInt(int64(len(output)))
if offset.Cmp(big.NewInt(int64(len(output)))) > 0 {
return 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)", offset, outputLen)
}
if offset.BitLen() > 63 {
return 0, fmt.Errorf("abi offset larger than int64: %v", offset)
}
return int(offset.Uint64()), nil
}
...@@ -35,9 +35,9 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, ...@@ -35,9 +35,9 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
func (evm *EVMExecutor) innerExec(msg *common.Message, txHash []byte, index int, txFee int64, readOnly bool) (receipt *types.Receipt, err error) { func (evm *EVMExecutor) innerExec(msg *common.Message, txHash []byte, index int, txFee int64, readOnly bool) (receipt *types.Receipt, err error) {
// 获取当前区块的上下文信息构造EVM上下文 // 获取当前区块的上下文信息构造EVM上下文
context := evm.NewEVMContext(msg) context := evm.NewEVMContext(msg)
cfg := evm.GetAPI().GetConfig()
// 创建EVM运行时对象 // 创建EVM运行时对象
env := runtime.NewEVM(context, evm.mStateDB, *evm.vmCfg) env := runtime.NewEVM(context, evm.mStateDB, *evm.vmCfg, cfg)
isCreate := strings.Compare(msg.To().String(), EvmAddress) == 0 isCreate := strings.Compare(msg.To().String(), EvmAddress) == 0
var ( var (
ret []byte ret []byte
...@@ -48,7 +48,6 @@ func (evm *EVMExecutor) innerExec(msg *common.Message, txHash []byte, index int, ...@@ -48,7 +48,6 @@ func (evm *EVMExecutor) innerExec(msg *common.Message, txHash []byte, index int,
execName string execName string
methodName string methodName string
) )
cfg := evm.GetAPI().GetConfig()
// 为了方便计费,即使合约为新生成,也将地址的初始化放到外面操作 // 为了方便计费,即使合约为新生成,也将地址的初始化放到外面操作
if isCreate { if isCreate {
...@@ -85,20 +84,18 @@ func (evm *EVMExecutor) innerExec(msg *common.Message, txHash []byte, index int, ...@@ -85,20 +84,18 @@ func (evm *EVMExecutor) innerExec(msg *common.Message, txHash []byte, index int,
} }
inData = packData inData = packData
methodName = funcName methodName = funcName
log.Debug("call contract ", "abi funcName", funcName, "packData", common.Bytes2Hex(inData))
} }
ret, snapshot, leftOverGas, vmerr = env.Call(runtime.AccountRef(msg.From()), *msg.To(), inData, context.GasLimit, msg.Value()) ret, snapshot, leftOverGas, vmerr = env.Call(runtime.AccountRef(msg.From()), *msg.To(), inData, context.GasLimit, msg.Value())
log.Debug("call(create) contract ", "input", common.Bytes2Hex(inData))
} }
log.Debug("call(create) contract ", "input", common.Bytes2Hex(msg.Data()))
usedGas := msg.GasLimit() - leftOverGas usedGas := msg.GasLimit() - leftOverGas
logMsg := "call contract details:" logMsg := "call contract details:"
if isCreate { if isCreate {
logMsg = "create contract details:" logMsg = "create contract details:"
} }
log.Debug(logMsg, "caller address", msg.From().String(), "contract address", contractAddr.String(), "exec name", execName, "alias name", msg.Alias(), "usedGas", usedGas, "return data", common.Bytes2Hex(ret)) log.Debug(logMsg, "caller address", msg.From().String(), "contract address", contractAddr.String(), "exec name", execName, "alias name", msg.Alias(), "usedGas", usedGas, "return data", common.Bytes2Hex(ret))
curVer := evm.mStateDB.GetLastSnapshot() curVer := evm.mStateDB.GetLastSnapshot()
if vmerr != nil { if vmerr != nil {
log.Error("evm contract exec error", "error info", vmerr) log.Error("evm contract exec error", "error info", vmerr)
return receipt, vmerr return receipt, vmerr
......
...@@ -130,7 +130,7 @@ func runCase(tt *testing.T, c VMCase, file string) { ...@@ -130,7 +130,7 @@ func runCase(tt *testing.T, c VMCase, file string) {
context.Coinbase = common.StringToAddress(c.env.currentCoinbase) context.Coinbase = common.StringToAddress(c.env.currentCoinbase)
// 3 调用执行逻辑 call // 3 调用执行逻辑 call
env := runtime.NewEVM(context, statedb, *vmcfg) env := runtime.NewEVM(context, statedb, *vmcfg, api.GetConfig())
var ( var (
ret []byte ret []byte
//addr common.Address //addr common.Address
......
...@@ -279,7 +279,7 @@ func createContract(mdb *db.GoMemDB, tx types.Transaction, maxCodeSize int) (ret ...@@ -279,7 +279,7 @@ func createContract(mdb *db.GoMemDB, tx types.Transaction, maxCodeSize int) (ret
context := inst.NewEVMContext(msg) context := inst.NewEVMContext(msg)
// 创建EVM运行时对象 // 创建EVM运行时对象
env := runtime.NewEVM(context, statedb, *vmcfg) env := runtime.NewEVM(context, statedb, *vmcfg, q.GetConfig())
if maxCodeSize != 0 { if maxCodeSize != 0 {
env.SetMaxCodeSize(maxCodeSize) env.SetMaxCodeSize(maxCodeSize)
} }
......
...@@ -13,24 +13,25 @@ import ( ...@@ -13,24 +13,25 @@ import (
"github.com/33cn/chain33/common/crypto/sha3" "github.com/33cn/chain33/common/crypto/sha3"
"github.com/33cn/chain33/common/log/log15" "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
"github.com/holiman/uint256"
) )
// Address 封装地址结构体,并提供各种常用操作封装 // Address 封装地址结构体,并提供各种常用操作封装
// 这里封装的操作主要是为了提供Address<->big.Int, Address<->[]byte 之间的互相转换 // 这里封装的操作主要是为了提供Address<->big.Int, Address<->[]byte 之间的互相转换
// 并且转换的核心是使用地址对象中的Hash160元素,因为在EVM中地址固定为[20]byte,超出此范围的地址无法正确解释执行 // 并且转换的核心是使用地址对象中的Hash160元素,因为在EVM中地址固定为[20]byte,超出此范围的地址无法正确解释执行
type Address struct { type Address struct {
addr *address.Address Addr *address.Address
} }
// Hash160Address EVM中使用的地址格式 // Hash160Address EVM中使用的地址格式
type Hash160Address [Hash160Length]byte type Hash160Address [Hash160Length]byte
// String 字符串结构 // String 字符串结构
func (a Address) String() string { return a.addr.String() } func (a Address) String() string { return a.Addr.String() }
// Bytes 字节数组 // Bytes 字节数组
func (a Address) Bytes() []byte { func (a Address) Bytes() []byte {
return a.addr.Hash160[:] return a.Addr.Hash160[:]
} }
// Big 大数字 // Big 大数字
...@@ -93,13 +94,13 @@ func (h Hash160Address) ToAddress() Address { ...@@ -93,13 +94,13 @@ func (h Hash160Address) ToAddress() Address {
// NewAddress xHash生成EVM合约地址 // NewAddress xHash生成EVM合约地址
func NewAddress(cfg *types.Chain33Config, txHash []byte) Address { func NewAddress(cfg *types.Chain33Config, txHash []byte) Address {
execAddr := address.GetExecAddress(cfg.ExecName("user.evm.") + BytesToHash(txHash).Hex()) execAddr := address.GetExecAddress(cfg.ExecName("user.evm.") + BytesToHash(txHash).Hex())
return Address{addr: execAddr} return Address{Addr: execAddr}
} }
// ExecAddress 返回合约地址 // ExecAddress 返回合约地址
func ExecAddress(execName string) Address { func ExecAddress(execName string) Address {
execAddr := address.GetExecAddress(execName) execAddr := address.GetExecAddress(execName)
return Address{addr: execAddr} return Address{Addr: execAddr}
} }
// BytesToAddress 字节向地址转换 // BytesToAddress 字节向地址转换
...@@ -107,7 +108,7 @@ func BytesToAddress(b []byte) Address { ...@@ -107,7 +108,7 @@ func BytesToAddress(b []byte) Address {
a := new(address.Address) a := new(address.Address)
a.Version = 0 a.Version = 0
a.SetBytes(copyBytes(LeftPadBytes(b, 20))) a.SetBytes(copyBytes(LeftPadBytes(b, 20)))
return Address{addr: a} return Address{Addr: a}
} }
// BytesToHash160Address 字节向地址转换 // BytesToHash160Address 字节向地址转换
...@@ -124,7 +125,7 @@ func StringToAddress(s string) *Address { ...@@ -124,7 +125,7 @@ func StringToAddress(s string) *Address {
log15.Error("create address form string error", "string:", s) log15.Error("create address form string error", "string:", s)
return nil return nil
} }
return &Address{addr: addr} return &Address{Addr: addr}
} }
func copyBytes(data []byte) (out []byte) { func copyBytes(data []byte) (out []byte) {
...@@ -144,7 +145,7 @@ func BigToAddress(b *big.Int) Address { ...@@ -144,7 +145,7 @@ func BigToAddress(b *big.Int) Address {
a := new(address.Address) a := new(address.Address)
a.Version = 0 a.Version = 0
a.SetBytes(bigBytes(b)) a.SetBytes(bigBytes(b))
return Address{addr: a} return Address{Addr: a}
} }
// EmptyAddress 返回空地址 // EmptyAddress 返回空地址
...@@ -153,3 +154,24 @@ func EmptyAddress() Address { return BytesToAddress([]byte{0}) } ...@@ -153,3 +154,24 @@ func EmptyAddress() Address { return BytesToAddress([]byte{0}) }
// HexToAddress returns Address with byte values of s. // HexToAddress returns Address with byte values of s.
// If s is larger than len(h), s will be cropped from the left. // If s is larger than len(h), s will be cropped from the left.
func HexToAddress(s string) Hash160Address { return BytesToHash160Address(FromHex(s)) } func HexToAddress(s string) Hash160Address { return BytesToHash160Address(FromHex(s)) }
// INTToAddress 大数字转换为地址
func Uint256ToAddress(b *uint256.Int) Address {
//TODO 这样转换可能与之前的版本不兼容
a := new(address.Address)
a.Version = 0
out := make([]byte, 20)
copy(out[:], b.Bytes())
a.SetBytes(out)
return Address{Addr: a}
}
//十六进制转换为虚拟机中的地址
func HexToAddr(s string) Address {
a := new(address.Address)
a.Version = 0
out := make([]byte, 20)
copy(out[:], FromHex(s))
a.SetBytes(out)
return Address{Addr: a}
}
...@@ -99,3 +99,14 @@ func Bytes2HexTrim(b []byte) string { ...@@ -99,3 +99,14 @@ func Bytes2HexTrim(b []byte) string {
hex.Encode(enc[2:], data) hex.Encode(enc[2:], data)
return string(enc) return string(enc)
} }
// CopyBytes returns an exact copy of the provided bytes.
func CopyBytes(b []byte) (copiedBytes []byte) {
if b == nil {
return nil
}
copiedBytes = make([]byte, len(b))
copy(copiedBytes, b)
return
}
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693
// and the extendable output function (XOF) BLAKE2Xb.
//
// For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf
// and for BLAKE2Xb see https://blake2.net/blake2x.pdf
//
// If you aren't sure which function you need, use BLAKE2b (Sum512 or New512).
// If you need a secret-key MAC (message authentication code), use the New512
// function with a non-nil key.
//
// BLAKE2X is a construction to compute hash values larger than 64 bytes. It
// can produce hash values between 0 and 4 GiB.
package blake2b
import (
"encoding/binary"
"errors"
"hash"
)
const (
// The blocksize of BLAKE2b in bytes.
BlockSize = 128
// The hash size of BLAKE2b-512 in bytes.
Size = 64
// The hash size of BLAKE2b-384 in bytes.
Size384 = 48
// The hash size of BLAKE2b-256 in bytes.
Size256 = 32
)
var (
useAVX2 bool
useAVX bool
useSSE4 bool
)
var (
errKeySize = errors.New("blake2b: invalid key size")
errHashSize = errors.New("blake2b: invalid hash size")
)
var iv = [8]uint64{
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
}
// Sum512 returns the BLAKE2b-512 checksum of the data.
func Sum512(data []byte) [Size]byte {
var sum [Size]byte
checkSum(&sum, Size, data)
return sum
}
// Sum384 returns the BLAKE2b-384 checksum of the data.
func Sum384(data []byte) [Size384]byte {
var sum [Size]byte
var sum384 [Size384]byte
checkSum(&sum, Size384, data)
copy(sum384[:], sum[:Size384])
return sum384
}
// Sum256 returns the BLAKE2b-256 checksum of the data.
func Sum256(data []byte) [Size256]byte {
var sum [Size]byte
var sum256 [Size256]byte
checkSum(&sum, Size256, data)
copy(sum256[:], sum[:Size256])
return sum256
}
// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
// New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) }
// New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) }
// New returns a new hash.Hash computing the BLAKE2b checksum with a custom length.
// A non-nil key turns the hash into a MAC. The key must be between zero and 64 bytes long.
// The hash size can be a value between 1 and 64 but it is highly recommended to use
// values equal or greater than:
// - 32 if BLAKE2b is used as a hash function (The key is zero bytes long).
// - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long).
// When the key is nil, the returned hash.Hash implements BinaryMarshaler
// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) }
// F is a compression function for BLAKE2b. It takes as an argument the state
// vector `h`, message block vector `m`, offset counter `t`, final block indicator
// flag `f`, and number of rounds `rounds`. The state vector provided as the first
// parameter is modified by the function.
func F(h *[8]uint64, m [16]uint64, c [2]uint64, final bool, rounds uint32) {
var flag uint64
if final {
flag = 0xFFFFFFFFFFFFFFFF
}
f(h, &m, c[0], c[1], flag, uint64(rounds))
}
func newDigest(hashSize int, key []byte) (*digest, error) {
if hashSize < 1 || hashSize > Size {
return nil, errHashSize
}
if len(key) > Size {
return nil, errKeySize
}
d := &digest{
size: hashSize,
keyLen: len(key),
}
copy(d.key[:], key)
d.Reset()
return d, nil
}
func checkSum(sum *[Size]byte, hashSize int, data []byte) {
h := iv
h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24)
var c [2]uint64
if length := len(data); length > BlockSize {
n := length &^ (BlockSize - 1)
if length == n {
n -= BlockSize
}
hashBlocks(&h, &c, 0, data[:n])
data = data[n:]
}
var block [BlockSize]byte
offset := copy(block[:], data)
remaining := uint64(BlockSize - offset)
if c[0] < remaining {
c[1]--
}
c[0] -= remaining
hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
for i, v := range h[:(hashSize+7)/8] {
binary.LittleEndian.PutUint64(sum[8*i:], v)
}
}
func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
var m [16]uint64
c0, c1 := c[0], c[1]
for i := 0; i < len(blocks); {
c0 += BlockSize
if c0 < BlockSize {
c1++
}
for j := range m {
m[j] = binary.LittleEndian.Uint64(blocks[i:])
i += 8
}
f(h, &m, c0, c1, flag, 12)
}
c[0], c[1] = c0, c1
}
type digest struct {
h [8]uint64
c [2]uint64
size int
block [BlockSize]byte
offset int
key [BlockSize]byte
keyLen int
}
const (
magic = "b2b"
marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1
)
func (d *digest) MarshalBinary() ([]byte, error) {
if d.keyLen != 0 {
return nil, errors.New("crypto/blake2b: cannot marshal MACs")
}
b := make([]byte, 0, marshaledSize)
b = append(b, magic...)
for i := 0; i < 8; i++ {
b = appendUint64(b, d.h[i])
}
b = appendUint64(b, d.c[0])
b = appendUint64(b, d.c[1])
// Maximum value for size is 64
b = append(b, byte(d.size))
b = append(b, d.block[:]...)
b = append(b, byte(d.offset))
return b, nil
}
func (d *digest) UnmarshalBinary(b []byte) error {
if len(b) < len(magic) || string(b[:len(magic)]) != magic {
return errors.New("crypto/blake2b: invalid hash state identifier")
}
if len(b) != marshaledSize {
return errors.New("crypto/blake2b: invalid hash state size")
}
b = b[len(magic):]
for i := 0; i < 8; i++ {
b, d.h[i] = consumeUint64(b)
}
b, d.c[0] = consumeUint64(b)
b, d.c[1] = consumeUint64(b)
d.size = int(b[0])
b = b[1:]
copy(d.block[:], b[:BlockSize])
b = b[BlockSize:]
d.offset = int(b[0])
return nil
}
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Size() int { return d.size }
func (d *digest) Reset() {
d.h = iv
d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24)
d.offset, d.c[0], d.c[1] = 0, 0, 0
if d.keyLen > 0 {
d.block = d.key
d.offset = BlockSize
}
}
func (d *digest) Write(p []byte) (n int, err error) {
n = len(p)
if d.offset > 0 {
remaining := BlockSize - d.offset
if n <= remaining {
d.offset += copy(d.block[d.offset:], p)
return
}
copy(d.block[d.offset:], p[:remaining])
hashBlocks(&d.h, &d.c, 0, d.block[:])
d.offset = 0
p = p[remaining:]
}
if length := len(p); length > BlockSize {
nn := length &^ (BlockSize - 1)
if length == nn {
nn -= BlockSize
}
hashBlocks(&d.h, &d.c, 0, p[:nn])
p = p[nn:]
}
if len(p) > 0 {
d.offset += copy(d.block[:], p)
}
return
}
func (d *digest) Sum(sum []byte) []byte {
var hash [Size]byte
d.finalize(&hash)
return append(sum, hash[:d.size]...)
}
func (d *digest) finalize(hash *[Size]byte) {
var block [BlockSize]byte
copy(block[:], d.block[:d.offset])
remaining := uint64(BlockSize - d.offset)
c := d.c
if c[0] < remaining {
c[1]--
}
c[0] -= remaining
h := d.h
hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
for i, v := range h {
binary.LittleEndian.PutUint64(hash[8*i:], v)
}
}
func appendUint64(b []byte, x uint64) []byte {
var a [8]byte
binary.BigEndian.PutUint64(a[:], x)
return append(b, a[:]...)
}
func appendUint32(b []byte, x uint32) []byte {
var a [4]byte
binary.BigEndian.PutUint32(a[:], x)
return append(b, a[:]...)
}
func consumeUint64(b []byte) ([]byte, uint64) {
x := binary.BigEndian.Uint64(b)
return b[8:], x
}
func consumeUint32(b []byte) ([]byte, uint32) {
x := binary.BigEndian.Uint32(b)
return b[4:], x
}
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.7,amd64,!gccgo,!appengine
package blake2b
import "golang.org/x/sys/cpu"
func init() {
useAVX2 = cpu.X86.HasAVX2
useAVX = cpu.X86.HasAVX
useSSE4 = cpu.X86.HasSSE41
}
//go:noescape
func fAVX2(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
//go:noescape
func fAVX(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
//go:noescape
func fSSE4(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
func f(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64) {
switch {
case useAVX2:
fAVX2(h, m, c0, c1, flag, rounds)
case useAVX:
fAVX(h, m, c0, c1, flag, rounds)
case useSSE4:
fSSE4(h, m, c0, c1, flag, rounds)
default:
fGeneric(h, m, c0, c1, flag, rounds)
}
}
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.7,amd64,!gccgo,!appengine
package blake2b
import "golang.org/x/sys/cpu"
func init() {
useSSE4 = cpu.X86.HasSSE41
}
//go:noescape
func fSSE4(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
func f(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64) {
if useSSE4 {
fSSE4(h, m, c0, c1, flag, rounds)
} else {
fGeneric(h, m, c0, c1, flag, rounds)
}
}
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64,!gccgo,!appengine
#include "textflag.h"
DATA ·iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
DATA ·iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
GLOBL ·iv0<>(SB), (NOPTR+RODATA), $16
DATA ·iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b
DATA ·iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1
GLOBL ·iv1<>(SB), (NOPTR+RODATA), $16
DATA ·iv2<>+0x00(SB)/8, $0x510e527fade682d1
DATA ·iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
GLOBL ·iv2<>(SB), (NOPTR+RODATA), $16
DATA ·iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b
DATA ·iv3<>+0x08(SB)/8, $0x5be0cd19137e2179
GLOBL ·iv3<>(SB), (NOPTR+RODATA), $16
DATA ·c40<>+0x00(SB)/8, $0x0201000706050403
DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
GLOBL ·c40<>(SB), (NOPTR+RODATA), $16
DATA ·c48<>+0x00(SB)/8, $0x0100070605040302
DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
GLOBL ·c48<>(SB), (NOPTR+RODATA), $16
#define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \
MOVO v4, t1; \
MOVO v5, v4; \
MOVO t1, v5; \
MOVO v6, t1; \
PUNPCKLQDQ v6, t2; \
PUNPCKHQDQ v7, v6; \
PUNPCKHQDQ t2, v6; \
PUNPCKLQDQ v7, t2; \
MOVO t1, v7; \
MOVO v2, t1; \
PUNPCKHQDQ t2, v7; \
PUNPCKLQDQ v3, t2; \
PUNPCKHQDQ t2, v2; \
PUNPCKLQDQ t1, t2; \
PUNPCKHQDQ t2, v3
#define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \
MOVO v4, t1; \
MOVO v5, v4; \
MOVO t1, v5; \
MOVO v2, t1; \
PUNPCKLQDQ v2, t2; \
PUNPCKHQDQ v3, v2; \
PUNPCKHQDQ t2, v2; \
PUNPCKLQDQ v3, t2; \
MOVO t1, v3; \
MOVO v6, t1; \
PUNPCKHQDQ t2, v3; \
PUNPCKLQDQ v7, t2; \
PUNPCKHQDQ t2, v6; \
PUNPCKLQDQ t1, t2; \
PUNPCKHQDQ t2, v7
#define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \
PADDQ m0, v0; \
PADDQ m1, v1; \
PADDQ v2, v0; \
PADDQ v3, v1; \
PXOR v0, v6; \
PXOR v1, v7; \
PSHUFD $0xB1, v6, v6; \
PSHUFD $0xB1, v7, v7; \
PADDQ v6, v4; \
PADDQ v7, v5; \
PXOR v4, v2; \
PXOR v5, v3; \
PSHUFB c40, v2; \
PSHUFB c40, v3; \
PADDQ m2, v0; \
PADDQ m3, v1; \
PADDQ v2, v0; \
PADDQ v3, v1; \
PXOR v0, v6; \
PXOR v1, v7; \
PSHUFB c48, v6; \
PSHUFB c48, v7; \
PADDQ v6, v4; \
PADDQ v7, v5; \
PXOR v4, v2; \
PXOR v5, v3; \
MOVOU v2, t0; \
PADDQ v2, t0; \
PSRLQ $63, v2; \
PXOR t0, v2; \
MOVOU v3, t0; \
PADDQ v3, t0; \
PSRLQ $63, v3; \
PXOR t0, v3
#define LOAD_MSG(m0, m1, m2, m3, i0, i1, i2, i3, i4, i5, i6, i7) \
MOVQ i0*8(SI), m0; \
PINSRQ $1, i1*8(SI), m0; \
MOVQ i2*8(SI), m1; \
PINSRQ $1, i3*8(SI), m1; \
MOVQ i4*8(SI), m2; \
PINSRQ $1, i5*8(SI), m2; \
MOVQ i6*8(SI), m3; \
PINSRQ $1, i7*8(SI), m3
// func fSSE4(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
TEXT ·fSSE4(SB), 4, $24-48 // frame size = 8 + 16 byte alignment
MOVQ h+0(FP), AX
MOVQ m+8(FP), SI
MOVQ c0+16(FP), R8
MOVQ c1+24(FP), R9
MOVQ flag+32(FP), CX
MOVQ rounds+40(FP), BX
MOVQ SP, BP
MOVQ SP, R10
ADDQ $15, R10
ANDQ $~15, R10
MOVQ R10, SP
MOVOU ·iv3<>(SB), X0
MOVO X0, 0(SP)
XORQ CX, 0(SP) // 0(SP) = ·iv3 ^ (CX || 0)
MOVOU ·c40<>(SB), X13
MOVOU ·c48<>(SB), X14
MOVOU 0(AX), X12
MOVOU 16(AX), X15
MOVQ R8, X8
PINSRQ $1, R9, X8
MOVO X12, X0
MOVO X15, X1
MOVOU 32(AX), X2
MOVOU 48(AX), X3
MOVOU ·iv0<>(SB), X4
MOVOU ·iv1<>(SB), X5
MOVOU ·iv2<>(SB), X6
PXOR X8, X6
MOVO 0(SP), X7
loop:
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 0, 2, 4, 6, 1, 3, 5, 7)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 8, 10, 12, 14, 9, 11, 13, 15)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 14, 4, 9, 13, 10, 8, 15, 6)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 1, 0, 11, 5, 12, 2, 7, 3)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 11, 12, 5, 15, 8, 0, 2, 13)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 10, 3, 7, 9, 14, 6, 1, 4)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 7, 3, 13, 11, 9, 1, 12, 14)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 2, 5, 4, 15, 6, 10, 0, 8)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 9, 5, 2, 10, 0, 7, 4, 15)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 14, 11, 6, 3, 1, 12, 8, 13)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 2, 6, 0, 8, 12, 10, 11, 3)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 4, 7, 15, 1, 13, 5, 14, 9)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 12, 1, 14, 4, 5, 15, 13, 10)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 0, 6, 9, 8, 7, 3, 2, 11)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 13, 7, 12, 3, 11, 14, 1, 9)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 5, 15, 8, 2, 0, 4, 6, 10)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 6, 14, 11, 0, 15, 9, 3, 8)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 12, 13, 1, 10, 2, 7, 4, 5)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 10, 8, 7, 1, 2, 4, 6, 5)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 15, 9, 3, 13, 11, 14, 12, 0)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
JMP loop
done:
MOVOU 32(AX), X10
MOVOU 48(AX), X11
PXOR X0, X12
PXOR X1, X15
PXOR X2, X10
PXOR X3, X11
PXOR X4, X12
PXOR X5, X15
PXOR X6, X10
PXOR X7, X11
MOVOU X10, 32(AX)
MOVOU X11, 48(AX)
MOVOU X12, 0(AX)
MOVOU X15, 16(AX)
MOVQ BP, SP
RET
// +build gofuzz
package blake2b
import (
"encoding/binary"
)
func Fuzz(data []byte) int {
// Make sure the data confirms to the input model
if len(data) != 211 {
return 0
}
// Parse everything and call all the implementations
var (
rounds = binary.BigEndian.Uint16(data[0:2])
h [8]uint64
m [16]uint64
t [2]uint64
f uint64
)
for i := 0; i < 8; i++ {
offset := 2 + i*8
h[i] = binary.LittleEndian.Uint64(data[offset : offset+8])
}
for i := 0; i < 16; i++ {
offset := 66 + i*8
m[i] = binary.LittleEndian.Uint64(data[offset : offset+8])
}
t[0] = binary.LittleEndian.Uint64(data[194:202])
t[1] = binary.LittleEndian.Uint64(data[202:210])
if data[210]%2 == 1 { // Avoid spinning the fuzzer to hit 0/1
f = 0xFFFFFFFFFFFFFFFF
}
// Run the blake2b compression on all instruction sets and cross reference
want := h
fGeneric(&want, &m, t[0], t[1], f, uint64(rounds))
have := h
fSSE4(&have, &m, t[0], t[1], f, uint64(rounds))
if have != want {
panic("SSE4 mismatches generic algo")
}
have = h
fAVX(&have, &m, t[0], t[1], f, uint64(rounds))
if have != want {
panic("AVX mismatches generic algo")
}
have = h
fAVX2(&have, &m, t[0], t[1], f, uint64(rounds))
if have != want {
panic("AVX2 mismatches generic algo")
}
return 1
}
package blake2b
import (
"fmt"
"reflect"
"testing"
)
func TestF(t *testing.T) {
for i, test := range testVectorsF {
t.Run(fmt.Sprintf("test vector %v", i), func(t *testing.T) {
//toEthereumTestCase(test)
h := test.hIn
F(&h, test.m, test.c, test.f, test.rounds)
if !reflect.DeepEqual(test.hOut, h) {
t.Errorf("Unexpected result\nExpected: [%#x]\nActual: [%#x]\n", test.hOut, h)
}
})
}
}
type testVector struct {
hIn [8]uint64
m [16]uint64
c [2]uint64
f bool
rounds uint32
hOut [8]uint64
}
// https://tools.ietf.org/html/rfc7693#appendix-A
var testVectorsF = []testVector{
{
hIn: [8]uint64{
0x6a09e667f2bdc948, 0xbb67ae8584caa73b,
0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
},
m: [16]uint64{
0x0000000000636261, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000,
},
c: [2]uint64{3, 0},
f: true,
rounds: 12,
hOut: [8]uint64{
0x0D4D1C983FA580BA, 0xE9F6129FB697276A, 0xB7C45A68142F214C,
0xD1A2FFDB6FBB124B, 0x2D79AB2A39C5877D, 0x95CC3345DED552C2,
0x5A92F1DBA88AD318, 0x239900D4ED8623B9,
},
},
}
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package blake2b
import (
"encoding/binary"
"math/bits"
)
// the precomputed values for BLAKE2b
// there are 10 16-byte arrays - one for each round
// the entries are calculated from the sigma constants.
var precomputed = [10][16]byte{
{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15},
{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3},
{11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4},
{7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8},
{9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13},
{2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9},
{12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11},
{13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10},
{6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5},
{10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0},
}
func hashBlocksGeneric(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
var m [16]uint64
c0, c1 := c[0], c[1]
for i := 0; i < len(blocks); {
c0 += BlockSize
if c0 < BlockSize {
c1++
}
for j := range m {
m[j] = binary.LittleEndian.Uint64(blocks[i:])
i += 8
}
fGeneric(h, &m, c0, c1, flag, 12)
}
c[0], c[1] = c0, c1
}
func fGeneric(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64) {
v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]
v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]
v12 ^= c0
v13 ^= c1
v14 ^= flag
for i := 0; i < int(rounds); i++ {
s := &(precomputed[i%10])
v0 += m[s[0]]
v0 += v4
v12 ^= v0
v12 = bits.RotateLeft64(v12, -32)
v8 += v12
v4 ^= v8
v4 = bits.RotateLeft64(v4, -24)
v1 += m[s[1]]
v1 += v5
v13 ^= v1
v13 = bits.RotateLeft64(v13, -32)
v9 += v13
v5 ^= v9
v5 = bits.RotateLeft64(v5, -24)
v2 += m[s[2]]
v2 += v6
v14 ^= v2
v14 = bits.RotateLeft64(v14, -32)
v10 += v14
v6 ^= v10
v6 = bits.RotateLeft64(v6, -24)
v3 += m[s[3]]
v3 += v7
v15 ^= v3
v15 = bits.RotateLeft64(v15, -32)
v11 += v15
v7 ^= v11
v7 = bits.RotateLeft64(v7, -24)
v0 += m[s[4]]
v0 += v4
v12 ^= v0
v12 = bits.RotateLeft64(v12, -16)
v8 += v12
v4 ^= v8
v4 = bits.RotateLeft64(v4, -63)
v1 += m[s[5]]
v1 += v5
v13 ^= v1
v13 = bits.RotateLeft64(v13, -16)
v9 += v13
v5 ^= v9
v5 = bits.RotateLeft64(v5, -63)
v2 += m[s[6]]
v2 += v6
v14 ^= v2
v14 = bits.RotateLeft64(v14, -16)
v10 += v14
v6 ^= v10
v6 = bits.RotateLeft64(v6, -63)
v3 += m[s[7]]
v3 += v7
v15 ^= v3
v15 = bits.RotateLeft64(v15, -16)
v11 += v15
v7 ^= v11
v7 = bits.RotateLeft64(v7, -63)
v0 += m[s[8]]
v0 += v5
v15 ^= v0
v15 = bits.RotateLeft64(v15, -32)
v10 += v15
v5 ^= v10
v5 = bits.RotateLeft64(v5, -24)
v1 += m[s[9]]
v1 += v6
v12 ^= v1
v12 = bits.RotateLeft64(v12, -32)
v11 += v12
v6 ^= v11
v6 = bits.RotateLeft64(v6, -24)
v2 += m[s[10]]
v2 += v7
v13 ^= v2
v13 = bits.RotateLeft64(v13, -32)
v8 += v13
v7 ^= v8
v7 = bits.RotateLeft64(v7, -24)
v3 += m[s[11]]
v3 += v4
v14 ^= v3
v14 = bits.RotateLeft64(v14, -32)
v9 += v14
v4 ^= v9
v4 = bits.RotateLeft64(v4, -24)
v0 += m[s[12]]
v0 += v5
v15 ^= v0
v15 = bits.RotateLeft64(v15, -16)
v10 += v15
v5 ^= v10
v5 = bits.RotateLeft64(v5, -63)
v1 += m[s[13]]
v1 += v6
v12 ^= v1
v12 = bits.RotateLeft64(v12, -16)
v11 += v12
v6 ^= v11
v6 = bits.RotateLeft64(v6, -63)
v2 += m[s[14]]
v2 += v7
v13 ^= v2
v13 = bits.RotateLeft64(v13, -16)
v8 += v13
v7 ^= v8
v7 = bits.RotateLeft64(v7, -63)
v3 += m[s[15]]
v3 += v4
v14 ^= v3
v14 = bits.RotateLeft64(v14, -16)
v9 += v14
v4 ^= v9
v4 = bits.RotateLeft64(v4, -63)
}
h[0] ^= v0 ^ v8
h[1] ^= v1 ^ v9
h[2] ^= v2 ^ v10
h[3] ^= v3 ^ v11
h[4] ^= v4 ^ v12
h[5] ^= v5 ^ v13
h[6] ^= v6 ^ v14
h[7] ^= v7 ^ v15
}
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64 appengine gccgo
package blake2b
func f(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64) {
fGeneric(h, m, c0, c1, flag, rounds)
}
This source diff could not be displayed because it is too large. You can view the blob instead.
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package blake2b
import (
"encoding/binary"
"errors"
"io"
)
// XOF defines the interface to hash functions that
// support arbitrary-length output.
type XOF interface {
// Write absorbs more data into the hash's state. It panics if called
// after Read.
io.Writer
// Read reads more output from the hash. It returns io.EOF if the limit
// has been reached.
io.Reader
// Clone returns a copy of the XOF in its current state.
Clone() XOF
// Reset resets the XOF to its initial state.
Reset()
}
// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
// the length of the output is not known in advance.
const OutputLengthUnknown = 0
// magicUnknownOutputLength is a magic value for the output size that indicates
// an unknown number of output bytes.
const magicUnknownOutputLength = (1 << 32) - 1
// maxOutputLength is the absolute maximum number of bytes to produce when the
// number of output bytes is unknown.
const maxOutputLength = (1 << 32) * 64
// NewXOF creates a new variable-output-length hash. The hash either produce a
// known number of bytes (1 <= size < 2**32-1), or an unknown number of bytes
// (size == OutputLengthUnknown). In the latter case, an absolute limit of
// 256GiB applies.
//
// A non-nil key turns the hash into a MAC. The key must between
// zero and 32 bytes long.
func NewXOF(size uint32, key []byte) (XOF, error) {
if len(key) > Size {
return nil, errKeySize
}
if size == magicUnknownOutputLength {
// 2^32-1 indicates an unknown number of bytes and thus isn't a
// valid length.
return nil, errors.New("blake2b: XOF length too large")
}
if size == OutputLengthUnknown {
size = magicUnknownOutputLength
}
x := &xof{
d: digest{
size: Size,
keyLen: len(key),
},
length: size,
}
copy(x.d.key[:], key)
x.Reset()
return x, nil
}
type xof struct {
d digest
length uint32
remaining uint64
cfg, root, block [Size]byte
offset int
nodeOffset uint32
readMode bool
}
func (x *xof) Write(p []byte) (n int, err error) {
if x.readMode {
panic("blake2b: write to XOF after read")
}
return x.d.Write(p)
}
func (x *xof) Clone() XOF {
clone := *x
return &clone
}
func (x *xof) Reset() {
x.cfg[0] = byte(Size)
binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length
binary.LittleEndian.PutUint32(x.cfg[12:], x.length) // XOF length
x.cfg[17] = byte(Size) // inner hash size
x.d.Reset()
x.d.h[1] ^= uint64(x.length) << 32
x.remaining = uint64(x.length)
if x.remaining == magicUnknownOutputLength {
x.remaining = maxOutputLength
}
x.offset, x.nodeOffset = 0, 0
x.readMode = false
}
func (x *xof) Read(p []byte) (n int, err error) {
if !x.readMode {
x.d.finalize(&x.root)
x.readMode = true
}
if x.remaining == 0 {
return 0, io.EOF
}
n = len(p)
if uint64(n) > x.remaining {
n = int(x.remaining)
p = p[:n]
}
if x.offset > 0 {
blockRemaining := Size - x.offset
if n < blockRemaining {
x.offset += copy(p, x.block[x.offset:])
x.remaining -= uint64(n)
return
}
copy(p, x.block[x.offset:])
p = p[blockRemaining:]
x.offset = 0
x.remaining -= uint64(blockRemaining)
}
for len(p) >= Size {
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
x.nodeOffset++
x.d.initConfig(&x.cfg)
x.d.Write(x.root[:])
x.d.finalize(&x.block)
copy(p, x.block[:])
p = p[Size:]
x.remaining -= uint64(Size)
}
if todo := len(p); todo > 0 {
if x.remaining < uint64(Size) {
x.cfg[0] = byte(x.remaining)
}
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
x.nodeOffset++
x.d.initConfig(&x.cfg)
x.d.Write(x.root[:])
x.d.finalize(&x.block)
x.offset = copy(p, x.block[:todo])
x.remaining -= uint64(todo)
}
return
}
func (d *digest) initConfig(cfg *[Size]byte) {
d.offset, d.c[0], d.c[1] = 0, 0, 0
for i := range d.h {
d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(cfg[i*8:])
}
}
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.9
package blake2b
import (
"crypto"
"hash"
)
func init() {
newHash256 := func() hash.Hash {
h, _ := New256(nil)
return h
}
newHash384 := func() hash.Hash {
h, _ := New384(nil)
return h
}
newHash512 := func() hash.Hash {
h, _ := New512(nil)
return h
}
crypto.RegisterHash(crypto.BLAKE2b_256, newHash256)
crypto.RegisterHash(crypto.BLAKE2b_384, newHash384)
crypto.RegisterHash(crypto.BLAKE2b_512, newHash512)
}
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build amd64,blsasm amd64,blsadx
package bls12381
import (
"golang.org/x/sys/cpu"
)
func init() {
if !enableADX || !cpu.X86.HasADX || !cpu.X86.HasBMI2 {
mul = mulNoADX
}
}
// Use ADX backend for default
var mul func(c, a, b *fe) = mulADX
func square(c, a *fe) {
mul(c, a, a)
}
func neg(c, a *fe) {
if a.isZero() {
c.set(a)
} else {
_neg(c, a)
}
}
//go:noescape
func add(c, a, b *fe)
//go:noescape
func addAssign(a, b *fe)
//go:noescape
func ladd(c, a, b *fe)
//go:noescape
func laddAssign(a, b *fe)
//go:noescape
func double(c, a *fe)
//go:noescape
func doubleAssign(a *fe)
//go:noescape
func ldouble(c, a *fe)
//go:noescape
func sub(c, a, b *fe)
//go:noescape
func subAssign(a, b *fe)
//go:noescape
func lsubAssign(a, b *fe)
//go:noescape
func _neg(c, a *fe)
//go:noescape
func mulNoADX(c, a, b *fe)
//go:noescape
func mulADX(c, a, b *fe)
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build amd64,blsadx
package bls12381
// enableADX is true if the ADX/BMI2 instruction set was requested for the BLS
// implementation. The system may still fall back to plain ASM if the necessary
// instructions are unavailable on the CPU.
const enableADX = true
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build amd64,blsasm
package bls12381
// enableADX is true if the ADX/BMI2 instruction set was requested for the BLS
// implementation. The system may still fall back to plain ASM if the necessary
// instructions are unavailable on the CPU.
const enableADX = false
package bls12381
import (
"crypto/rand"
"math/big"
)
var fuz int = 10
func randScalar(max *big.Int) *big.Int {
a, _ := rand.Int(rand.Reader, max)
return a
}
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package bls12381
import (
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"math/big"
)
// fe is base field element representation
type fe [6]uint64
// fe2 is element representation of 'fp2' which is quadratic extension of base field 'fp'
// Representation follows c[0] + c[1] * u encoding order.
type fe2 [2]fe
// fe6 is element representation of 'fp6' field which is cubic extension of 'fp2'
// Representation follows c[0] + c[1] * v + c[2] * v^2 encoding order.
type fe6 [3]fe2
// fe12 is element representation of 'fp12' field which is quadratic extension of 'fp6'
// Representation follows c[0] + c[1] * w encoding order.
type fe12 [2]fe6
func (fe *fe) setBytes(in []byte) *fe {
size := 48
l := len(in)
if l >= size {
l = size
}
padded := make([]byte, size)
copy(padded[size-l:], in[:])
var a int
for i := 0; i < 6; i++ {
a = size - i*8
fe[i] = uint64(padded[a-1]) | uint64(padded[a-2])<<8 |
uint64(padded[a-3])<<16 | uint64(padded[a-4])<<24 |
uint64(padded[a-5])<<32 | uint64(padded[a-6])<<40 |
uint64(padded[a-7])<<48 | uint64(padded[a-8])<<56
}
return fe
}
func (fe *fe) setBig(a *big.Int) *fe {
return fe.setBytes(a.Bytes())
}
func (fe *fe) setString(s string) (*fe, error) {
if s[:2] == "0x" {
s = s[2:]
}
bytes, err := hex.DecodeString(s)
if err != nil {
return nil, err
}
return fe.setBytes(bytes), nil
}
func (fe *fe) set(fe2 *fe) *fe {
fe[0] = fe2[0]
fe[1] = fe2[1]
fe[2] = fe2[2]
fe[3] = fe2[3]
fe[4] = fe2[4]
fe[5] = fe2[5]
return fe
}
func (fe *fe) bytes() []byte {
out := make([]byte, 48)
var a int
for i := 0; i < 6; i++ {
a = 48 - i*8
out[a-1] = byte(fe[i])
out[a-2] = byte(fe[i] >> 8)
out[a-3] = byte(fe[i] >> 16)
out[a-4] = byte(fe[i] >> 24)
out[a-5] = byte(fe[i] >> 32)
out[a-6] = byte(fe[i] >> 40)
out[a-7] = byte(fe[i] >> 48)
out[a-8] = byte(fe[i] >> 56)
}
return out
}
func (fe *fe) big() *big.Int {
return new(big.Int).SetBytes(fe.bytes())
}
func (fe *fe) string() (s string) {
for i := 5; i >= 0; i-- {
s = fmt.Sprintf("%s%16.16x", s, fe[i])
}
return "0x" + s
}
func (fe *fe) zero() *fe {
fe[0] = 0
fe[1] = 0
fe[2] = 0
fe[3] = 0
fe[4] = 0
fe[5] = 0
return fe
}
func (fe *fe) one() *fe {
return fe.set(r1)
}
func (fe *fe) rand(r io.Reader) (*fe, error) {
bi, err := rand.Int(r, modulus.big())
if err != nil {
return nil, err
}
return fe.setBig(bi), nil
}
func (fe *fe) isValid() bool {
return fe.cmp(&modulus) < 0
}
func (fe *fe) isOdd() bool {
var mask uint64 = 1
return fe[0]&mask != 0
}
func (fe *fe) isEven() bool {
var mask uint64 = 1
return fe[0]&mask == 0
}
func (fe *fe) isZero() bool {
return (fe[5] | fe[4] | fe[3] | fe[2] | fe[1] | fe[0]) == 0
}
func (fe *fe) isOne() bool {
return fe.equal(r1)
}
func (fe *fe) cmp(fe2 *fe) int {
for i := 5; i >= 0; i-- {
if fe[i] > fe2[i] {
return 1
} else if fe[i] < fe2[i] {
return -1
}
}
return 0
}
func (fe *fe) equal(fe2 *fe) bool {
return fe2[0] == fe[0] && fe2[1] == fe[1] && fe2[2] == fe[2] && fe2[3] == fe[3] && fe2[4] == fe[4] && fe2[5] == fe[5]
}
func (e *fe) sign() bool {
r := new(fe)
fromMont(r, e)
return r[0]&1 == 0
}
func (fe *fe) div2(e uint64) {
fe[0] = fe[0]>>1 | fe[1]<<63
fe[1] = fe[1]>>1 | fe[2]<<63
fe[2] = fe[2]>>1 | fe[3]<<63
fe[3] = fe[3]>>1 | fe[4]<<63
fe[4] = fe[4]>>1 | fe[5]<<63
fe[5] = fe[5]>>1 | e<<63
}
func (fe *fe) mul2() uint64 {
e := fe[5] >> 63
fe[5] = fe[5]<<1 | fe[4]>>63
fe[4] = fe[4]<<1 | fe[3]>>63
fe[3] = fe[3]<<1 | fe[2]>>63
fe[2] = fe[2]<<1 | fe[1]>>63
fe[1] = fe[1]<<1 | fe[0]>>63
fe[0] = fe[0] << 1
return e
}
func (e *fe2) zero() *fe2 {
e[0].zero()
e[1].zero()
return e
}
func (e *fe2) one() *fe2 {
e[0].one()
e[1].zero()
return e
}
func (e *fe2) set(e2 *fe2) *fe2 {
e[0].set(&e2[0])
e[1].set(&e2[1])
return e
}
func (e *fe2) rand(r io.Reader) (*fe2, error) {
a0, err := new(fe).rand(r)
if err != nil {
return nil, err
}
a1, err := new(fe).rand(r)
if err != nil {
return nil, err
}
return &fe2{*a0, *a1}, nil
}
func (e *fe2) isOne() bool {
return e[0].isOne() && e[1].isZero()
}
func (e *fe2) isZero() bool {
return e[0].isZero() && e[1].isZero()
}
func (e *fe2) equal(e2 *fe2) bool {
return e[0].equal(&e2[0]) && e[1].equal(&e2[1])
}
func (e *fe2) sign() bool {
r := new(fe)
if !e[0].isZero() {
fromMont(r, &e[0])
return r[0]&1 == 0
}
fromMont(r, &e[1])
return r[0]&1 == 0
}
func (e *fe6) zero() *fe6 {
e[0].zero()
e[1].zero()
e[2].zero()
return e
}
func (e *fe6) one() *fe6 {
e[0].one()
e[1].zero()
e[2].zero()
return e
}
func (e *fe6) set(e2 *fe6) *fe6 {
e[0].set(&e2[0])
e[1].set(&e2[1])
e[2].set(&e2[2])
return e
}
func (e *fe6) rand(r io.Reader) (*fe6, error) {
a0, err := new(fe2).rand(r)
if err != nil {
return nil, err
}
a1, err := new(fe2).rand(r)
if err != nil {
return nil, err
}
a2, err := new(fe2).rand(r)
if err != nil {
return nil, err
}
return &fe6{*a0, *a1, *a2}, nil
}
func (e *fe6) isOne() bool {
return e[0].isOne() && e[1].isZero() && e[2].isZero()
}
func (e *fe6) isZero() bool {
return e[0].isZero() && e[1].isZero() && e[2].isZero()
}
func (e *fe6) equal(e2 *fe6) bool {
return e[0].equal(&e2[0]) && e[1].equal(&e2[1]) && e[2].equal(&e2[2])
}
func (e *fe12) zero() *fe12 {
e[0].zero()
e[1].zero()
return e
}
func (e *fe12) one() *fe12 {
e[0].one()
e[1].zero()
return e
}
func (e *fe12) set(e2 *fe12) *fe12 {
e[0].set(&e2[0])
e[1].set(&e2[1])
return e
}
func (e *fe12) rand(r io.Reader) (*fe12, error) {
a0, err := new(fe6).rand(r)
if err != nil {
return nil, err
}
a1, err := new(fe6).rand(r)
if err != nil {
return nil, err
}
return &fe12{*a0, *a1}, nil
}
func (e *fe12) isOne() bool {
return e[0].isOne() && e[1].isZero()
}
func (e *fe12) isZero() bool {
return e[0].isZero() && e[1].isZero()
}
func (e *fe12) equal(e2 *fe12) bool {
return e[0].equal(&e2[0]) && e[1].equal(&e2[1])
}
package bls12381
import (
"bytes"
"crypto/rand"
"math/big"
"testing"
)
func TestFieldElementValidation(t *testing.T) {
zero := new(fe).zero()
if !zero.isValid() {
t.Fatal("zero must be valid")
}
one := new(fe).one()
if !one.isValid() {
t.Fatal("one must be valid")
}
if modulus.isValid() {
t.Fatal("modulus must be invalid")
}
n := modulus.big()
n.Add(n, big.NewInt(1))
if new(fe).setBig(n).isValid() {
t.Fatal("number greater than modulus must be invalid")
}
}
func TestFieldElementEquality(t *testing.T) {
// fe
zero := new(fe).zero()
if !zero.equal(zero) {
t.Fatal("0 == 0")
}
one := new(fe).one()
if !one.equal(one) {
t.Fatal("1 == 1")
}
a, _ := new(fe).rand(rand.Reader)
if !a.equal(a) {
t.Fatal("a == a")
}
b := new(fe)
add(b, a, one)
if a.equal(b) {
t.Fatal("a != a + 1")
}
// fe2
zero2 := new(fe2).zero()
if !zero2.equal(zero2) {
t.Fatal("0 == 0")
}
one2 := new(fe2).one()
if !one2.equal(one2) {
t.Fatal("1 == 1")
}
a2, _ := new(fe2).rand(rand.Reader)
if !a2.equal(a2) {
t.Fatal("a == a")
}
b2 := new(fe2)
fp2 := newFp2()
fp2.add(b2, a2, one2)
if a2.equal(b2) {
t.Fatal("a != a + 1")
}
// fe6
zero6 := new(fe6).zero()
if !zero6.equal(zero6) {
t.Fatal("0 == 0")
}
one6 := new(fe6).one()
if !one6.equal(one6) {
t.Fatal("1 == 1")
}
a6, _ := new(fe6).rand(rand.Reader)
if !a6.equal(a6) {
t.Fatal("a == a")
}
b6 := new(fe6)
fp6 := newFp6(fp2)
fp6.add(b6, a6, one6)
if a6.equal(b6) {
t.Fatal("a != a + 1")
}
// fe12
zero12 := new(fe12).zero()
if !zero12.equal(zero12) {
t.Fatal("0 == 0")
}
one12 := new(fe12).one()
if !one12.equal(one12) {
t.Fatal("1 == 1")
}
a12, _ := new(fe12).rand(rand.Reader)
if !a12.equal(a12) {
t.Fatal("a == a")
}
b12 := new(fe12)
fp12 := newFp12(fp6)
fp12.add(b12, a12, one12)
if a12.equal(b12) {
t.Fatal("a != a + 1")
}
}
func TestFieldElementHelpers(t *testing.T) {
// fe
zero := new(fe).zero()
if !zero.isZero() {
t.Fatal("'zero' is not zero")
}
one := new(fe).one()
if !one.isOne() {
t.Fatal("'one' is not one")
}
odd := new(fe).setBig(big.NewInt(1))
if !odd.isOdd() {
t.Fatal("1 must be odd")
}
if odd.isEven() {
t.Fatal("1 must not be even")
}
even := new(fe).setBig(big.NewInt(2))
if !even.isEven() {
t.Fatal("2 must be even")
}
if even.isOdd() {
t.Fatal("2 must not be odd")
}
// fe2
zero2 := new(fe2).zero()
if !zero2.isZero() {
t.Fatal("'zero' is not zero, 2")
}
one2 := new(fe2).one()
if !one2.isOne() {
t.Fatal("'one' is not one, 2")
}
// fe6
zero6 := new(fe6).zero()
if !zero6.isZero() {
t.Fatal("'zero' is not zero, 6")
}
one6 := new(fe6).one()
if !one6.isOne() {
t.Fatal("'one' is not one, 6")
}
// fe12
zero12 := new(fe12).zero()
if !zero12.isZero() {
t.Fatal("'zero' is not zero, 12")
}
one12 := new(fe12).one()
if !one12.isOne() {
t.Fatal("'one' is not one, 12")
}
}
func TestFieldElementSerialization(t *testing.T) {
t.Run("zero", func(t *testing.T) {
in := make([]byte, 48)
fe := new(fe).setBytes(in)
if !fe.isZero() {
t.Fatal("bad serialization")
}
if !bytes.Equal(in, fe.bytes()) {
t.Fatal("bad serialization")
}
})
t.Run("bytes", func(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b := new(fe).setBytes(a.bytes())
if !a.equal(b) {
t.Fatal("bad serialization")
}
}
})
t.Run("big", func(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b := new(fe).setBig(a.big())
if !a.equal(b) {
t.Fatal("bad encoding or decoding")
}
}
})
t.Run("string", func(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b, err := new(fe).setString(a.string())
if err != nil {
t.Fatal(err)
}
if !a.equal(b) {
t.Fatal("bad encoding or decoding")
}
}
})
}
func TestFieldElementByteInputs(t *testing.T) {
zero := new(fe).zero()
in := make([]byte, 0)
a := new(fe).setBytes(in)
if !a.equal(zero) {
t.Fatal("bad serialization")
}
in = make([]byte, 48)
a = new(fe).setBytes(in)
if !a.equal(zero) {
t.Fatal("bad serialization")
}
in = make([]byte, 64)
a = new(fe).setBytes(in)
if !a.equal(zero) {
t.Fatal("bad serialization")
}
in = make([]byte, 49)
in[47] = 1
normalOne := &fe{1, 0, 0, 0, 0, 0}
a = new(fe).setBytes(in)
if !a.equal(normalOne) {
t.Fatal("bad serialization")
}
}
func TestFieldElementCopy(t *testing.T) {
a, _ := new(fe).rand(rand.Reader)
b := new(fe).set(a)
if !a.equal(b) {
t.Fatal("bad copy, 1")
}
a2, _ := new(fe2).rand(rand.Reader)
b2 := new(fe2).set(a2)
if !a2.equal(b2) {
t.Fatal("bad copy, 2")
}
a6, _ := new(fe6).rand(rand.Reader)
b6 := new(fe6).set(a6)
if !a6.equal(b6) {
t.Fatal("bad copy, 6")
}
a12, _ := new(fe12).rand(rand.Reader)
b12 := new(fe12).set(a12)
if !a12.equal(b12) {
t.Fatal("bad copy, 12")
}
}
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package bls12381
import (
"errors"
"math/big"
)
func fromBytes(in []byte) (*fe, error) {
fe := &fe{}
if len(in) != 48 {
return nil, errors.New("input string should be equal 48 bytes")
}
fe.setBytes(in)
if !fe.isValid() {
return nil, errors.New("must be less than modulus")
}
toMont(fe, fe)
return fe, nil
}
func fromBig(in *big.Int) (*fe, error) {
fe := new(fe).setBig(in)
if !fe.isValid() {
return nil, errors.New("invalid input string")
}
toMont(fe, fe)
return fe, nil
}
func fromString(in string) (*fe, error) {
fe, err := new(fe).setString(in)
if err != nil {
return nil, err
}
if !fe.isValid() {
return nil, errors.New("invalid input string")
}
toMont(fe, fe)
return fe, nil
}
func toBytes(e *fe) []byte {
e2 := new(fe)
fromMont(e2, e)
return e2.bytes()
}
func toBig(e *fe) *big.Int {
e2 := new(fe)
fromMont(e2, e)
return e2.big()
}
func toString(e *fe) (s string) {
e2 := new(fe)
fromMont(e2, e)
return e2.string()
}
func toMont(c, a *fe) {
mul(c, a, r2)
}
func fromMont(c, a *fe) {
mul(c, a, &fe{1})
}
func exp(c, a *fe, e *big.Int) {
z := new(fe).set(r1)
for i := e.BitLen(); i >= 0; i-- {
mul(z, z, z)
if e.Bit(i) == 1 {
mul(z, z, a)
}
}
c.set(z)
}
func inverse(inv, e *fe) {
if e.isZero() {
inv.zero()
return
}
u := new(fe).set(&modulus)
v := new(fe).set(e)
s := &fe{1}
r := &fe{0}
var k int
var z uint64
var found = false
// Phase 1
for i := 0; i < 768; i++ {
if v.isZero() {
found = true
break
}
if u.isEven() {
u.div2(0)
s.mul2()
} else if v.isEven() {
v.div2(0)
z += r.mul2()
} else if u.cmp(v) == 1 {
lsubAssign(u, v)
u.div2(0)
laddAssign(r, s)
s.mul2()
} else {
lsubAssign(v, u)
v.div2(0)
laddAssign(s, r)
z += r.mul2()
}
k += 1
}
if !found {
inv.zero()
return
}
if k < 381 || k > 381+384 {
inv.zero()
return
}
if r.cmp(&modulus) != -1 || z > 0 {
lsubAssign(r, &modulus)
}
u.set(&modulus)
lsubAssign(u, r)
// Phase 2
for i := k; i < 384*2; i++ {
double(u, u)
}
inv.set(u)
}
func sqrt(c, a *fe) bool {
u, v := new(fe).set(a), new(fe)
exp(c, a, pPlus1Over4)
square(v, c)
return u.equal(v)
}
func isQuadraticNonResidue(elem *fe) bool {
result := new(fe)
exp(result, elem, pMinus1Over2)
return !result.isOne()
}
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package bls12381
import (
"errors"
"math/big"
)
type fp12 struct {
fp12temp
fp6 *fp6
}
type fp12temp struct {
t2 [9]*fe2
t6 [5]*fe6
t12 *fe12
}
func newFp12Temp() fp12temp {
t2 := [9]*fe2{}
t6 := [5]*fe6{}
for i := 0; i < len(t2); i++ {
t2[i] = &fe2{}
}
for i := 0; i < len(t6); i++ {
t6[i] = &fe6{}
}
return fp12temp{t2, t6, &fe12{}}
}
func newFp12(fp6 *fp6) *fp12 {
t := newFp12Temp()
if fp6 == nil {
return &fp12{t, newFp6(nil)}
}
return &fp12{t, fp6}
}
func (e *fp12) fp2() *fp2 {
return e.fp6.fp2
}
func (e *fp12) fromBytes(in []byte) (*fe12, error) {
if len(in) != 576 {
return nil, errors.New("input string should be larger than 96 bytes")
}
fp6 := e.fp6
c1, err := fp6.fromBytes(in[:288])
if err != nil {
return nil, err
}
c0, err := fp6.fromBytes(in[288:])
if err != nil {
return nil, err
}
return &fe12{*c0, *c1}, nil
}
func (e *fp12) toBytes(a *fe12) []byte {
fp6 := e.fp6
out := make([]byte, 576)
copy(out[:288], fp6.toBytes(&a[1]))
copy(out[288:], fp6.toBytes(&a[0]))
return out
}
func (e *fp12) new() *fe12 {
return new(fe12)
}
func (e *fp12) zero() *fe12 {
return new(fe12)
}
func (e *fp12) one() *fe12 {
return new(fe12).one()
}
func (e *fp12) add(c, a, b *fe12) {
fp6 := e.fp6
fp6.add(&c[0], &a[0], &b[0])
fp6.add(&c[1], &a[1], &b[1])
}
func (e *fp12) double(c, a *fe12) {
fp6 := e.fp6
fp6.double(&c[0], &a[0])
fp6.double(&c[1], &a[1])
}
func (e *fp12) sub(c, a, b *fe12) {
fp6 := e.fp6
fp6.sub(&c[0], &a[0], &b[0])
fp6.sub(&c[1], &a[1], &b[1])
}
func (e *fp12) neg(c, a *fe12) {
fp6 := e.fp6
fp6.neg(&c[0], &a[0])
fp6.neg(&c[1], &a[1])
}
func (e *fp12) conjugate(c, a *fe12) {
fp6 := e.fp6
c[0].set(&a[0])
fp6.neg(&c[1], &a[1])
}
func (e *fp12) square(c, a *fe12) {
fp6, t := e.fp6, e.t6
fp6.add(t[0], &a[0], &a[1])
fp6.mul(t[2], &a[0], &a[1])
fp6.mulByNonResidue(t[1], &a[1])
fp6.addAssign(t[1], &a[0])
fp6.mulByNonResidue(t[3], t[2])
fp6.mulAssign(t[0], t[1])
fp6.subAssign(t[0], t[2])
fp6.sub(&c[0], t[0], t[3])
fp6.double(&c[1], t[2])
}
func (e *fp12) cyclotomicSquare(c, a *fe12) {
t, fp2 := e.t2, e.fp2()
e.fp4Square(t[3], t[4], &a[0][0], &a[1][1])
fp2.sub(t[2], t[3], &a[0][0])
fp2.doubleAssign(t[2])
fp2.add(&c[0][0], t[2], t[3])
fp2.add(t[2], t[4], &a[1][1])
fp2.doubleAssign(t[2])
fp2.add(&c[1][1], t[2], t[4])
e.fp4Square(t[3], t[4], &a[1][0], &a[0][2])
e.fp4Square(t[5], t[6], &a[0][1], &a[1][2])
fp2.sub(t[2], t[3], &a[0][1])
fp2.doubleAssign(t[2])
fp2.add(&c[0][1], t[2], t[3])
fp2.add(t[2], t[4], &a[1][2])
fp2.doubleAssign(t[2])
fp2.add(&c[1][2], t[2], t[4])
fp2.mulByNonResidue(t[3], t[6])
fp2.add(t[2], t[3], &a[1][0])
fp2.doubleAssign(t[2])
fp2.add(&c[1][0], t[2], t[3])
fp2.sub(t[2], t[5], &a[0][2])
fp2.doubleAssign(t[2])
fp2.add(&c[0][2], t[2], t[5])
}
func (e *fp12) mul(c, a, b *fe12) {
t, fp6 := e.t6, e.fp6
fp6.mul(t[1], &a[0], &b[0])
fp6.mul(t[2], &a[1], &b[1])
fp6.add(t[0], t[1], t[2])
fp6.mulByNonResidue(t[2], t[2])
fp6.add(t[3], t[1], t[2])
fp6.add(t[1], &a[0], &a[1])
fp6.add(t[2], &b[0], &b[1])
fp6.mulAssign(t[1], t[2])
c[0].set(t[3])
fp6.sub(&c[1], t[1], t[0])
}
func (e *fp12) mulAssign(a, b *fe12) {
t, fp6 := e.t6, e.fp6
fp6.mul(t[1], &a[0], &b[0])
fp6.mul(t[2], &a[1], &b[1])
fp6.add(t[0], t[1], t[2])
fp6.mulByNonResidue(t[2], t[2])
fp6.add(t[3], t[1], t[2])
fp6.add(t[1], &a[0], &a[1])
fp6.add(t[2], &b[0], &b[1])
fp6.mulAssign(t[1], t[2])
a[0].set(t[3])
fp6.sub(&a[1], t[1], t[0])
}
func (e *fp12) fp4Square(c0, c1, a0, a1 *fe2) {
t, fp2 := e.t2, e.fp2()
fp2.square(t[0], a0)
fp2.square(t[1], a1)
fp2.mulByNonResidue(t[2], t[1])
fp2.add(c0, t[2], t[0])
fp2.add(t[2], a0, a1)
fp2.squareAssign(t[2])
fp2.subAssign(t[2], t[0])
fp2.sub(c1, t[2], t[1])
}
func (e *fp12) inverse(c, a *fe12) {
fp6, t := e.fp6, e.t6
fp6.square(t[0], &a[0])
fp6.square(t[1], &a[1])
fp6.mulByNonResidue(t[1], t[1])
fp6.sub(t[1], t[0], t[1])
fp6.inverse(t[0], t[1])
fp6.mul(&c[0], &a[0], t[0])
fp6.mulAssign(t[0], &a[1])
fp6.neg(&c[1], t[0])
}
func (e *fp12) mulBy014Assign(a *fe12, c0, c1, c4 *fe2) {
fp2, fp6, t, t2 := e.fp2(), e.fp6, e.t6, e.t2[0]
fp6.mulBy01(t[0], &a[0], c0, c1)
fp6.mulBy1(t[1], &a[1], c4)
fp2.add(t2, c1, c4)
fp6.add(t[2], &a[1], &a[0])
fp6.mulBy01Assign(t[2], c0, t2)
fp6.subAssign(t[2], t[0])
fp6.sub(&a[1], t[2], t[1])
fp6.mulByNonResidue(t[1], t[1])
fp6.add(&a[0], t[1], t[0])
}
func (e *fp12) exp(c, a *fe12, s *big.Int) {
z := e.one()
for i := s.BitLen() - 1; i >= 0; i-- {
e.square(z, z)
if s.Bit(i) == 1 {
e.mul(z, z, a)
}
}
c.set(z)
}
func (e *fp12) cyclotomicExp(c, a *fe12, s *big.Int) {
z := e.one()
for i := s.BitLen() - 1; i >= 0; i-- {
e.cyclotomicSquare(z, z)
if s.Bit(i) == 1 {
e.mul(z, z, a)
}
}
c.set(z)
}
func (e *fp12) frobeniusMap(c, a *fe12, power uint) {
fp6 := e.fp6
fp6.frobeniusMap(&c[0], &a[0], power)
fp6.frobeniusMap(&c[1], &a[1], power)
switch power {
case 0:
return
case 6:
fp6.neg(&c[1], &c[1])
default:
fp6.mulByBaseField(&c[1], &c[1], &frobeniusCoeffs12[power])
}
}
func (e *fp12) frobeniusMapAssign(a *fe12, power uint) {
fp6 := e.fp6
fp6.frobeniusMapAssign(&a[0], power)
fp6.frobeniusMapAssign(&a[1], power)
switch power {
case 0:
return
case 6:
fp6.neg(&a[1], &a[1])
default:
fp6.mulByBaseField(&a[1], &a[1], &frobeniusCoeffs12[power])
}
}
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package bls12381
import (
"errors"
"math/big"
)
type fp2Temp struct {
t [4]*fe
}
type fp2 struct {
fp2Temp
}
func newFp2Temp() fp2Temp {
t := [4]*fe{}
for i := 0; i < len(t); i++ {
t[i] = &fe{}
}
return fp2Temp{t}
}
func newFp2() *fp2 {
t := newFp2Temp()
return &fp2{t}
}
func (e *fp2) fromBytes(in []byte) (*fe2, error) {
if len(in) != 96 {
return nil, errors.New("length of input string should be 96 bytes")
}
c1, err := fromBytes(in[:48])
if err != nil {
return nil, err
}
c0, err := fromBytes(in[48:])
if err != nil {
return nil, err
}
return &fe2{*c0, *c1}, nil
}
func (e *fp2) toBytes(a *fe2) []byte {
out := make([]byte, 96)
copy(out[:48], toBytes(&a[1]))
copy(out[48:], toBytes(&a[0]))
return out
}
func (e *fp2) new() *fe2 {
return new(fe2).zero()
}
func (e *fp2) zero() *fe2 {
return new(fe2).zero()
}
func (e *fp2) one() *fe2 {
return new(fe2).one()
}
func (e *fp2) add(c, a, b *fe2) {
add(&c[0], &a[0], &b[0])
add(&c[1], &a[1], &b[1])
}
func (e *fp2) addAssign(a, b *fe2) {
addAssign(&a[0], &b[0])
addAssign(&a[1], &b[1])
}
func (e *fp2) ladd(c, a, b *fe2) {
ladd(&c[0], &a[0], &b[0])
ladd(&c[1], &a[1], &b[1])
}
func (e *fp2) double(c, a *fe2) {
double(&c[0], &a[0])
double(&c[1], &a[1])
}
func (e *fp2) doubleAssign(a *fe2) {
doubleAssign(&a[0])
doubleAssign(&a[1])
}
func (e *fp2) ldouble(c, a *fe2) {
ldouble(&c[0], &a[0])
ldouble(&c[1], &a[1])
}
func (e *fp2) sub(c, a, b *fe2) {
sub(&c[0], &a[0], &b[0])
sub(&c[1], &a[1], &b[1])
}
func (e *fp2) subAssign(c, a *fe2) {
subAssign(&c[0], &a[0])
subAssign(&c[1], &a[1])
}
func (e *fp2) neg(c, a *fe2) {
neg(&c[0], &a[0])
neg(&c[1], &a[1])
}
func (e *fp2) mul(c, a, b *fe2) {
t := e.t
mul(t[1], &a[0], &b[0])
mul(t[2], &a[1], &b[1])
add(t[0], &a[0], &a[1])
add(t[3], &b[0], &b[1])
sub(&c[0], t[1], t[2])
addAssign(t[1], t[2])
mul(t[0], t[0], t[3])
sub(&c[1], t[0], t[1])
}
func (e *fp2) mulAssign(a, b *fe2) {
t := e.t
mul(t[1], &a[0], &b[0])
mul(t[2], &a[1], &b[1])
add(t[0], &a[0], &a[1])
add(t[3], &b[0], &b[1])
sub(&a[0], t[1], t[2])
addAssign(t[1], t[2])
mul(t[0], t[0], t[3])
sub(&a[1], t[0], t[1])
}
func (e *fp2) square(c, a *fe2) {
t := e.t
ladd(t[0], &a[0], &a[1])
sub(t[1], &a[0], &a[1])
ldouble(t[2], &a[0])
mul(&c[0], t[0], t[1])
mul(&c[1], t[2], &a[1])
}
func (e *fp2) squareAssign(a *fe2) {
t := e.t
ladd(t[0], &a[0], &a[1])
sub(t[1], &a[0], &a[1])
ldouble(t[2], &a[0])
mul(&a[0], t[0], t[1])
mul(&a[1], t[2], &a[1])
}
func (e *fp2) mulByNonResidue(c, a *fe2) {
t := e.t
sub(t[0], &a[0], &a[1])
add(&c[1], &a[0], &a[1])
c[0].set(t[0])
}
func (e *fp2) mulByB(c, a *fe2) {
t := e.t
double(t[0], &a[0])
double(t[1], &a[1])
doubleAssign(t[0])
doubleAssign(t[1])
sub(&c[0], t[0], t[1])
add(&c[1], t[0], t[1])
}
func (e *fp2) inverse(c, a *fe2) {
t := e.t
square(t[0], &a[0])
square(t[1], &a[1])
addAssign(t[0], t[1])
inverse(t[0], t[0])
mul(&c[0], &a[0], t[0])
mul(t[0], t[0], &a[1])
neg(&c[1], t[0])
}
func (e *fp2) mulByFq(c, a *fe2, b *fe) {
mul(&c[0], &a[0], b)
mul(&c[1], &a[1], b)
}
func (e *fp2) exp(c, a *fe2, s *big.Int) {
z := e.one()
for i := s.BitLen() - 1; i >= 0; i-- {
e.square(z, z)
if s.Bit(i) == 1 {
e.mul(z, z, a)
}
}
c.set(z)
}
func (e *fp2) frobeniusMap(c, a *fe2, power uint) {
c[0].set(&a[0])
if power%2 == 1 {
neg(&c[1], &a[1])
return
}
c[1].set(&a[1])
}
func (e *fp2) frobeniusMapAssign(a *fe2, power uint) {
if power%2 == 1 {
neg(&a[1], &a[1])
return
}
}
func (e *fp2) sqrt(c, a *fe2) bool {
u, x0, a1, alpha := &fe2{}, &fe2{}, &fe2{}, &fe2{}
u.set(a)
e.exp(a1, a, pMinus3Over4)
e.square(alpha, a1)
e.mul(alpha, alpha, a)
e.mul(x0, a1, a)
if alpha.equal(negativeOne2) {
neg(&c[0], &x0[1])
c[1].set(&x0[0])
return true
}
e.add(alpha, alpha, e.one())
e.exp(alpha, alpha, pMinus1Over2)
e.mul(c, alpha, x0)
e.square(alpha, c)
return alpha.equal(u)
}
func (e *fp2) isQuadraticNonResidue(a *fe2) bool {
// https://github.com/leovt/constructible/wiki/Taking-Square-Roots-in-quadratic-extension-Fields
c0, c1 := new(fe), new(fe)
square(c0, &a[0])
square(c1, &a[1])
add(c1, c1, c0)
return isQuadraticNonResidue(c1)
}
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package bls12381
import (
"errors"
"math/big"
)
type fp6Temp struct {
t [6]*fe2
}
type fp6 struct {
fp2 *fp2
fp6Temp
}
func newFp6Temp() fp6Temp {
t := [6]*fe2{}
for i := 0; i < len(t); i++ {
t[i] = &fe2{}
}
return fp6Temp{t}
}
func newFp6(f *fp2) *fp6 {
t := newFp6Temp()
if f == nil {
return &fp6{newFp2(), t}
}
return &fp6{f, t}
}
func (e *fp6) fromBytes(b []byte) (*fe6, error) {
if len(b) < 288 {
return nil, errors.New("input string should be larger than 288 bytes")
}
fp2 := e.fp2
u2, err := fp2.fromBytes(b[:96])
if err != nil {
return nil, err
}
u1, err := fp2.fromBytes(b[96:192])
if err != nil {
return nil, err
}
u0, err := fp2.fromBytes(b[192:])
if err != nil {
return nil, err
}
return &fe6{*u0, *u1, *u2}, nil
}
func (e *fp6) toBytes(a *fe6) []byte {
fp2 := e.fp2
out := make([]byte, 288)
copy(out[:96], fp2.toBytes(&a[2]))
copy(out[96:192], fp2.toBytes(&a[1]))
copy(out[192:], fp2.toBytes(&a[0]))
return out
}
func (e *fp6) new() *fe6 {
return new(fe6)
}
func (e *fp6) zero() *fe6 {
return new(fe6)
}
func (e *fp6) one() *fe6 {
return new(fe6).one()
}
func (e *fp6) add(c, a, b *fe6) {
fp2 := e.fp2
fp2.add(&c[0], &a[0], &b[0])
fp2.add(&c[1], &a[1], &b[1])
fp2.add(&c[2], &a[2], &b[2])
}
func (e *fp6) addAssign(a, b *fe6) {
fp2 := e.fp2
fp2.addAssign(&a[0], &b[0])
fp2.addAssign(&a[1], &b[1])
fp2.addAssign(&a[2], &b[2])
}
func (e *fp6) double(c, a *fe6) {
fp2 := e.fp2
fp2.double(&c[0], &a[0])
fp2.double(&c[1], &a[1])
fp2.double(&c[2], &a[2])
}
func (e *fp6) doubleAssign(a *fe6) {
fp2 := e.fp2
fp2.doubleAssign(&a[0])
fp2.doubleAssign(&a[1])
fp2.doubleAssign(&a[2])
}
func (e *fp6) sub(c, a, b *fe6) {
fp2 := e.fp2
fp2.sub(&c[0], &a[0], &b[0])
fp2.sub(&c[1], &a[1], &b[1])
fp2.sub(&c[2], &a[2], &b[2])
}
func (e *fp6) subAssign(a, b *fe6) {
fp2 := e.fp2
fp2.subAssign(&a[0], &b[0])
fp2.subAssign(&a[1], &b[1])
fp2.subAssign(&a[2], &b[2])
}
func (e *fp6) neg(c, a *fe6) {
fp2 := e.fp2
fp2.neg(&c[0], &a[0])
fp2.neg(&c[1], &a[1])
fp2.neg(&c[2], &a[2])
}
func (e *fp6) mul(c, a, b *fe6) {
fp2, t := e.fp2, e.t
fp2.mul(t[0], &a[0], &b[0])
fp2.mul(t[1], &a[1], &b[1])
fp2.mul(t[2], &a[2], &b[2])
fp2.add(t[3], &a[1], &a[2])
fp2.add(t[4], &b[1], &b[2])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[1], t[2])
fp2.subAssign(t[3], t[4])
fp2.mulByNonResidue(t[3], t[3])
fp2.add(t[5], t[0], t[3])
fp2.add(t[3], &a[0], &a[1])
fp2.add(t[4], &b[0], &b[1])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[0], t[1])
fp2.subAssign(t[3], t[4])
fp2.mulByNonResidue(t[4], t[2])
fp2.add(&c[1], t[3], t[4])
fp2.add(t[3], &a[0], &a[2])
fp2.add(t[4], &b[0], &b[2])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[0], t[2])
fp2.subAssign(t[3], t[4])
fp2.add(&c[2], t[1], t[3])
c[0].set(t[5])
}
func (e *fp6) mulAssign(a, b *fe6) {
fp2, t := e.fp2, e.t
fp2.mul(t[0], &a[0], &b[0])
fp2.mul(t[1], &a[1], &b[1])
fp2.mul(t[2], &a[2], &b[2])
fp2.add(t[3], &a[1], &a[2])
fp2.add(t[4], &b[1], &b[2])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[1], t[2])
fp2.subAssign(t[3], t[4])
fp2.mulByNonResidue(t[3], t[3])
fp2.add(t[5], t[0], t[3])
fp2.add(t[3], &a[0], &a[1])
fp2.add(t[4], &b[0], &b[1])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[0], t[1])
fp2.subAssign(t[3], t[4])
fp2.mulByNonResidue(t[4], t[2])
fp2.add(&a[1], t[3], t[4])
fp2.add(t[3], &a[0], &a[2])
fp2.add(t[4], &b[0], &b[2])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[0], t[2])
fp2.subAssign(t[3], t[4])
fp2.add(&a[2], t[1], t[3])
a[0].set(t[5])
}
func (e *fp6) square(c, a *fe6) {
fp2, t := e.fp2, e.t
fp2.square(t[0], &a[0])
fp2.mul(t[1], &a[0], &a[1])
fp2.doubleAssign(t[1])
fp2.sub(t[2], &a[0], &a[1])
fp2.addAssign(t[2], &a[2])
fp2.squareAssign(t[2])
fp2.mul(t[3], &a[1], &a[2])
fp2.doubleAssign(t[3])
fp2.square(t[4], &a[2])
fp2.mulByNonResidue(t[5], t[3])
fp2.add(&c[0], t[0], t[5])
fp2.mulByNonResidue(t[5], t[4])
fp2.add(&c[1], t[1], t[5])
fp2.addAssign(t[1], t[2])
fp2.addAssign(t[1], t[3])
fp2.addAssign(t[0], t[4])
fp2.sub(&c[2], t[1], t[0])
}
func (e *fp6) mulBy01Assign(a *fe6, b0, b1 *fe2) {
fp2, t := e.fp2, e.t
fp2.mul(t[0], &a[0], b0)
fp2.mul(t[1], &a[1], b1)
fp2.add(t[5], &a[1], &a[2])
fp2.mul(t[2], b1, t[5])
fp2.subAssign(t[2], t[1])
fp2.mulByNonResidue(t[2], t[2])
fp2.add(t[5], &a[0], &a[2])
fp2.mul(t[3], b0, t[5])
fp2.subAssign(t[3], t[0])
fp2.add(&a[2], t[3], t[1])
fp2.add(t[4], b0, b1)
fp2.add(t[5], &a[0], &a[1])
fp2.mulAssign(t[4], t[5])
fp2.subAssign(t[4], t[0])
fp2.sub(&a[1], t[4], t[1])
fp2.add(&a[0], t[2], t[0])
}
func (e *fp6) mulBy01(c, a *fe6, b0, b1 *fe2) {
fp2, t := e.fp2, e.t
fp2.mul(t[0], &a[0], b0)
fp2.mul(t[1], &a[1], b1)
fp2.add(t[2], &a[1], &a[2])
fp2.mulAssign(t[2], b1)
fp2.subAssign(t[2], t[1])
fp2.mulByNonResidue(t[2], t[2])
fp2.add(t[3], &a[0], &a[2])
fp2.mulAssign(t[3], b0)
fp2.subAssign(t[3], t[0])
fp2.add(&c[2], t[3], t[1])
fp2.add(t[4], b0, b1)
fp2.add(t[3], &a[0], &a[1])
fp2.mulAssign(t[4], t[3])
fp2.subAssign(t[4], t[0])
fp2.sub(&c[1], t[4], t[1])
fp2.add(&c[0], t[2], t[0])
}
func (e *fp6) mulBy1(c, a *fe6, b1 *fe2) {
fp2, t := e.fp2, e.t
fp2.mul(t[0], &a[2], b1)
fp2.mul(&c[2], &a[1], b1)
fp2.mul(&c[1], &a[0], b1)
fp2.mulByNonResidue(&c[0], t[0])
}
func (e *fp6) mulByNonResidue(c, a *fe6) {
fp2, t := e.fp2, e.t
t[0].set(&a[0])
fp2.mulByNonResidue(&c[0], &a[2])
c[2].set(&a[1])
c[1].set(t[0])
}
func (e *fp6) mulByBaseField(c, a *fe6, b *fe2) {
fp2 := e.fp2
fp2.mul(&c[0], &a[0], b)
fp2.mul(&c[1], &a[1], b)
fp2.mul(&c[2], &a[2], b)
}
func (e *fp6) exp(c, a *fe6, s *big.Int) {
z := e.one()
for i := s.BitLen() - 1; i >= 0; i-- {
e.square(z, z)
if s.Bit(i) == 1 {
e.mul(z, z, a)
}
}
c.set(z)
}
func (e *fp6) inverse(c, a *fe6) {
fp2, t := e.fp2, e.t
fp2.square(t[0], &a[0])
fp2.mul(t[1], &a[1], &a[2])
fp2.mulByNonResidue(t[1], t[1])
fp2.subAssign(t[0], t[1])
fp2.square(t[1], &a[1])
fp2.mul(t[2], &a[0], &a[2])
fp2.subAssign(t[1], t[2])
fp2.square(t[2], &a[2])
fp2.mulByNonResidue(t[2], t[2])
fp2.mul(t[3], &a[0], &a[1])
fp2.subAssign(t[2], t[3])
fp2.mul(t[3], &a[2], t[2])
fp2.mul(t[4], &a[1], t[1])
fp2.addAssign(t[3], t[4])
fp2.mulByNonResidue(t[3], t[3])
fp2.mul(t[4], &a[0], t[0])
fp2.addAssign(t[3], t[4])
fp2.inverse(t[3], t[3])
fp2.mul(&c[0], t[0], t[3])
fp2.mul(&c[1], t[2], t[3])
fp2.mul(&c[2], t[1], t[3])
}
func (e *fp6) frobeniusMap(c, a *fe6, power uint) {
fp2 := e.fp2
fp2.frobeniusMap(&c[0], &a[0], power)
fp2.frobeniusMap(&c[1], &a[1], power)
fp2.frobeniusMap(&c[2], &a[2], power)
switch power % 6 {
case 0:
return
case 3:
neg(&c[0][0], &a[1][1])
c[1][1].set(&a[1][0])
fp2.neg(&a[2], &a[2])
default:
fp2.mul(&c[1], &c[1], &frobeniusCoeffs61[power%6])
fp2.mul(&c[2], &c[2], &frobeniusCoeffs62[power%6])
}
}
func (e *fp6) frobeniusMapAssign(a *fe6, power uint) {
fp2 := e.fp2
fp2.frobeniusMapAssign(&a[0], power)
fp2.frobeniusMapAssign(&a[1], power)
fp2.frobeniusMapAssign(&a[2], power)
t := e.t
switch power % 6 {
case 0:
return
case 3:
neg(&t[0][0], &a[1][1])
a[1][1].set(&a[1][0])
a[1][0].set(&t[0][0])
fp2.neg(&a[2], &a[2])
default:
fp2.mulAssign(&a[1], &frobeniusCoeffs61[power%6])
fp2.mulAssign(&a[2], &frobeniusCoeffs62[power%6])
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment